about summary refs log tree commit diff
path: root/gn_auth/auth/authorisation/resources
diff options
context:
space:
mode:
Diffstat (limited to 'gn_auth/auth/authorisation/resources')
-rw-r--r--gn_auth/auth/authorisation/resources/checks.py80
-rw-r--r--gn_auth/auth/authorisation/resources/groups/models.py4
-rw-r--r--gn_auth/auth/authorisation/resources/models.py15
-rw-r--r--gn_auth/auth/authorisation/resources/system/models.py17
-rw-r--r--gn_auth/auth/authorisation/resources/views.py14
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,