From 6d61ef8de94fa87cb6ee31cc57f1f37dd04d097d Mon Sep 17 00:00:00 2001 From: Frederick Muriuki Muriithi Date: Wed, 24 Apr 2024 11:34:09 +0300 Subject: Move the errors module up one level to break circular dependencies. --- .../authentication/oauth2/grants/password_grant.py | 3 +- .../authentication/oauth2/models/oauth2client.py | 3 +- .../authentication/oauth2/models/oauth2token.py | 2 +- gn_auth/auth/authentication/oauth2/views.py | 4 +-- gn_auth/auth/authentication/users.py | 2 +- gn_auth/auth/authorisation/checks.py | 4 +-- gn_auth/auth/authorisation/data/views.py | 2 +- gn_auth/auth/authorisation/errors.py | 41 ---------------------- gn_auth/auth/authorisation/resources/errors.py | 2 +- .../auth/authorisation/resources/groups/data.py | 2 +- .../auth/authorisation/resources/groups/models.py | 2 +- .../auth/authorisation/resources/groups/views.py | 2 +- gn_auth/auth/authorisation/resources/models.py | 2 +- gn_auth/auth/authorisation/resources/views.py | 2 +- gn_auth/auth/authorisation/roles/models.py | 3 +- gn_auth/auth/authorisation/users/admin/views.py | 2 +- .../auth/authorisation/users/collections/models.py | 2 +- .../auth/authorisation/users/collections/views.py | 3 +- .../auth/authorisation/users/masquerade/models.py | 4 +-- .../auth/authorisation/users/masquerade/views.py | 4 +-- gn_auth/auth/authorisation/users/views.py | 2 +- gn_auth/auth/errors.py | 41 ++++++++++++++++++++++ gn_auth/errors.py | 2 +- scripts/gn_auth_wsgi.py | 3 +- tests/unit/auth/test_groups.py | 2 +- tests/unit/auth/test_resources.py | 2 +- tests/unit/auth/test_roles.py | 2 +- 27 files changed, 72 insertions(+), 73 deletions(-) delete mode 100644 gn_auth/auth/authorisation/errors.py create mode 100644 gn_auth/auth/errors.py diff --git a/gn_auth/auth/authentication/oauth2/grants/password_grant.py b/gn_auth/auth/authentication/oauth2/grants/password_grant.py index 79382fd..acd0958 100644 --- a/gn_auth/auth/authentication/oauth2/grants/password_grant.py +++ b/gn_auth/auth/authentication/oauth2/grants/password_grant.py @@ -4,10 +4,9 @@ from flask import current_app as app from authlib.oauth2.rfc6749 import grants from gn_auth.auth.db import sqlite3 as db +from gn_auth.auth.errors import NotFoundError from gn_auth.auth.authentication.users import valid_login, user_by_email -from gn_auth.auth.authorisation.errors import NotFoundError - class PasswordGrant(grants.ResourceOwnerPasswordCredentialsGrant): """Implement the 'Password' grant.""" TOKEN_ENDPOINT_AUTH_METHODS = ["client_secret_basic", "client_secret_post"] diff --git a/gn_auth/auth/authentication/oauth2/models/oauth2client.py b/gn_auth/auth/authentication/oauth2/models/oauth2client.py index 98c3001..0f40688 100644 --- a/gn_auth/auth/authentication/oauth2/models/oauth2client.py +++ b/gn_auth/auth/authentication/oauth2/models/oauth2client.py @@ -11,13 +11,12 @@ from authlib.oauth2.rfc6749 import ClientMixin from pymonad.maybe import Just, Maybe, Nothing from gn_auth.auth.db import sqlite3 as db +from gn_auth.auth.errors import NotFoundError from gn_auth.auth.authentication.users import (User, fetch_users, user_by_id, same_password) -from gn_auth.auth.authorisation.errors import NotFoundError - @dataclass(frozen=True) class OAuth2Client(ClientMixin): diff --git a/gn_auth/auth/authentication/oauth2/models/oauth2token.py b/gn_auth/auth/authentication/oauth2/models/oauth2token.py index 45962cd..6ec5c3d 100644 --- a/gn_auth/auth/authentication/oauth2/models/oauth2token.py +++ b/gn_auth/auth/authentication/oauth2/models/oauth2token.py @@ -10,8 +10,8 @@ from pymonad.tools import monad_from_none_or_value from pymonad.maybe import Just, Maybe, Nothing from gn_auth.auth.db import sqlite3 as db +from gn_auth.auth.errors import NotFoundError from gn_auth.auth.authentication.users import User, user_by_id -from gn_auth.auth.authorisation.errors import NotFoundError from .oauth2client import client, OAuth2Client diff --git a/gn_auth/auth/authentication/oauth2/views.py b/gn_auth/auth/authentication/oauth2/views.py index add2cba..8e2ceef 100644 --- a/gn_auth/auth/authentication/oauth2/views.py +++ b/gn_auth/auth/authentication/oauth2/views.py @@ -16,13 +16,13 @@ from flask import ( from gn_auth.auth.db import sqlite3 as db from gn_auth.auth.db.sqlite3 import with_db_connection -from gn_auth.auth.authorisation.errors import ForbiddenAccess +from gn_auth.auth.errors import NotFoundError, ForbiddenAccess +from gn_auth.auth.authentication.users import valid_login, user_by_email from .resource_server import require_oauth from .endpoints.revocation import RevocationEndpoint from .endpoints.introspection import IntrospectionEndpoint -from ..users import valid_login, NotFoundError, user_by_email auth = Blueprint("auth", __name__) diff --git a/gn_auth/auth/authentication/users.py b/gn_auth/auth/authentication/users.py index 1f364b8..ca37524 100644 --- a/gn_auth/auth/authentication/users.py +++ b/gn_auth/auth/authentication/users.py @@ -7,7 +7,7 @@ from argon2 import PasswordHasher from argon2.exceptions import VerifyMismatchError from gn_auth.auth.db import sqlite3 as db -from gn_auth.auth.authorisation.errors import NotFoundError +from gn_auth.auth.errors import NotFoundError @dataclass(frozen=True) diff --git a/gn_auth/auth/authorisation/checks.py b/gn_auth/auth/authorisation/checks.py index 4d5b6bc..66bb723 100644 --- a/gn_auth/auth/authorisation/checks.py +++ b/gn_auth/auth/authorisation/checks.py @@ -4,9 +4,9 @@ from typing import Callable from flask import request, current_app as app -from . import privileges as auth_privs -from .errors import InvalidData, AuthorisationError +from gn_auth.auth.errors import InvalidData, AuthorisationError +from . import privileges as auth_privs from ..db import sqlite3 as db from ..authentication.oauth2.resource_server import require_oauth diff --git a/gn_auth/auth/authorisation/data/views.py b/gn_auth/auth/authorisation/data/views.py index 01fffcd..83f4e4b 100644 --- a/gn_auth/auth/authorisation/data/views.py +++ b/gn_auth/auth/authorisation/data/views.py @@ -14,6 +14,7 @@ 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.errors import InvalidData, NotFoundError from gn_auth.auth.authorisation.resources.groups.models import group_by_id from ...db import sqlite3 as db @@ -21,7 +22,6 @@ from ...db import mariadb as gn3db from ...db.sqlite3 import with_db_connection from ..checks import require_json -from ..errors import InvalidData, NotFoundError from ..users.models import user_resource_roles diff --git a/gn_auth/auth/authorisation/errors.py b/gn_auth/auth/authorisation/errors.py deleted file mode 100644 index 60d6a22..0000000 --- a/gn_auth/auth/authorisation/errors.py +++ /dev/null @@ -1,41 +0,0 @@ -"""Authorisation exceptions""" - -class AuthorisationError(Exception): - """ - Top-level exception for the `gn3.auth.authorisation` package. - - All exceptions in this package should inherit from this class. - """ - error_code: int = 400 - -class ForbiddenAccess(AuthorisationError): - """Raised for forbidden access.""" - error_code: int = 403 - -class UserRegistrationError(AuthorisationError): - """Raised whenever a user registration fails""" - -class NotFoundError(AuthorisationError): - """Raised whenever we try fetching (a/an) object(s) that do(es) not exist.""" - error_code: int = 404 - -class InvalidData(AuthorisationError): - """ - Exception if user requests invalid data - """ - -class InconsistencyError(AuthorisationError): - """ - Exception raised due to data inconsistencies - """ - error_code: int = 500 - -class PasswordError(AuthorisationError): - """ - Raise in case of an error with passwords. - """ - -class UsernameError(AuthorisationError): - """ - Raise in case of an error with a user's name. - """ diff --git a/gn_auth/auth/authorisation/resources/errors.py b/gn_auth/auth/authorisation/resources/errors.py index dc6c379..a13ea1f 100644 --- a/gn_auth/auth/authorisation/resources/errors.py +++ b/gn_auth/auth/authorisation/resources/errors.py @@ -1,6 +1,6 @@ """Exceptions for Authorisation""" -from gn_auth.auth.authorisation.errors import AuthorisationError +from gn_auth.auth.errors import AuthorisationError class MissingGroupError(AuthorisationError): """Raised for any resource operation without a group.""" diff --git a/gn_auth/auth/authorisation/resources/groups/data.py b/gn_auth/auth/authorisation/resources/groups/data.py index 9fcdc6e..702955d 100644 --- a/gn_auth/auth/authorisation/resources/groups/data.py +++ b/gn_auth/auth/authorisation/resources/groups/data.py @@ -4,8 +4,8 @@ from MySQLdb.cursors import DictCursor from gn_auth.auth.db import mariadb as gn3db from gn_auth.auth.db import sqlite3 as authdb +from gn_auth.auth.errors import NotFoundError 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__( diff --git a/gn_auth/auth/authorisation/resources/groups/models.py b/gn_auth/auth/authorisation/resources/groups/models.py index e8c3492..3feefa6 100644 --- a/gn_auth/auth/authorisation/resources/groups/models.py +++ b/gn_auth/auth/authorisation/resources/groups/models.py @@ -15,7 +15,7 @@ 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 ( +from gn_auth.auth.errors import ( NotFoundError, AuthorisationError, InconsistencyError) from gn_auth.auth.authorisation.roles.models import ( Role, create_role, check_user_editable, revoke_user_role_by_name, diff --git a/gn_auth/auth/authorisation/resources/groups/views.py b/gn_auth/auth/authorisation/resources/groups/views.py index 303368c..fe7a3de 100644 --- a/gn_auth/auth/authorisation/resources/groups/views.py +++ b/gn_auth/auth/authorisation/resources/groups/views.py @@ -19,7 +19,7 @@ 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.errors import InvalidData, NotFoundError, AuthorisationError from gn_auth.auth.authentication.users import User from gn_auth.auth.authentication.oauth2.resource_server import require_oauth diff --git a/gn_auth/auth/authorisation/resources/models.py b/gn_auth/auth/authorisation/resources/models.py index 9931559..e23aac5 100644 --- a/gn_auth/auth/authorisation/resources/models.py +++ b/gn_auth/auth/authorisation/resources/models.py @@ -11,7 +11,7 @@ from gn_auth.auth.db.sqlite3 import with_db_connection from gn_auth.auth.authorisation.roles import Role from gn_auth.auth.authorisation.privileges import Privilege from gn_auth.auth.authorisation.checks import authorised_p -from gn_auth.auth.authorisation.errors import NotFoundError, AuthorisationError +from gn_auth.auth.errors import NotFoundError, AuthorisationError from .checks import authorised_for from .base import Resource, ResourceCategory diff --git a/gn_auth/auth/authorisation/resources/views.py b/gn_auth/auth/authorisation/resources/views.py index e256b3e..58adaa2 100644 --- a/gn_auth/auth/authorisation/resources/views.py +++ b/gn_auth/auth/authorisation/resources/views.py @@ -14,7 +14,7 @@ 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.errors import InvalidData, InconsistencyError, AuthorisationError 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 diff --git a/gn_auth/auth/authorisation/roles/models.py b/gn_auth/auth/authorisation/roles/models.py index b45dcc1..3ec3316 100644 --- a/gn_auth/auth/authorisation/roles/models.py +++ b/gn_auth/auth/authorisation/roles/models.py @@ -7,12 +7,13 @@ from typing import Sequence, Iterable from pymonad.either import Left, Right, Either +from gn_auth.auth.errors import NotFoundError, AuthorisationError + from ...db import sqlite3 as db from ...authentication.users import User from ..checks import authorised_p from ..privileges import Privilege -from ..errors import NotFoundError, AuthorisationError @dataclass(frozen=True) diff --git a/gn_auth/auth/authorisation/users/admin/views.py b/gn_auth/auth/authorisation/users/admin/views.py index aed8b31..7ffee95 100644 --- a/gn_auth/auth/authorisation/users/admin/views.py +++ b/gn_auth/auth/authorisation/users/admin/views.py @@ -18,7 +18,7 @@ from flask import ( from gn_auth import session -from gn_auth.auth.authorisation.errors import NotFoundError +from gn_auth.auth.errors import NotFoundError from ....db import sqlite3 as db from ....db.sqlite3 import with_db_connection diff --git a/gn_auth/auth/authorisation/users/collections/models.py b/gn_auth/auth/authorisation/users/collections/models.py index 9397094..b4a24f3 100644 --- a/gn_auth/auth/authorisation/users/collections/models.py +++ b/gn_auth/auth/authorisation/users/collections/models.py @@ -6,7 +6,7 @@ from datetime import datetime from redis import Redis from email_validator import validate_email, EmailNotValidError -from ...errors import InvalidData, NotFoundError +from gn_auth.auth.errors import InvalidData, NotFoundError from ..models import User diff --git a/gn_auth/auth/authorisation/users/collections/views.py b/gn_auth/auth/authorisation/users/collections/views.py index 6c68b35..eeae91d 100644 --- a/gn_auth/auth/authorisation/users/collections/views.py +++ b/gn_auth/auth/authorisation/users/collections/views.py @@ -4,6 +4,8 @@ from uuid import UUID from redis import Redis from flask import jsonify, request, Response, Blueprint, current_app +from gn_auth.auth.errors import NotFoundError + from ....db import sqlite3 as db from ....db.sqlite3 import with_db_connection @@ -11,7 +13,6 @@ from ....authentication.users import User, user_by_id from ....authentication.oauth2.resource_server import require_oauth from ...checks import require_json -from ...errors import NotFoundError from .models import ( add_traits, diff --git a/gn_auth/auth/authorisation/users/masquerade/models.py b/gn_auth/auth/authorisation/users/masquerade/models.py index 86b9e53..57bc564 100644 --- a/gn_auth/auth/authorisation/users/masquerade/models.py +++ b/gn_auth/auth/authorisation/users/masquerade/models.py @@ -6,9 +6,9 @@ from datetime import datetime from flask import current_app as app -from ...errors import ForbiddenAccess -from ...roles.models import user_roles +from gn_auth.auth.errors import ForbiddenAccess +from ...roles.models import user_roles from ....db import sqlite3 as db from ....authentication.users import User from ....authentication.oauth2.models.oauth2token import ( diff --git a/gn_auth/auth/authorisation/users/masquerade/views.py b/gn_auth/auth/authorisation/users/masquerade/views.py index b0464ba..276859a 100644 --- a/gn_auth/auth/authorisation/users/masquerade/views.py +++ b/gn_auth/auth/authorisation/users/masquerade/views.py @@ -5,9 +5,9 @@ from functools import partial from flask import request, jsonify, Response, Blueprint -from ...errors import InvalidData -from ...checks import require_json +from gn_auth.auth.errors import InvalidData +from ...checks import require_json from ....db.sqlite3 import with_db_connection from ....authentication.users import user_by_id from ....authentication.oauth2.resource_server import require_oauth diff --git a/gn_auth/auth/authorisation/users/views.py b/gn_auth/auth/authorisation/users/views.py index 7a32292..9ea0c59 100644 --- a/gn_auth/auth/authorisation/users/views.py +++ b/gn_auth/auth/authorisation/users/views.py @@ -14,7 +14,7 @@ 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 ( +from gn_auth.auth.errors import ( NotFoundError, UsernameError, PasswordError, UserRegistrationError) from gn_auth.auth.authorisation.resources.groups.models import ( user_group as _user_group) diff --git a/gn_auth/auth/errors.py b/gn_auth/auth/errors.py new file mode 100644 index 0000000..60d6a22 --- /dev/null +++ b/gn_auth/auth/errors.py @@ -0,0 +1,41 @@ +"""Authorisation exceptions""" + +class AuthorisationError(Exception): + """ + Top-level exception for the `gn3.auth.authorisation` package. + + All exceptions in this package should inherit from this class. + """ + error_code: int = 400 + +class ForbiddenAccess(AuthorisationError): + """Raised for forbidden access.""" + error_code: int = 403 + +class UserRegistrationError(AuthorisationError): + """Raised whenever a user registration fails""" + +class NotFoundError(AuthorisationError): + """Raised whenever we try fetching (a/an) object(s) that do(es) not exist.""" + error_code: int = 404 + +class InvalidData(AuthorisationError): + """ + Exception if user requests invalid data + """ + +class InconsistencyError(AuthorisationError): + """ + Exception raised due to data inconsistencies + """ + error_code: int = 500 + +class PasswordError(AuthorisationError): + """ + Raise in case of an error with passwords. + """ + +class UsernameError(AuthorisationError): + """ + Raise in case of an error with a user's name. + """ diff --git a/gn_auth/errors.py b/gn_auth/errors.py index 7e90659..7b6ad33 100644 --- a/gn_auth/errors.py +++ b/gn_auth/errors.py @@ -4,7 +4,7 @@ import traceback from werkzeug.exceptions import NotFound from flask import Flask, request, jsonify, current_app, render_template -from gn_auth.auth.authorisation.errors import AuthorisationError +from gn_auth.auth.errors import AuthorisationError def add_trace(exc: Exception, errobj: dict) -> dict: """Add the traceback to the error handling object.""" diff --git a/scripts/gn_auth_wsgi.py b/scripts/gn_auth_wsgi.py index 1de0b56..811a0d5 100644 --- a/scripts/gn_auth_wsgi.py +++ b/scripts/gn_auth_wsgi.py @@ -17,9 +17,8 @@ from gn_auth import migrations from gn_auth import create_app from gn_auth.auth.db import sqlite3 as db +from gn_auth.auth.errors import NotFoundError from gn_auth.auth.authentication.users import user_by_id, hash_password - -from gn_auth.auth.authorisation.errors import NotFoundError from gn_auth.auth.authorisation.users.admin.models import make_sys_admin from scripts import register_sys_admin as rsysadm# type: ignore[import] diff --git a/tests/unit/auth/test_groups.py b/tests/unit/auth/test_groups.py index a6a0da5..c9d8b19 100644 --- a/tests/unit/auth/test_groups.py +++ b/tests/unit/auth/test_groups.py @@ -5,10 +5,10 @@ import pytest from pymonad.maybe import Nothing from gn_auth.auth.db import sqlite3 as db +from gn_auth.auth.errors import AuthorisationError from gn_auth.auth.authentication.users import User from gn_auth.auth.authorisation.roles import Role from gn_auth.auth.authorisation.privileges import Privilege -from gn_auth.auth.authorisation.errors import AuthorisationError from gn_auth.auth.authorisation.resources.groups.models import ( Group, GroupRole, user_group, create_group, create_group_role) diff --git a/tests/unit/auth/test_resources.py b/tests/unit/auth/test_resources.py index 9b4d0e7..85641be 100644 --- a/tests/unit/auth/test_resources.py +++ b/tests/unit/auth/test_resources.py @@ -4,8 +4,8 @@ import uuid import pytest from gn_auth.auth.db import sqlite3 as db +from gn_auth.auth.errors import AuthorisationError -from gn_auth.auth.authorisation.errors import AuthorisationError from gn_auth.auth.authorisation.resources.groups import Group from gn_auth.auth.authorisation.resources.models import ( Resource, user_resources, create_resource, ResourceCategory, diff --git a/tests/unit/auth/test_roles.py b/tests/unit/auth/test_roles.py index 6c8dbae..00148a0 100644 --- a/tests/unit/auth/test_roles.py +++ b/tests/unit/auth/test_roles.py @@ -4,8 +4,8 @@ import uuid import pytest from gn_auth.auth.db import sqlite3 as db +from gn_auth.auth.errors import AuthorisationError from gn_auth.auth.authorisation.privileges import Privilege -from gn_auth.auth.authorisation.errors import AuthorisationError from gn_auth.auth.authorisation.roles.models import Role, user_roles, create_role from tests.unit.auth import conftest -- cgit v1.2.3