about summary refs log tree commit diff
diff options
context:
space:
mode:
authorClaude2026-09-01 15:36:34 +0000
committerFrederick Muriuki Muriithi2026-09-01 10:39:53 -0500
commitaab9408e8c1641c0552e51e1c9f6ebd8804f00cc (patch)
treeb12aa8275db4242d24f16e69e95d73030c4606a1
parent7f5a53035b8c39cc4c0821cc6e6a7c4ca7fcd293 (diff)
downloadgn-auth-aab9408e8c1641c0552e51e1c9f6ebd8804f00cc.tar.gz
fix(auth): check system:user:list against system resource in resource_users
The HACK block in resource_users() was checking the system:user:list
privilege against the requested resource_id rather than the system
resource. This made the sysadmin branch a dead leg: sysadmins hold
system:user:list on the system resource, not on individual data resources.

Fix: pass system_resource(conn).resource_id for the system-level check.
Also restructure to early-return on auth failure (cleaner control flow).

Reviewed-By: Frederick M. Muriithi <fredmanglis@gmail.com>
-rw-r--r--gn_auth/auth/authorisation/resources/views.py93
1 files changed, 43 insertions, 50 deletions
diff --git a/gn_auth/auth/authorisation/resources/views.py b/gn_auth/auth/authorisation/resources/views.py
index 06645db..bdcc803 100644
--- a/gn_auth/auth/authorisation/resources/views.py
+++ b/gn_auth/auth/authorisation/resources/views.py
@@ -255,57 +255,50 @@ def resource_users(resource_id: UUID):
     """Retrieve all users with access to the given resource."""
     with require_oauth.acquire("profile group resource") as the_token:
         def __the_users__(conn: db.DbConnection):
-            ########## BEGIN: HACK ##########
-            # This hack gets the UI to work, but needs replacing.
-            # It resolves (albeit, temporarily) the bug introduced after a
-            # refactor that made the system itself, and the groups into
-            # resources.
-            grouplevelauth = authorised_for_spec(
-                conn,
-                the_token.user.user_id,
-                resource_id,
-                "group:resource:view-resource")
-            systemlevelauth = authorised_for_spec(
-                conn,
-                the_token.user.user_id,
-                resource_id,
-                "system:user:list")
-            ########## END: HACK ##########
-            if grouplevelauth or systemlevelauth:
-                with db.cursor(conn) as cursor:
-                    def __organise_users_n_roles__(users_n_roles, row):
-                        user_id = UUID(row["user_id"])
-                        user = users_n_roles.get(user_id, {}).get(
-                            "user", User.from_sqlite3_row(row))
-                        role = Role(
-                            UUID(row["role_id"]), row["role_name"],
-                            bool(int(row["user_editable"])), tuple())
-                        return {
-                            **users_n_roles,
-                            user_id: {
-                                "user": user,
-                                "user_group": (
-                                    Group(UUID(row["group_id"]),
-                                          row["group_name"],
-                                          json.loads(row["group_metadata"]))
-                                    if bool(row["group_id"]) else False) ,
-                                "roles": users_n_roles.get(
-                                    user_id, {}).get("roles", tuple()) + (role,)
-                            }
+            if not (authorised_for_spec(
+                        conn,
+                        the_token.user.user_id,
+                        resource_id,
+                        "group:resource:view-resource")
+                    or authorised_for_spec(
+                        conn,
+                        the_token.user.user_id,
+                        system_resource(conn).resource_id,
+                        "system:user:list")):
+                raise AuthorisationError(
+                    "You do not have sufficient privileges to view the resource "
+                    "users.")
+            with db.cursor(conn) as cursor:
+                def __organise_users_n_roles__(users_n_roles, row):
+                    user_id = UUID(row["user_id"])
+                    user = users_n_roles.get(user_id, {}).get(
+                        "user", User.from_sqlite3_row(row))
+                    role = Role(
+                        UUID(row["role_id"]), row["role_name"],
+                        bool(int(row["user_editable"])), tuple())
+                    return {
+                        **users_n_roles,
+                        user_id: {
+                            "user": user,
+                            "user_group": (
+                                Group(UUID(row["group_id"]),
+                                      row["group_name"],
+                                      json.loads(row["group_metadata"]))
+                                if bool(row["group_id"]) else False) ,
+                            "roles": users_n_roles.get(
+                                user_id, {}).get("roles", tuple()) + (role,)
                         }
-                    cursor.execute(
-                        "SELECT g.*, u.*, r.* "
-                        "FROM groups AS g INNER JOIN group_users AS gu "
-                        "ON g.group_id=gu.group_id RIGHT JOIN users AS u "
-                        "ON gu.user_id=u.user_id INNER JOIN user_roles AS ur "
-                        "ON u.user_id=ur.user_id INNER JOIN roles AS r "
-                        "ON ur.role_id=r.role_id "
-                        "WHERE ur.resource_id=?",
-                        (str(resource_id),))
-                    return reduce(__organise_users_n_roles__, cursor.fetchall(), {})
-            raise AuthorisationError(
-                "You do not have sufficient privileges to view the resource "
-                "users.")
+                    }
+                cursor.execute(
+                    "SELECT g.*, u.*, r.* "
+                    "FROM groups AS g INNER JOIN group_users AS gu "
+                    "ON g.group_id=gu.group_id RIGHT JOIN users AS u "
+                    "ON gu.user_id=u.user_id INNER JOIN user_roles AS ur "
+                    "ON u.user_id=ur.user_id INNER JOIN roles AS r "
+                    "ON ur.role_id=r.role_id "
+                    "WHERE ur.resource_id=?",
+                    (str(resource_id),))
+                return reduce(__organise_users_n_roles__, cursor.fetchall(), {})
         results = (
             {
                 "user": asdict(row["user"]),