diff options
Diffstat (limited to 'gn_auth')
16 files changed, 119 insertions, 107 deletions
diff --git a/gn_auth/auth/authorisation/data/genotypes.py b/gn_auth/auth/authorisation/data/genotypes.py index 818f72d..bfddfc1 100644 --- a/gn_auth/auth/authorisation/data/genotypes.py +++ b/gn_auth/auth/authorisation/data/genotypes.py @@ -4,12 +4,12 @@ from typing import Iterable from MySQLdb.cursors import DictCursor -from ..checks import authorised_p -from ..groups.models import Group +from gn_auth.auth.dictify import dictify +from gn_auth.auth.db import mariadb as gn3db +from gn_auth.auth.db import sqlite3 as authdb -from ...dictify import dictify -from ...db import mariadb as gn3db -from ...db import sqlite3 as authdb +from gn_auth.auth.authorisation.checks import authorised_p +from gn_auth.auth.authorisation.resources.groups.models import Group def linked_genotype_data(conn: authdb.DbConnection) -> Iterable[dict]: """Retrive genotype data that is linked to user groups.""" diff --git a/gn_auth/auth/authorisation/data/mrna.py b/gn_auth/auth/authorisation/data/mrna.py index 53f9bf9..edcd29e 100644 --- a/gn_auth/auth/authorisation/data/mrna.py +++ b/gn_auth/auth/authorisation/data/mrna.py @@ -3,12 +3,12 @@ import uuid from typing import Iterable from MySQLdb.cursors import DictCursor -from ..checks import authorised_p -from ..groups.models import Group +from gn_auth.auth.dictify import dictify +from gn_auth.auth.db import sqlite3 as authdb +from gn_auth.auth.db import mariadb as gn3db -from ...dictify import dictify -from ...db import sqlite3 as authdb -from ...db import mariadb as gn3db +from gn_auth.auth.authorisation.checks import authorised_p +from gn_auth.auth.authorisation.resources.groups.models import Group def linked_mrna_data(conn: authdb.DbConnection) -> Iterable[dict]: """Retrieve mRNA Assay data that is linked to user groups.""" diff --git a/gn_auth/auth/authorisation/data/phenotypes.py b/gn_auth/auth/authorisation/data/phenotypes.py index 84fc089..17555ec 100644 --- a/gn_auth/auth/authorisation/data/phenotypes.py +++ b/gn_auth/auth/authorisation/data/phenotypes.py @@ -4,13 +4,12 @@ from typing import Any, Iterable from MySQLdb.cursors import DictCursor +from gn_auth.auth.dictify import dictify +from gn_auth.auth.db import sqlite3 as authdb +from gn_auth.auth.db import mariadb as gn3db -from ..checks import authorised_p -from ..groups.models import Group - -from ...dictify import dictify -from ...db import sqlite3 as authdb -from ...db import mariadb as gn3db +from gn_auth.auth.authorisation.checks import authorised_p +from gn_auth.auth.authorisation.resources.groups.models import Group def linked_phenotype_data( authconn: authdb.DbConnection, gn3conn: gn3db.DbConnection, diff --git a/gn_auth/auth/authorisation/data/views.py b/gn_auth/auth/authorisation/data/views.py index 3c49ae5..a674ab4 100644 --- a/gn_auth/auth/authorisation/data/views.py +++ b/gn_auth/auth/authorisation/data/views.py @@ -13,6 +13,8 @@ from flask import request, jsonify, Response, Blueprint, current_app as app from gn_auth import jobs from gn_auth.commands import run_async_cmd +from gn_auth.auth.authorisation.resources.groups.models import group_by_id + from ...db import sqlite3 as db from ...db import mariadb as gn3db from ...db.sqlite3 import with_db_connection @@ -20,8 +22,6 @@ from ...db.sqlite3 import with_db_connection from ..checks import require_json from ..errors import InvalidData, NotFoundError -from ..groups.models import group_by_id - from ..users.models import user_resource_roles from ..resources.checks import authorised_for diff --git a/gn_auth/auth/authorisation/resources/errors.py b/gn_auth/auth/authorisation/resources/errors.py new file mode 100644 index 0000000..dc6c379 --- /dev/null +++ b/gn_auth/auth/authorisation/resources/errors.py @@ -0,0 +1,6 @@ +"""Exceptions for Authorisation""" + +from gn_auth.auth.authorisation.errors import AuthorisationError + +class MissingGroupError(AuthorisationError): + """Raised for any resource operation without a group.""" diff --git a/gn_auth/auth/authorisation/resources/genotype_resource.py b/gn_auth/auth/authorisation/resources/genotype.py index 206ab61..206ab61 100644 --- a/gn_auth/auth/authorisation/resources/genotype_resource.py +++ b/gn_auth/auth/authorisation/resources/genotype.py diff --git a/gn_auth/auth/authorisation/groups/__init__.py b/gn_auth/auth/authorisation/resources/groups/__init__.py index 1cb0bba..1cb0bba 100644 --- a/gn_auth/auth/authorisation/groups/__init__.py +++ b/gn_auth/auth/authorisation/resources/groups/__init__.py diff --git a/gn_auth/auth/authorisation/groups/data.py b/gn_auth/auth/authorisation/resources/groups/data.py index 1650405..9fcdc6e 100644 --- a/gn_auth/auth/authorisation/groups/data.py +++ b/gn_auth/auth/authorisation/resources/groups/data.py @@ -1,12 +1,12 @@ """Handles the resource objects' data.""" from MySQLdb.cursors import DictCursor -from ..groups import Group -from ..checks import authorised_p -from ..errors import NotFoundError +from gn_auth.auth.db import mariadb as gn3db +from gn_auth.auth.db import sqlite3 as authdb -from ...db import mariadb as gn3db -from ...db import sqlite3 as authdb +from gn_auth.auth.authorisation.checks import authorised_p +from gn_auth.auth.authorisation.errors import NotFoundError +from gn_auth.auth.authorisation.resources.groups import Group def __fetch_mrna_data_by_ids__( conn: gn3db.DbConnection, dataset_ids: tuple[str, ...]) -> tuple[ diff --git a/gn_auth/auth/authorisation/groups/models.py b/gn_auth/auth/authorisation/resources/groups/models.py index c40adbd..5ec26c5 100644 --- a/gn_auth/auth/authorisation/groups/models.py +++ b/gn_auth/auth/authorisation/resources/groups/models.py @@ -7,14 +7,17 @@ from typing import Any, Sequence, Iterable, Optional, NamedTuple from flask import g from pymonad.maybe import Just, Maybe, Nothing -from ...db import sqlite3 as db -from ...dictify import dictify -from ...authentication.users import User, user_by_id - -from ..checks import authorised_p -from ..privileges import Privilege -from ..errors import NotFoundError, AuthorisationError, InconsistencyError -from ..roles.models import ( +from gn_auth.auth.db import sqlite3 as db +from gn_auth.auth.dictify import dictify +from gn_auth.auth.authentication.users import User, user_by_id + +from gn_auth.auth.authorisation.checks import authorised_p +from gn_auth.auth.authorisation.privileges import Privilege +from gn_auth.auth.authorisation.resources.base import Resource +from gn_auth.auth.authorisation.resources.errors import MissingGroupError +from gn_auth.auth.authorisation.errors import ( + NotFoundError, AuthorisationError, InconsistencyError) +from gn_auth.auth.authorisation.roles.models import ( Role, create_role, check_user_editable, revoke_user_role_by_name, assign_user_role_by_name) @@ -431,3 +434,20 @@ def delete_privilege_from_group_role( group_role.role.user_editable, tuple(priv for priv in group_role.role.privileges if priv != privilege))) + +def resource_owner(conn: db.DbConnection, resource: Resource) -> Group: + """Return the user group that owns the resource.""" + with db.cursor(conn) as cursor: + cursor.execute( + "SELECT g.* FROM resource_ownership AS ro " + "INNER JOIN groups AS g ON ro.group_id=g.group_id " + "WHERE ro.resource_id=?", + (str(resource.resource_id),)) + row = cursor.fetchone() + if row: + return Group( + UUID(row["group_id"]), + row["group_name"], + json.loads(row["group_metadata"])) + + raise MissingGroupError("Resource has no 'owning' group.") diff --git a/gn_auth/auth/authorisation/groups/views.py b/gn_auth/auth/authorisation/resources/groups/views.py index 4dc17e0..f146ffd 100644 --- a/gn_auth/auth/authorisation/groups/views.py +++ b/gn_auth/auth/authorisation/resources/groups/views.py @@ -1,4 +1,6 @@ -"""The views/routes for the `gn3.auth.authorisation.groups` package.""" +""" +The views/routes for the `gn3.auth.authorisation.resources.groups` package. +""" import uuid import datetime from typing import Iterable @@ -7,11 +9,20 @@ from functools import partial from MySQLdb.cursors import DictCursor from flask import request, jsonify, Response, Blueprint, current_app -from ...db import sqlite3 as db -from ...db import mariadb as gn3db +from gn_auth.auth.db import sqlite3 as db +from gn_auth.auth.db import mariadb as gn3db +from gn_auth.auth.db.sqlite3 import with_db_connection +from gn_auth.auth.dictify import dictify -from ...dictify import dictify -from ...db.sqlite3 import with_db_connection +from gn_auth.auth.authorisation.roles.models import Role +from gn_auth.auth.authorisation.roles.models import user_roles + +from gn_auth.auth.authorisation.checks import authorised_p +from gn_auth.auth.authorisation.privileges import Privilege, privileges_by_ids +from gn_auth.auth.authorisation.errors import InvalidData, NotFoundError, AuthorisationError + +from gn_auth.auth.authentication.users import User +from gn_auth.auth.authentication.oauth2.resource_server import require_oauth from .data import link_data_to_group from .models import ( @@ -21,16 +32,6 @@ from .models import ( create_group as _create_group, add_privilege_to_group_role, delete_privilege_from_group_role, create_group_role as _create_group_role) -from ..roles.models import Role -from ..roles.models import user_roles - -from ..checks import authorised_p -from ..privileges import Privilege, privileges_by_ids -from ..errors import InvalidData, NotFoundError, AuthorisationError - -from ...authentication.users import User -from ...authentication.oauth2.resource_server import require_oauth - groups = Blueprint("groups", __name__) @groups.route("/list", methods=["GET"]) diff --git a/gn_auth/auth/authorisation/resources/models.py b/gn_auth/auth/authorisation/resources/models.py index f307fdc..80820a5 100644 --- a/gn_auth/auth/authorisation/resources/models.py +++ b/gn_auth/auth/authorisation/resources/models.py @@ -1,38 +1,37 @@ """Handle the management of resources.""" -import json from uuid import UUID, uuid4 from functools import reduce, partial from typing import Dict, Sequence, Optional -from ...db import sqlite3 as db -from ...dictify import dictify -from ...authentication.users import User -from ...db.sqlite3 import with_db_connection +from gn_auth.auth.db import sqlite3 as db +from gn_auth.auth.dictify import dictify +from gn_auth.auth.authentication.users import User +from gn_auth.auth.db.sqlite3 import with_db_connection -from ..checks import authorised_p -from ..errors import NotFoundError, AuthorisationError -from ..groups.models import Group, GroupRole, user_group, is_group_leader +from gn_auth.auth.authorisation.checks import authorised_p +from gn_auth.auth.authorisation.errors import NotFoundError, AuthorisationError from .checks import authorised_for from .base import Resource, ResourceCategory -from .mrna_resource import ( +from .groups.models import ( + Group, GroupRole, user_group, resource_owner, is_group_leader) +from .mrna import ( resource_data as mrna_resource_data, attach_resources_data as mrna_attach_resources_data, link_data_to_resource as mrna_link_data_to_resource, unlink_data_from_resource as mrna_unlink_data_from_resource) -from .genotype_resource import ( +from .genotype import ( resource_data as genotype_resource_data, attach_resources_data as genotype_attach_resources_data, link_data_to_resource as genotype_link_data_to_resource, unlink_data_from_resource as genotype_unlink_data_from_resource) -from .phenotype_resource import ( +from .phenotype import ( resource_data as phenotype_resource_data, attach_resources_data as phenotype_attach_resources_data, link_data_to_resource as phenotype_link_data_to_resource, unlink_data_from_resource as phenotype_unlink_data_from_resource) -class MissingGroupError(AuthorisationError): - """Raised for any resource operation without a group.""" +from .errors import MissingGroupError def __assign_resource_owner_role__(cursor, resource, user, group): """Assign `user` the 'Resource Owner' role for `resource`.""" @@ -73,7 +72,7 @@ def create_resource( group = user_group(conn, user).maybe( False, lambda grp: grp)# type: ignore[misc, arg-type] if not group: - raise MissingGroupError( + raise MissingGroupError(# Not all resources require an owner group "User with no group cannot create a resource.") resource = Resource(uuid4(), resource_name, resource_category, public) cursor.execute( @@ -246,7 +245,7 @@ def link_data_to_resource( "genotype": genotype_link_data_to_resource, "phenotype": phenotype_link_data_to_resource, }[dataset_type.lower()]( - conn, resource, resource_group(conn, resource), data_link_id) + conn, resource, resource_owner(conn, resource), data_link_id) def unlink_data_from_resource( conn: db.DbConnection, user: User, resource_id: UUID, data_link_id: UUID): @@ -367,20 +366,3 @@ def save_resource( raise AuthorisationError( "You do not have the appropriate privileges to edit this resource.") - -def resource_group(conn: db.DbConnection, resource: Resource) -> Group: - """Return the group that owns the resource.""" - with db.cursor(conn) as cursor: - cursor.execute( - "SELECT g.* FROM resource_ownership AS ro " - "INNER JOIN groups AS g ON ro.group_id=g.group_id " - "WHERE ro.resource_id=?", - (str(resource.resource_id),)) - row = cursor.fetchone() - if row: - return Group( - UUID(row["group_id"]), - row["group_name"], - json.loads(row["group_metadata"])) - - raise MissingGroupError("Resource has no 'owning' group.") diff --git a/gn_auth/auth/authorisation/resources/mrna_resource.py b/gn_auth/auth/authorisation/resources/mrna.py index 7fce227..7fce227 100644 --- a/gn_auth/auth/authorisation/resources/mrna_resource.py +++ b/gn_auth/auth/authorisation/resources/mrna.py diff --git a/gn_auth/auth/authorisation/resources/phenotype_resource.py b/gn_auth/auth/authorisation/resources/phenotype.py index 046357c..cd3f23d 100644 --- a/gn_auth/auth/authorisation/resources/phenotype_resource.py +++ b/gn_auth/auth/authorisation/resources/phenotype.py @@ -5,8 +5,8 @@ from typing import Optional, Sequence import sqlite3 import gn_auth.auth.db.sqlite3 as db -from gn_auth.auth.authorisation.groups import Group +from .groups import Group from .base import Resource from .data import __attach_data__ diff --git a/gn_auth/auth/authorisation/resources/views.py b/gn_auth/auth/authorisation/resources/views.py index 4fe04d9..0e44df5 100644 --- a/gn_auth/auth/authorisation/resources/views.py +++ b/gn_auth/auth/authorisation/resources/views.py @@ -6,23 +6,23 @@ from functools import reduce from flask import request, jsonify, Response, Blueprint, current_app as app -from ...db import sqlite3 as db -from ...db.sqlite3 import with_db_connection +from gn_auth.auth.db import sqlite3 as db +from gn_auth.auth.db.sqlite3 import with_db_connection + +from gn_auth.auth.authorisation.roles import Role +from gn_auth.auth.authorisation.errors import InvalidData, InconsistencyError, AuthorisationError + +from gn_auth.auth.dictify import dictify +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 .checks import authorised_for from .models import ( - Resource, save_resource, resource_data, resource_group, resource_by_id, + Resource, save_resource, resource_data, resource_by_id, resource_categories, assign_resource_user, link_data_to_resource, unassign_resource_user, resource_category_by_id, unlink_data_from_resource, create_resource as _create_resource) - -from ..roles import Role -from ..errors import InvalidData, InconsistencyError, AuthorisationError -from ..groups.models import Group, GroupRole, group_role_by_id - -from ...dictify import dictify -from ...authentication.oauth2.resource_server import require_oauth -from ...authentication.users import User, user_by_id, user_by_email +from .groups.models import Group, GroupRole, resource_owner, group_role_by_id resources = Blueprint("resources", __name__) @@ -165,7 +165,7 @@ def resource_users(resource_id: uuid.UUID): "user", User(user_id, row["email"], row["name"])) role = GroupRole( uuid.UUID(row["group_role_id"]), - resource_group(conn, resource), + resource_owner(conn, resource), Role(uuid.UUID(row["role_id"]), row["role_name"], bool(int(row["user_editable"])), tuple())) return { @@ -222,7 +222,7 @@ def assign_role_to_user(resource_id: uuid.UUID) -> Response: return assign_resource_user( conn, resource, user, group_role_by_id(conn, - resource_group(conn, resource), + resource_owner(conn, resource), uuid.UUID(group_role_id))) except AssertionError as aserr: raise AuthorisationError(aserr.args[0]) from aserr @@ -246,7 +246,7 @@ def unassign_role_to_user(resource_id: uuid.UUID) -> Response: return unassign_resource_user( conn, resource, user_by_id(conn, uuid.UUID(user_id)), group_role_by_id(conn, - resource_group(conn, resource), + resource_owner(conn, resource), uuid.UUID(group_role_id))) except AssertionError as aserr: raise AuthorisationError(aserr.args[0]) from aserr diff --git a/gn_auth/auth/authorisation/users/views.py b/gn_auth/auth/authorisation/users/views.py index 6de30da..50386ac 100644 --- a/gn_auth/auth/authorisation/users/views.py +++ b/gn_auth/auth/authorisation/users/views.py @@ -7,24 +7,28 @@ import sqlite3 from email_validator import validate_email, EmailNotValidError from flask import request, jsonify, Response, Blueprint, current_app -from ...db import sqlite3 as db -from ...dictify import dictify -from ...db.sqlite3 import with_db_connection +from gn_auth.auth.db import sqlite3 as db +from gn_auth.auth.dictify import dictify +from gn_auth.auth.db.sqlite3 import with_db_connection + +from gn_auth.auth.authorisation.resources.models import ( + user_resources as _user_resources) +from gn_auth.auth.authorisation.roles.models import ( + assign_default_roles, user_roles as _user_roles) +from gn_auth.auth.authorisation.errors import ( + NotFoundError, UsernameError, PasswordError, UserRegistrationError) +from gn_auth.auth.authorisation.resources.groups.models import ( + user_group as _user_group) + +from gn_auth.auth.authentication.oauth2.resource_server import require_oauth +from gn_auth.auth.authentication.users import User, save_user, set_user_password +from gn_auth.auth.authentication.oauth2.models.oauth2token import ( + token_by_access_token) from .models import list_users from .masquerade.views import masq from .collections.views import collections -from ..groups.models import user_group as _user_group -from ..resources.models import user_resources as _user_resources -from ..roles.models import assign_default_roles, user_roles as _user_roles -from ..errors import ( - NotFoundError, UsernameError, PasswordError, UserRegistrationError) - -from ...authentication.oauth2.resource_server import require_oauth -from ...authentication.users import User, save_user, set_user_password -from ...authentication.oauth2.models.oauth2token import token_by_access_token - users = Blueprint("users", __name__) users.register_blueprint(masq, url_prefix="/masquerade") users.register_blueprint(collections, url_prefix="/collections") diff --git a/gn_auth/auth/views.py b/gn_auth/auth/views.py index 56eace7..cd1cb6f 100644 --- a/gn_auth/auth/views.py +++ b/gn_auth/auth/views.py @@ -7,8 +7,8 @@ from .authorisation.data.views import data from .authorisation.users.views import users from .authorisation.users.admin import admin from .authorisation.roles.views import roles -from .authorisation.groups.views import groups from .authorisation.resources.views import resources +from .authorisation.resources.groups.views import groups oauth2 = Blueprint("oauth2", __name__) |