oso icon indicating copy to clipboard operation
oso copied to clipboard

Can't get shortcut "admin" rule to work

Open lafrech opened this issue 2 years ago • 1 comments

Hi.

Here's another of my 0.26 migration issues.

I have a set of auth rules based on a SQLAlchemy relationship model and I use a shortcut "admin" rule to specify that admin users (users with is_admin property set to True) can do everything.

# Admin can do anything
allow(user: User, _action, _resource) if user.is_admin = true;

This worked fine until 0.26 / SqlAlchemyAdapter. Now, I have issues with authorized_query not returning all expected rows.

Here's a 0.25 query:

SELECT anon_1.timeseries_id AS anon_1_timeseries_id, anon_1.timeseries_cluster_id AS anon_1_timeseries_cluster_id, anon_1.timeseries_data_state_id AS anon_1_timeseries_data_state_id 
FROM (SELECT timeseries.id AS timeseries_id, timeseries.cluster_id AS timeseries_cluster_id, timeseries.data_state_id AS timeseries_data_state_id 
FROM timeseries 
WHERE true UNION SELECT timeseries.id AS timeseries_id, timeseries.cluster_id AS timeseries_cluster_id, timeseries.data_state_id AS timeseries_data_state_id 
FROM timeseries 
WHERE timeseries.cluster_id IN (__[POSTCOMPILE_cluster_id_1])) AS anon_1

And here's the equivalent 0.26 query:

SELECT DISTINCT timeseries.id AS timeseries_id, timeseries.cluster_id AS timeseries_cluster_id, timeseries.data_state_id AS timeseries_data_state_id 
FROM timeseries JOIN timeseries_clusters ON timeseries.cluster_id = timeseries_clusters.id JOIN timeseries_cluster_groups ON timeseries_clusters.group_id = timeseries_cluster_groups.id JOIN timeseries_cluster_groups_by_users ON timeseries_cluster_groups.id = timeseries_cluster_groups_by_users.timeseries_cluster_group_id JOIN users ON timeseries_cluster_groups_by_users.user_id = users.id 
WHERE true OR users.id = %(id_1)s

The issue seems to be that the "admin" shortcut (WHERE true) is only used after the joins needed for the relational rule.

In the case above, the query returns no row because the admin user has no relation to the timeseries objects. If I add an unrelated user with relations to timeseries objects, then, thanks to the admin shortcut, those timeseries are returned.

Basically, the "admin" shortcut is broken as it only returns the rows for which at least a user exists that fills the rule.

