From ecce454ca9d0f374e22da8401206e3b1695dbded Mon Sep 17 00:00:00 2001 From: Frederick Muriuki Muriithi Date: Thu, 2 Feb 2023 14:15:29 +0300 Subject: auth: Improve authorisation Retrieve the token, and user in the authorisation decorator to enable checking of privileges. --- gn3/auth/authorisation/checks.py | 29 +++++++++++--------- gn3/auth/authorisation/groups/models.py | 43 ++++++++++++++++-------------- gn3/auth/authorisation/resources/models.py | 3 ++- gn3/auth/authorisation/roles/models.py | 4 ++- 4 files changed, 44 insertions(+), 35 deletions(-) diff --git a/gn3/auth/authorisation/checks.py b/gn3/auth/authorisation/checks.py index 8fef209..6579afc 100644 --- a/gn3/auth/authorisation/checks.py +++ b/gn3/auth/authorisation/checks.py @@ -10,29 +10,32 @@ from . import privileges as auth_privs from .errors import AuthorisationError from ..authentication.users import User +from ..authentication.oauth2.resource_server import require_oauth def authorised_p( privileges: tuple[str], - error_message: str = ( + error_description: str = ( "You lack authorisation to perform requested action"), - user: Optional[User] = None): + oauth2_scope = "profile"): """Authorisation decorator.""" assert len(privileges) > 0, "You must provide at least one privilege" def __build_authoriser__(func: Callable): @wraps(func) def __authoriser__(*args, **kwargs): - the_user = user or (hasattr(g, "user") and g.user) - if the_user: - with db.connection(app.config["AUTH_DB"]) as conn: - user_privileges = tuple( - priv.privilege_id for priv in - auth_privs.user_privileges(conn, the_user)) + # the_user = user or (hasattr(g, "user") and g.user) + with require_oauth.acquire(oauth2_scope) as the_token: + the_user = the_token.user + if the_user: + with db.connection(app.config["AUTH_DB"]) as conn: + user_privileges = tuple( + priv.privilege_id for priv in + auth_privs.user_privileges(conn, the_user)) - not_assigned = [ - priv for priv in privileges if priv not in user_privileges] - if len(not_assigned) == 0: - return func(*args, **kwargs) + not_assigned = [ + priv for priv in privileges if priv not in user_privileges] + if len(not_assigned) == 0: + return func(*args, **kwargs) - raise AuthorisationError(error_message) + raise AuthorisationError(error_message) return __authoriser__ return __build_authoriser__ diff --git a/gn3/auth/authorisation/groups/models.py b/gn3/auth/authorisation/groups/models.py index 0750419..c5c9370 100644 --- a/gn3/auth/authorisation/groups/models.py +++ b/gn3/auth/authorisation/groups/models.py @@ -51,10 +51,10 @@ class MembershipError(AuthorisationError): def __init__(self, user: User, groups: Sequence[Group]): """Initialise the `MembershipError` exception object.""" groups_str = ", ".join(group.group_name for group in groups) - error_message = ( + error_description = ( f"User '{user.name} ({user.email})' is a member of {len(groups)} " f"groups ({groups_str})") - super().__init__(f"{type(self).__name__}: {error_message}.") + super().__init__(f"{type(self).__name__}: {error_description}.") def user_membership(conn: db.DbConnection, user: User) -> Sequence[Group]: """Returns all the groups that a member belongs to""" @@ -70,6 +70,12 @@ def user_membership(conn: db.DbConnection, user: User) -> Sequence[Group]: return groups +@authorised_p( + privileges = ("system:group:create-group",), + error_description = ( + "You do not have the appropriate privileges to enable you to " + "create a new group."), + oauth2_scope = "profile group") def create_group( conn: db.DbConnection, group_name: str, group_leader: User, group_description: Optional[str] = None) -> Group: @@ -78,26 +84,18 @@ def create_group( if len(user_groups) > 0: raise MembershipError(group_leader, user_groups) - @authorised_p( - ("system:group:create-group",), ( - "You do not have the appropriate privileges to enable you to " - "create a new group."), - group_leader) - def __create_group__(): - with db.cursor(conn) as cursor: - new_group = __save_group__( - cursor, group_name,( - {"group_description": group_description} - if group_description else {})) - add_user_to_group(cursor, new_group, group_leader) - revoke_user_role_by_name(cursor, group_leader, "group-creator") - assign_user_role_by_name(cursor, group_leader, "group-leader") - return new_group - - return __create_group__() + with db.cursor(conn) as cursor: + new_group = __save_group__( + cursor, group_name,( + {"group_description": group_description} + if group_description else {})) + add_user_to_group(cursor, new_group, group_leader) + revoke_user_role_by_name(cursor, group_leader, "group-creator") + assign_user_role_by_name(cursor, group_leader, "group-leader") + return new_group @authorised_p(("group:role:create-role",), - error_message="Could not create the group role") + error_description="Could not create the group role") def create_group_role( conn: db.DbConnection, group: Group, role_name: str, privileges: Iterable[Privilege]) -> GroupRole: @@ -210,6 +208,11 @@ def add_user_to_group(cursor: db.DbCursor, the_group: Group, user: User): "ON CONFLICT (group_id, user_id) DO NOTHING"), {"group_id": str(the_group.group_id), "user_id": str(user.user_id)}) +@authorised_p( + privileges = ("system:group:view-group",), + error_description = ( + "You do not have the appropriate privileges to access the list of users" + " in the group.")) def group_users(conn: db.DbConnection, group_id: UUID) -> Iterable[User]: """Retrieve all users that are members of group with id `group_id`.""" with db.cursor(conn) as cursor: diff --git a/gn3/auth/authorisation/resources/models.py b/gn3/auth/authorisation/resources/models.py index 1959362..8d45ef4 100644 --- a/gn3/auth/authorisation/resources/models.py +++ b/gn3/auth/authorisation/resources/models.py @@ -47,7 +47,8 @@ class Resource(NamedTuple): } @authorised_p(("group:resource:create-resource",), - error_message="Could not create resource") + error_description="Insufficient privileges to create a resource", + oauth2_scope="profile resource") def create_resource( conn: db.DbConnection, resource_name: str, resource_category: ResourceCategory) -> Resource: diff --git a/gn3/auth/authorisation/roles/models.py b/gn3/auth/authorisation/roles/models.py index b1aac75..26b8f0a 100644 --- a/gn3/auth/authorisation/roles/models.py +++ b/gn3/auth/authorisation/roles/models.py @@ -27,7 +27,9 @@ class Role(NamedTuple): "privileges": tuple(dictify(priv) for priv in self.privileges) } -@authorised_p(("group:role:create-role",), error_message="Could not create role") +@authorised_p( + privileges = ("group:role:create-role",), + error_description="Could not create role") def create_role( cursor: db.DbCursor, role_name: str, privileges: Iterable[Privilege]) -> Role: -- cgit v1.2.3