From 98dc0c5b1a67a7c7b97a1fa02211e9f99360edce Mon Sep 17 00:00:00 2001
From: Frederick Muriuki Muriithi
Date: Mon, 16 Jan 2023 12:14:24 +0300
Subject: auth: update privileges format

Save privileges with ids of the form <top-level>:<sub-level>:<privilege-name>
rather than using a UUID, to reduce indirection levels.

* migrations/auth/20230116_01_KwuJ3-rework-privileges-schema.py: new migration
  to change the schema and IDs for the privileges.
* Update code to use new privileges format
  * gn3/auth/authorisation/checks.py
  * gn3/auth/authorisation/groups.py
  * gn3/auth/authorisation/privileges.py
  * gn3/auth/authorisation/resources.py
  * gn3/auth/authorisation/roles.py
  * migrations/auth/20230116_01_KwuJ3-rework-privileges-schema.py
  * tests/unit/auth/fixtures/role_fixtures.py
  * tests/unit/auth/test_groups.py
  * tests/unit/auth/test_privileges.py
  * tests/unit/auth/test_roles.py
---
 gn3/auth/authorisation/checks.py     |  2 +-
 gn3/auth/authorisation/groups.py     |  6 ++++--
 gn3/auth/authorisation/privileges.py |  9 ++++-----
 gn3/auth/authorisation/resources.py  |  3 ++-
 gn3/auth/authorisation/roles.py      | 10 +++++-----
 5 files changed, 16 insertions(+), 14 deletions(-)

(limited to 'gn3/auth/authorisation')

diff --git a/gn3/auth/authorisation/checks.py b/gn3/auth/authorisation/checks.py
index dd041fe..d847c1e 100644
--- a/gn3/auth/authorisation/checks.py
+++ b/gn3/auth/authorisation/checks.py
@@ -19,7 +19,7 @@ def authorised_p(
             if hasattr(g, "user") and g.user:
                 with db.connection(app.config["AUTH_DB"]) as conn:
                     user_privileges = tuple(
-                        priv.privilege_name for priv in
+                        priv.privilege_id for priv in
                         auth_privs.user_privileges(conn, g.user))
 
                 not_assigned = [
diff --git a/gn3/auth/authorisation/groups.py b/gn3/auth/authorisation/groups.py
index ff4dc80..bbabd44 100644
--- a/gn3/auth/authorisation/groups.py
+++ b/gn3/auth/authorisation/groups.py
@@ -49,7 +49,8 @@ def user_membership(conn: db.DbConnection, user: User) -> Sequence[Group]:
     return groups
 
 @authenticated_p
-@authorised_p(("create-group",), error_message="Failed to create group.")
+@authorised_p(("system:group:create-group",),
+              error_message="Failed to create group.")
 def create_group(conn: db.DbConnection, group_name: str,
                  group_leader: User) -> Group:
     """Create a group"""
@@ -69,7 +70,8 @@ def create_group(conn: db.DbConnection, group_name: str,
     return group
 
 @authenticated_p
-@authorised_p(("create-role",), error_message="Could not create the group role")
+@authorised_p(("group:role:create-role",),
+              error_message="Could not create the group role")
 def create_group_role(
         conn: db.DbConnection, group: Group, role_name: str,
         privileges: Iterable[Privilege]) -> GroupRole:
diff --git a/gn3/auth/authorisation/privileges.py b/gn3/auth/authorisation/privileges.py
index 9e66bda..6cfd1d8 100644
--- a/gn3/auth/authorisation/privileges.py
+++ b/gn3/auth/authorisation/privileges.py
@@ -1,5 +1,4 @@
 """Handle privileges"""
-from uuid import UUID
 from typing import Iterable, NamedTuple
 
 from gn3.auth import db
@@ -7,14 +6,14 @@ from gn3.auth.authentication.users import User
 
 class Privilege(NamedTuple):
     """Class representing a privilege: creates immutable objects."""
-    privilege_id: UUID
-    privilege_name: str
+    privilege_id: str
+    privilege_description: str
 
 def user_privileges(conn: db.DbConnection, user: User) -> Iterable[Privilege]:
     """Fetch the user's privileges from the database."""
     with db.cursor(conn) as cursor:
         cursor.execute(
-            ("SELECT p.privilege_id, p.privilege_name "
+            ("SELECT p.privilege_id, p.privilege_description "
              "FROM user_roles AS ur "
              "INNER JOIN role_privileges AS rp ON ur.role_id=rp.role_id "
              "INNER JOIN privileges AS p ON rp.privilege_id=p.privilege_id "
@@ -22,4 +21,4 @@ def user_privileges(conn: db.DbConnection, user: User) -> Iterable[Privilege]:
             (str(user.user_id),))
         results = cursor.fetchall()
 
-    return (Privilege(UUID(row[0]), row[1]) for row in results)
+    return (Privilege(row[0], row[1]) for row in results)
diff --git a/gn3/auth/authorisation/resources.py b/gn3/auth/authorisation/resources.py
index bc6ba44..f27d61a 100644
--- a/gn3/auth/authorisation/resources.py
+++ b/gn3/auth/authorisation/resources.py
@@ -26,7 +26,8 @@ class Resource(NamedTuple):
     resource_category: ResourceCategory
     public: bool
 
-@authorised_p(("create-resource",),  error_message="Could not create resource")
+@authorised_p(("group:resource:create-resource",),
+              error_message="Could not create resource")
 def create_resource(
         conn: db.DbConnection, resource_name: str,
         resource_category: ResourceCategory) -> Resource:
diff --git a/gn3/auth/authorisation/roles.py b/gn3/auth/authorisation/roles.py
index 6602c9f..606403e 100644
--- a/gn3/auth/authorisation/roles.py
+++ b/gn3/auth/authorisation/roles.py
@@ -17,7 +17,7 @@ class Role(NamedTuple):
     privileges: Iterable[Privilege]
 
 @authenticated_p
-@authorised_p(("create-role",), error_message="Could not create role")
+@authorised_p(("group:role:create-role",), error_message="Could not create role")
 def create_role(
         cursor: db.DbCursor, role_name: str,
         privileges: Iterable[Privilege]) -> Role:
@@ -55,8 +55,8 @@ def __organise_privileges__(roles_dict, privilege_row):
                 UUID(role_id_str),
                 privilege_row["role_name"],
                 roles_dict[role_id_str].privileges + (
-                    Privilege(UUID(privilege_row["privilege_id"]),
-                              privilege_row["privilege_name"]),))
+                    Privilege(privilege_row["privilege_id"],
+                              privilege_row["privilege_description"]),))
         }
 
     return {
@@ -64,8 +64,8 @@ def __organise_privileges__(roles_dict, privilege_row):
         role_id_str: Role(
             UUID(role_id_str),
             privilege_row["role_name"],
-            (Privilege(UUID(privilege_row["privilege_id"]),
-                       privilege_row["privilege_name"]),))
+            (Privilege(privilege_row["privilege_id"],
+                       privilege_row["privilege_description"]),))
     }
 
 def user_roles(conn: db.DbConnection, user: User):
-- 
cgit v1.2.3