diff options
Diffstat (limited to 'gn_auth/auth/authorisation/resources')
| -rw-r--r-- | gn_auth/auth/authorisation/resources/checks.py | 80 | ||||
| -rw-r--r-- | gn_auth/auth/authorisation/resources/groups/models.py | 4 | ||||
| -rw-r--r-- | gn_auth/auth/authorisation/resources/models.py | 15 | ||||
| -rw-r--r-- | gn_auth/auth/authorisation/resources/system/models.py | 17 | ||||
| -rw-r--r-- | gn_auth/auth/authorisation/resources/views.py | 14 |
5 files changed, 111 insertions, 19 deletions
diff --git a/gn_auth/auth/authorisation/resources/checks.py b/gn_auth/auth/authorisation/resources/checks.py index ce2b821..bc9e4da 100644 --- a/gn_auth/auth/authorisation/resources/checks.py +++ b/gn_auth/auth/authorisation/resources/checks.py @@ -1,18 +1,25 @@ """Handle authorisation checks for resources""" import uuid +import logging import warnings from functools import reduce from typing import Sequence +import gn_libs.sqlite3 as authdb from gn_libs.privileges import check from .base import Resource +from .system.models import system_resource from ...db import sqlite3 as db from ...authentication.users import User from ..privileges.models import db_row_to_privilege + +logger = logging.getLogger(__name__) + + def __organise_privileges_by_resource_id__(rows): def __organise__(privs, row): resource_id = uuid.UUID(row["resource_id"]) @@ -120,3 +127,76 @@ def authorised_for_spec( (str(resource_id), str(user_id))) _privileges = tuple(row["privilege_id"] for row in cursor.fetchall()) return check(auth_spec, _privileges) + + +def can_delete( + conn: authdb.DbConnection, + user_id: uuid.UUID, + resource_id: uuid.UUID +) -> bool: + """Check whether user is allowed delete a resource and/or its data.""" + return ( + authorised_for_spec(# resource-level delete access + conn, + user_id, + resource_id, + "(OR group:resource:delete-resource system:resource:delete)") + or + authorised_for_spec(# system-wide delete access + conn, + user_id, + system_resource(conn).resource_id, + "(AND system:system-wide:data:delete)")) + + +def can_view( + conn: authdb.DbConnection, + user_id: uuid.UUID, + resource_id: uuid.UUID +) -> bool: + """Check whether user is allowed view a resource and/or its data.""" + with authdb.cursor(conn) as cursor: + cursor.execute("SELECT public FROM resources WHERE resource_id=?", + (str(resource_id),)) + row = cursor.fetchone() + is_public = bool(row) and bool(int(row["public"])) + + return ( + is_public# The resource is public, everyone can view! + or + authorised_for_spec( + # resource-level view access: user has view access to his resource. + conn, + user_id, + resource_id, + "(OR group:resource:view-resource system:resource:view)") + or + authorised_for_spec( + # system-wide view access: user can view any/all resource(s). + conn, + user_id, + system_resource(conn).resource_id, + "(OR system:system-wide:data:view system:resource:view)")) + + +def can_edit( + conn: authdb.DbConnection, + user_id: uuid.UUID, + resource_id: uuid.UUID +) -> bool: + """Check whether user is allowed edit a resource and/or its data.""" + return ( + authorised_for_spec( + # resource-level edit access: user has edit access to his resource. + conn, + user_id, + resource_id, + "(OR group:resource:edit-resource system:resource:edit)") + or + authorised_for_spec( + # system-wide edit access: user can edit any/all resource(s). + conn, + user_id, + system_resource(conn).resource_id, + "(OR system:system-wide:data:edit system:resource:edit)")) + diff --git a/gn_auth/auth/authorisation/resources/groups/models.py b/gn_auth/auth/authorisation/resources/groups/models.py index a1937ce..6a7af4c 100644 --- a/gn_auth/auth/authorisation/resources/groups/models.py +++ b/gn_auth/auth/authorisation/resources/groups/models.py @@ -428,8 +428,8 @@ gjr.status='PENDING'", return tuple(dict(row)for row in cursor.fetchall()) raise AuthorisationError( - "You do not have the appropriate authorisation to access the " - "group's join requests.") + "You need to be the group's leader in order to access the group's join " + "requests.") @authorised_p(("system:group:view-group", "system:group:edit-group"), diff --git a/gn_auth/auth/authorisation/resources/models.py b/gn_auth/auth/authorisation/resources/models.py index 31371fd..a4df363 100644 --- a/gn_auth/auth/authorisation/resources/models.py +++ b/gn_auth/auth/authorisation/resources/models.py @@ -2,9 +2,10 @@ from dataclasses import asdict from uuid import UUID, uuid4 from functools import reduce, partial -from typing import Dict, Sequence, Optional +from typing import Dict, Union, Sequence, Optional + +from gn_libs import sqlite3 as db -from gn_auth.auth.db import sqlite3 as db from gn_auth.auth.authentication.users import User from gn_auth.auth.db.sqlite3 import with_db_connection @@ -40,7 +41,7 @@ from .phenotypes.models import ( error_description="Insufficient privileges to create a resource", oauth2_scope="profile resource") def create_resource(# pylint: disable=[too-many-arguments, too-many-positional-arguments] - conn: db.DbConnection, + conn: Union[db.DbConnection, db.DbCursor], resource_name: str, resource_category: ResourceCategory, user: User, @@ -48,7 +49,7 @@ def create_resource(# pylint: disable=[too-many-arguments, too-many-positional-a public: bool ) -> Resource: """Create a resource item.""" - with db.cursor(conn) as cursor: + def __create_resource__(cursor: db.DbCursor) -> Resource: resource = Resource(uuid4(), resource_name, resource_category, public) cursor.execute( "INSERT INTO resources VALUES (?, ?, ?, ?)", @@ -75,6 +76,12 @@ def create_resource(# pylint: disable=[too-many-arguments, too-many-positional-a return resource + if hasattr(conn, "cursor"): # This is a connection: get its cursor. + with db.cursor(conn) as cursor: + return __create_resource__(cursor) + else: + return __create_resource__(conn) + def delete_resource(conn: db.DbConnection, resource_id: UUID): """Delete a resource.""" diff --git a/gn_auth/auth/authorisation/resources/system/models.py b/gn_auth/auth/authorisation/resources/system/models.py index 303b0ac..25089fa 100644 --- a/gn_auth/auth/authorisation/resources/system/models.py +++ b/gn_auth/auth/authorisation/resources/system/models.py @@ -1,9 +1,10 @@ """Base functions and utilities for system resources.""" from uuid import UUID from functools import reduce -from typing import Sequence +from typing import Union, Sequence + +from gn_libs import sqlite3 as db -from gn_auth.auth.db import sqlite3 as db from gn_auth.auth.errors import NotFoundError from gn_auth.auth.authentication.users import User @@ -52,9 +53,9 @@ def user_roles_on_system(conn: db.DbConnection, user: User) -> Sequence[Role]: return tuple() -def system_resource(conn: db.DbConnection) -> Resource: +def system_resource(conn: Union[db.DbConnection, db.DbCursor]) -> Resource: """Retrieve the system resource.""" - with db.cursor(conn) as cursor: + def __fetch_sys_resource__(cursor: db.DbCursor) -> Resource: cursor.execute( "SELECT resource_categories.*, resources.resource_id, " "resources.resource_name, resources.public " @@ -65,4 +66,10 @@ def system_resource(conn: db.DbConnection) -> Resource: if row: return resource_from_dbrow(row) - raise NotFoundError("Could not find a system resource!") + raise NotFoundError("Could not find a system resource!") + + if hasattr(conn, "cursor"): # is connection + with db.cursor(conn) as cursor: + return __fetch_sys_resource__(cursor) + else: + return __fetch_sys_resource__(conn) diff --git a/gn_auth/auth/authorisation/resources/views.py b/gn_auth/auth/authorisation/resources/views.py index a960ca3..e4401c5 100644 --- a/gn_auth/auth/authorisation/resources/views.py +++ b/gn_auth/auth/authorisation/resources/views.py @@ -39,12 +39,14 @@ from gn_auth.auth.authorisation.roles.models import ( from gn_auth.auth.authentication.oauth2.resource_server import require_oauth from gn_auth.auth.authentication.users import User, user_by_id, user_by_email +from .system.models import system_resource + from .inbredset.views import popbp from .genotypes.views import genobp from .phenotypes.views import phenobp from .errors import MissingGroupError from .groups.models import Group, user_group -from .checks import authorised_for, authorised_for_spec +from .checks import can_delete, authorised_for from .models import ( Resource, resource_data, resource_by_id, public_resources, resource_categories, assign_resource_user, link_data_to_resource, @@ -685,13 +687,9 @@ def delete_resource(): form = request_json() try: resource_id = UUID(form.get("resource_id")) - if not authorised_for_spec( - conn, - the_token.user.user_id, - resource_id, - "(OR group:resource:delete-resource system:resource:delete)"): - raise AuthorisationError("You do not have the appropriate " - "privileges to delete this resource.") + if not can_delete(conn, the_token.user.user_id, resource_id): + raise AuthorisationError( + "You are not allowed to delete this resource.") data = resource_data( conn, |