Trace 0.25
[oso][info]   QUERY RULE: allow(<User Chuck <[email protected]>, admin: True, active: True> TYPE `User`, "read", resource)
[oso][info]     APPLICABLE_RULES:
[oso][info]       allow(user: UserActor{}, _action, _resource) at line 13, column 1 of file /mnt/projets/bemserver/bemserver-core/bemserver_core/authorization.polar
[oso][info]       allow(actor, action, resource) at line 7, column 1 of file /mnt/projets/bemserver/bemserver-core/bemserver_core/authorization.polar
[oso][info]       allow(_actor, _action, _resource) at line 10, column 1 of file /mnt/projets/bemserver/bemserver-core/bemserver_core/authorization.polar
[oso][info]   RESULT: {
[oso][info]     resource: _this matches Timeseries{}
[oso][info]   }
[oso][info]       QUERY RULE: has_permission(_actor_320, _action_321, _resource_322)
[oso][info]           QUERY RULE: has_relation(_related_timeseriescluster_410, "cluster", _timeseries_409)
[oso][info]           QUERY RULE: has_permission(_actor_408, "read", _related_timeseriescluster_410)
[oso][info]               QUERY RULE: has_relation(_related_timeseriesclustergroup_510, "group", _timeseriescluster_509)
[oso][info]               QUERY RULE: has_role(_actor_508, "tscg_member", _related_timeseriesclustergroup_510)
[oso][info]   RESULT: {
[oso][info]     resource: _this.cluster.group matches TimeseriesClusterGroup{} and _this.cluster matches TimeseriesCluster{} and _this matches Timeseries{} and _tscgbu_537 in _this.cluster.group.timeseries_cluster_groups_by_users and <User Chuck <[email protected]>, admin: True, active: True> TYPE `User` = _tscgbu_537.user
[oso][info]   }
Trace 0.26
[oso][info]   QUERY RULE: allow(<User Chuck <[email protected]>, admin: True, active: True> TYPE `User`, "read", resource)
[oso][info]     APPLICABLE_RULES:
[oso][info]       allow(user: User{}, _action, _resource) at line 13, column 1 of file /mnt/projets/bemserver/bemserver-core/bemserver_core/authorization.polar
[oso][info]       allow(actor, action, resource) at line 7, column 1 of file /mnt/projets/bemserver/bemserver-core/bemserver_core/authorization.polar
[oso][info]       allow(_actor, _action, _resource) at line 10, column 1 of file /mnt/projets/bemserver/bemserver-core/bemserver_core/authorization.polar
[oso][info]     RULE: allow(user: User{}, _action, _resource) if _value_2 = true and user.is_admin = _value_2;
[oso][info]   RESULT: {
[oso][info]     resource: _this matches Timeseries{}
[oso][info]   }
[oso][info]     RULE: allow(actor, action, resource) if has_permission(actor, action, resource);
[oso][info]       QUERY RULE: has_permission(_actor_315, _action_316, _resource_317)
[oso][info]         APPLICABLE_RULES:
[oso][info]           has_permission(actor: Actor{}, "read", timeseries: Timeseries{}) at line 144, column 5 of file /mnt/projets/bemserver/bemserver-core/bemserver_core/authorization.polar
[oso][info]         RULE: has_permission(actor: Actor{}, "read", timeseries: Timeseries{}) if has_relation(related_timeseriescluster, "cluster", timeseries) and has_permission(actor, "read", related_timeseriescluster);
[oso][info]           QUERY RULE: has_relation(_related_timeseriescluster_386, "cluster", _timeseries_385)
[oso][info]             APPLICABLE_RULES:
[oso][info]               has_relation(tsc: TimeseriesCluster{}, "cluster", ts: Timeseries{}) at line 149, column 1 of file /mnt/projets/bemserver/bemserver-core/bemserver_core/authorization.polar
[oso][info]             RULE: has_relation(tsc: TimeseriesCluster{}, "cluster", ts: Timeseries{}) if tsc = _value_15 and ts.cluster = _value_15;
[oso][info]           QUERY RULE: has_permission(_actor_384, "read", _related_timeseriescluster_386)
[oso][info]             APPLICABLE_RULES:
[oso][info]               has_permission(actor: Actor{}, "read", timeseriescluster: TimeseriesCluster{}) at line 116, column 5 of file /mnt/projets/bemserver/bemserver-core/bemserver_core/authorization.polar
[oso][info]             RULE: has_permission(actor: Actor{}, "read", timeseriescluster: TimeseriesCluster{}) if has_relation(related_timeseriesclustergroup, "group", timeseriescluster) and has_role(actor, "tscg_member", related_timeseriesclustergroup);
[oso][info]               QUERY RULE: has_relation(_related_timeseriesclustergroup_467, "group", _timeseriescluster_466)
[oso][info]                 APPLICABLE_RULES:
[oso][info]                   has_relation(group: TimeseriesClusterGroup{}, "group", tsc: TimeseriesCluster{}) at line 121, column 1 of file /mnt/projets/bemserver/bemserver-core/bemserver_core/authorization.polar
[oso][info]                 RULE: has_relation(group: TimeseriesClusterGroup{}, "group", tsc: TimeseriesCluster{}) if group = _value_13 and tsc.group = _value_13;
[oso][info]               QUERY RULE: has_role(_actor_465, "tscg_member", _related_timeseriesclustergroup_467)
[oso][info]                 APPLICABLE_RULES:
[oso][info]                   has_role(user: User{}, "tscg_member", tg: TimeseriesClusterGroup{}) at line 93, column 1 of file /mnt/projets/bemserver/bemserver-core/bemserver_core/authorization.polar
[oso][info]                 RULE: has_role(user: User{}, "tscg_member", tg: TimeseriesClusterGroup{}) if tg.timeseries_cluster_groups_by_users = _value_10 and tscgbu in _value_10 and user = _value_11 and tscgbu.user = _value_11;
[oso][info]   RESULT: {
[oso][info]     resource: _this.cluster.group matches TimeseriesClusterGroup{} and _this.cluster matches TimeseriesCluster{} and _this matches Timeseries{} and _tscgbu_492 in _this.cluster.group.timeseries_cluster_groups_by_users and <User Chuck <[email protected]>, admin: True, active: True> TYPE `User` = _tscgbu_492.user
[oso][info]   }
[oso][info]     RULE: allow(_actor, _action, _resource) if OpenBarPolarClass.get() = _value_1 and _value_1;

In both traces, the admin shortcut line gives the following result:

[oso][info]   RESULT: {
[oso][info]     resource: _this matches Timeseries{}
[oso][info]   }

and the relational line

[oso][info]   RESULT: {
[oso][info]     resource: _this.cluster.group matches TimeseriesClusterGroup{} and _this.cluster matches TimeseriesCluster{} and _this matches Timeseries{} and _tscgbu_492 in _this.cluster.group.timeseries_cluster_groups_by_users and <User Chuck <[email protected]>, admin: True, active: True> TYPE `User` = _tscgbu_492.user
[oso][info]   }

The first result should allow the query to return all Timeseries. The generated query should then be

SELECT DISTINCT timeseries.id AS timeseries_id, timeseries.cluster_id AS timeseries_cluster_id, timeseries.data_state_id AS timeseries_data_state_id 
FROM timeseries

Or am I getting/doing this wrong?

lafrech avatar Feb 27 '22 22:02 lafrech

Hi @lafrech , you're not wrong, this is a bug. I added it to our internal issue tracker & I'll keep you updated. Thanks for reporting!

cofinalsubnets avatar Feb 28 '22 14:02 cofinalsubnets