aboutsummaryrefslogtreecommitdiff
path: root/gn3/auth
diff options
context:
space:
mode:
authorFrederick Muriuki Muriithi2023-02-02 11:35:51 +0300
committerFrederick Muriuki Muriithi2023-02-02 12:03:51 +0300
commitdfe5eb18e3ec8dc570d118bfe95c5d4dcb2c7575 (patch)
treeb45da1e9eba405042ef47174215b827739f5a393 /gn3/auth
parent6fc120aca6062f96725adaece85a7b76000affda (diff)
downloadgenenetwork3-dfe5eb18e3ec8dc570d118bfe95c5d4dcb2c7575.tar.gz
auth: Reorganise modules/packages for easier dev and maintenance
Split the views/routes into separate modules each dealing with a narrower scope of the application to aid in maintenance, and help with making the development easier.
Diffstat (limited to 'gn3/auth')
-rw-r--r--gn3/auth/__init__.py4
-rw-r--r--gn3/auth/authentication/oauth2/views.py16
-rw-r--r--gn3/auth/authorisation/groups/__init__.py3
-rw-r--r--gn3/auth/authorisation/groups/models.py (renamed from gn3/auth/authorisation/groups.py)8
-rw-r--r--gn3/auth/authorisation/groups/views.py54
-rw-r--r--gn3/auth/authorisation/resources/__init__.py2
-rw-r--r--gn3/auth/authorisation/resources/models.py (renamed from gn3/auth/authorisation/resources.py)7
-rw-r--r--gn3/auth/authorisation/resources/views.py4
-rw-r--r--gn3/auth/authorisation/roles/__init__.py3
-rw-r--r--gn3/auth/authorisation/roles/models.py (renamed from gn3/auth/authorisation/roles.py)6
-rw-r--r--gn3/auth/authorisation/roles/views.py26
-rw-r--r--gn3/auth/authorisation/users/__init__.py0
-rw-r--r--gn3/auth/authorisation/users/views.py (renamed from gn3/auth/authorisation/views.py)116
-rw-r--r--gn3/auth/blueprint.py4
14 files changed, 146 insertions, 107 deletions
diff --git a/gn3/auth/__init__.py b/gn3/auth/__init__.py
index ba10305..a28498d 100644
--- a/gn3/auth/__init__.py
+++ b/gn3/auth/__init__.py
@@ -2,6 +2,4 @@
from . import authorisation
from . import authentication
-## Setup the endpoints
-from .authorisation.views import *
-from .authentication.oauth2.views import *
+from .views import oauth2
diff --git a/gn3/auth/authentication/oauth2/views.py b/gn3/auth/authentication/oauth2/views.py
index 3af83e2..e440c6e 100644
--- a/gn3/auth/authentication/oauth2/views.py
+++ b/gn3/auth/authentication/oauth2/views.py
@@ -1,41 +1,41 @@
"""Endpoints for the oauth2 server"""
import uuid
-from flask import current_app as app
+from flask import Blueprint, current_app as app
-from gn3.auth.blueprint import oauth2
from .endpoints.revocation import RevocationEndpoint
from .endpoints.introspection import IntrospectionEndpoint
+auth = Blueprint("auth", __name__)
-@oauth2.route("/register-client", methods=["GET", "POST"])
+@auth.route("/register-client", methods=["GET", "POST"])
def register_client():
"""Register an OAuth2 client."""
return "WOULD REGISTER ..."
-@oauth2.route("/delete-client/<uuid:client_id>", methods=["GET", "POST"])
+@auth.route("/delete-client/<uuid:client_id>", methods=["GET", "POST"])
def delete_client(client_id: uuid.UUID):
"""Delete an OAuth2 client."""
return f"WOULD DELETE OAUTH2 CLIENT {client_id}."
-@oauth2.route("/authorise", methods=["GET", "POST"])
+@auth.route("/authorise", methods=["GET", "POST"])
def authorise():
"""Authorise a user"""
return "WOULD AUTHORISE THE USER."
-@oauth2.route("/token", methods=["POST"])
+@auth.route("/token", methods=["POST"])
def token():
"""Retrieve the authorisation token."""
server = app.config["OAUTH2_SERVER"]
return server.create_token_response()
-@oauth2.route("/revoke", methods=["POST"])
+@auth.route("/revoke", methods=["POST"])
def revoke_token():
"""Revoke the token."""
return app.config["OAUTH2_SERVER"].create_endpoint_response(
RevocationEndpoint.ENDPOINT_NAME)
-@oauth2.route("/introspect", methods=["POST"])
+@auth.route("/introspect", methods=["POST"])
def introspect_token():
"""Provide introspection information for the token."""
return app.config["OAUTH2_SERVER"].create_endpoint_response(
diff --git a/gn3/auth/authorisation/groups/__init__.py b/gn3/auth/authorisation/groups/__init__.py
new file mode 100644
index 0000000..1cb0bba
--- /dev/null
+++ b/gn3/auth/authorisation/groups/__init__.py
@@ -0,0 +1,3 @@
+"""Initialise the `gn3.auth.authorisation.groups` package"""
+
+from .models import Group, GroupRole
diff --git a/gn3/auth/authorisation/groups.py b/gn3/auth/authorisation/groups/models.py
index c691457..0750419 100644
--- a/gn3/auth/authorisation/groups.py
+++ b/gn3/auth/authorisation/groups/models.py
@@ -10,10 +10,10 @@ from gn3.auth import db
from gn3.auth.dictify import dictify
from gn3.auth.authentication.users import User
-from .checks import authorised_p
-from .privileges import Privilege
-from .errors import AuthorisationError
-from .roles import (
+from ..checks import authorised_p
+from ..privileges import Privilege
+from ..errors import AuthorisationError
+from ..roles.models import (
Role, create_role, revoke_user_role_by_name, assign_user_role_by_name)
class Group(NamedTuple):
diff --git a/gn3/auth/authorisation/groups/views.py b/gn3/auth/authorisation/groups/views.py
new file mode 100644
index 0000000..02b3162
--- /dev/null
+++ b/gn3/auth/authorisation/groups/views.py
@@ -0,0 +1,54 @@
+"""The views/routes for the `gn3.auth.authorisation.groups` package."""
+import uuid
+
+from flask import request, jsonify, Response, Blueprint, current_app
+
+from gn3.auth import db
+from gn3.auth.dictify import dictify
+
+from .models import (
+ all_groups, GroupCreationError, group_users as _group_users,
+ create_group as _create_group)
+
+from ...authentication.oauth2.resource_server import require_oauth
+
+groups = Blueprint("groups", __name__)
+
+@groups.route("/list", methods=["GET"])
+@require_oauth("profile group")
+def list_groups():
+ """Return the list of groups that exist."""
+ with db.connection(current_app.config["AUTH_DB"]) as conn:
+ the_groups = all_groups(conn)
+
+ return jsonify(the_groups.maybe(
+ [], lambda grps: [dictify(grp) for grp in grps]))
+
+@groups.route("/create", methods=["POST"])
+@require_oauth("profile group")
+def create_group():
+ """Create a new group."""
+ with require_oauth.acquire("profile group") as the_token:
+ group_name=request.form.get("group_name", "").strip()
+ if not bool(group_name):
+ raise GroupCreationError("Could not create the group.")
+
+ db_uri = current_app.config["AUTH_DB"]
+ with db.connection(db_uri) as conn:
+ user = the_token.user
+ new_group = _create_group(
+ conn, group_name, user, request.form.get("group_description"))
+ return jsonify({
+ **dictify(new_group), "group_leader": dictify(user)
+ })
+
+@groups.route("/members/<uuid:group_id>", methods=["GET"])
+@require_oauth("profile group")
+def group_members(group_id: uuid.UUID) -> Response:
+ """Retrieve all the members of a group."""
+ with require_oauth.acquire("profile group") as the_token:# pylint: disable=[unused-variable]
+ db_uri = current_app.config["AUTH_DB"]
+ ## Check that user has appropriate privileges and remove the pylint disable above
+ with db.connection(db_uri) as conn:
+ return jsonify(tuple(
+ dictify(user) for user in _group_users(conn, group_id)))
diff --git a/gn3/auth/authorisation/resources/__init__.py b/gn3/auth/authorisation/resources/__init__.py
new file mode 100644
index 0000000..869ab60
--- /dev/null
+++ b/gn3/auth/authorisation/resources/__init__.py
@@ -0,0 +1,2 @@
+"""Initialise the `gn3.auth.authorisation.resources` package."""
+from .models import Resource, ResourceCategory
diff --git a/gn3/auth/authorisation/resources.py b/gn3/auth/authorisation/resources/models.py
index fe096e8..1959362 100644
--- a/gn3/auth/authorisation/resources.py
+++ b/gn3/auth/authorisation/resources/models.py
@@ -7,9 +7,10 @@ from gn3.auth import db
from gn3.auth.dictify import dictify
from gn3.auth.authentication.users import User
-from .checks import authorised_p
-from .errors import AuthorisationError
-from .groups import Group, user_group, is_group_leader, authenticated_user_group
+from ..checks import authorised_p
+from ..errors import AuthorisationError
+from ..groups.models import (
+ Group, user_group, is_group_leader, authenticated_user_group)
class MissingGroupError(AuthorisationError):
"""Raised for any resource operation without a group."""
diff --git a/gn3/auth/authorisation/resources/views.py b/gn3/auth/authorisation/resources/views.py
new file mode 100644
index 0000000..009cae6
--- /dev/null
+++ b/gn3/auth/authorisation/resources/views.py
@@ -0,0 +1,4 @@
+"""The views/routes for the resources package"""
+from flask import Blueprint
+
+resources = Blueprint("resources", __name__)
diff --git a/gn3/auth/authorisation/roles/__init__.py b/gn3/auth/authorisation/roles/__init__.py
new file mode 100644
index 0000000..293a12f
--- /dev/null
+++ b/gn3/auth/authorisation/roles/__init__.py
@@ -0,0 +1,3 @@
+"""Initialise the `gn3.auth.authorisation.roles` package"""
+
+from .models import Role
diff --git a/gn3/auth/authorisation/roles.py b/gn3/auth/authorisation/roles/models.py
index e9f3fb0..b1aac75 100644
--- a/gn3/auth/authorisation/roles.py
+++ b/gn3/auth/authorisation/roles/models.py
@@ -10,9 +10,9 @@ from gn3.auth import db
from gn3.auth.dictify import dictify
from gn3.auth.authentication.users import User
-from .checks import authorised_p
-from .privileges import Privilege
-from .errors import NotFoundError
+from ..checks import authorised_p
+from ..privileges import Privilege
+from ..errors import NotFoundError
class Role(NamedTuple):
"""Class representing a role: creates immutable objects."""
diff --git a/gn3/auth/authorisation/roles/views.py b/gn3/auth/authorisation/roles/views.py
new file mode 100644
index 0000000..975fb19
--- /dev/null
+++ b/gn3/auth/authorisation/roles/views.py
@@ -0,0 +1,26 @@
+"""The views/routes for the `gn3.auth.authorisation.roles` package."""
+import uuid
+
+from flask import jsonify, Response, Blueprint, current_app
+
+from gn3.auth import db
+from gn3.auth.dictify import dictify
+
+from .models import user_role
+
+from ...authentication.oauth2.resource_server import require_oauth
+
+roles = Blueprint("roles", __name__)
+
+@roles.route("/view/<uuid:role_id>", methods=["GET"])
+@require_oauth("role")
+def view_role(role_id: uuid.UUID) -> Response:
+ """Retrieve a user role with id `role_id`"""
+ def __error__(exc: Exception):
+ raise exc
+ with require_oauth.acquire("profile role") as the_token:
+ db_uri = current_app.config["AUTH_DB"]
+ with db.connection(db_uri) as conn:
+ the_role = user_role(conn, the_token.user, role_id)
+ return the_role.either(
+ __error__, lambda a_role: jsonify(dictify(a_role)))
diff --git a/gn3/auth/authorisation/users/__init__.py b/gn3/auth/authorisation/users/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gn3/auth/authorisation/users/__init__.py
diff --git a/gn3/auth/authorisation/views.py b/gn3/auth/authorisation/users/views.py
index 03c4b03..460f81c 100644
--- a/gn3/auth/authorisation/views.py
+++ b/gn3/auth/authorisation/users/views.py
@@ -1,29 +1,27 @@
-"""Endpoints for the authorisation stuff."""
-import uuid
+"""User authorisation endpoints."""
import traceback
from typing import Tuple, Optional
import sqlite3
-from flask import request, jsonify, Response, current_app
+from flask import request, jsonify, Response, Blueprint, current_app
from gn3.auth import db
from gn3.auth.dictify import dictify
-from gn3.auth.blueprint import oauth2
-from .errors import NotFoundError, UserRegistrationError
-from .resources import user_resources as _user_resources
-from .roles import user_role, assign_default_roles, user_roles as _user_roles
-from .groups import (
- all_groups, GroupCreationError, user_group as _user_group,
- group_users as _group_users, create_group as _create_group)
+from ..groups.models import user_group as _user_group
+from ..errors import NotFoundError, UserRegistrationError
+from ..resources.models import user_resources as _user_resources
+from ..roles.models import assign_default_roles, user_roles as _user_roles
-from ..authentication.oauth2.resource_server import require_oauth
-from ..authentication.users import save_user, set_user_password
-from ..authentication.oauth2.models.oauth2token import token_by_access_token
+from ...authentication.oauth2.resource_server import require_oauth
+from ...authentication.users import save_user, set_user_password
+from ...authentication.oauth2.models.oauth2token import token_by_access_token
-@oauth2.route("/user", methods=["GET"])
+users = Blueprint("users", __name__)
+
+@users.route("/", methods=["GET"])
@require_oauth("profile")
-def user_details():
+def user_details() -> Response:
"""Return user's details."""
with require_oauth.acquire("profile") as the_token:
user = the_token.user
@@ -32,18 +30,23 @@ def user_details():
"group": False
}
with db.connection(current_app.config["AUTH_DB"]) as conn, db.cursor(conn) as cursor:
- return jsonify(_user_group(cursor, user).maybe(
- user_dets,
- lambda group: {**user_dets, "group": dictify(group)}))
+ the_group = _user_group(cursor, user).maybe(# type: ignore[misc]
+ False, lambda grp: grp)# type: ignore[arg-type]
+ return jsonify({
+ **user_dets,
+ "group": dictify(the_group) if the_group else False
+ })
-@oauth2.route("/user-roles", methods=["GET"])
+@users.route("/roles", methods=["GET"])
@require_oauth("role")
-def user_roles():
+def user_roles() -> Response:
"""Return the non-resource roles assigned to the user."""
with require_oauth.acquire("role") as token:
with db.connection(current_app.config["AUTH_DB"]) as conn:
- return jsonify(_user_roles(conn, token.user).maybe(
- tuple(), lambda roles: tuple(dictify(role) for role in roles)))
+ return jsonify(tuple(
+ dictify(role) for role in
+ _user_roles(conn, token.user).maybe(# type: ignore[misc]
+ tuple(), lambda roles: roles)))
def __email_valid__(email: str) -> Tuple[bool, Optional[str]]:
"""Validate the email address."""
@@ -81,8 +84,8 @@ def __assert_not_logged_in__(conn: db.DbConnection):
raise UserRegistrationError(
"Cannot register user while authenticated")
-@oauth2.route("/register-user", methods=["POST"])
-def register_user():
+@users.route("/register", methods=["POST"])
+def register_user() -> Response:
"""Register a user."""
with db.connection(current_app.config["AUTH_DB"]) as conn:
__assert_not_logged_in__(conn)
@@ -111,7 +114,7 @@ def register_user():
"user_id": user.user_id,
"email": user.email,
"name": user.name
- }), 200
+ })
except sqlite3.IntegrityError as sq3ie:
current_app.logger.debug(traceback.format_exc())
raise UserRegistrationError(
@@ -120,64 +123,23 @@ def register_user():
raise Exception(
"unknown_error", "The system experienced an unexpected error.")
-@oauth2.route("/groups", methods=["GET"])
-@require_oauth("profile group")
-def groups():
- """Return the list of groups that exist."""
- with db.connection(current_app.config["AUTH_DB"]) as conn:
- the_groups = all_groups(conn)
-
- return jsonify(the_groups.maybe(
- [], lambda grps: [dictify(grp) for grp in grps]))
-
-@oauth2.route("/create-group", methods=["POST"])
-@require_oauth("profile group")
-def create_group():
- """Create a new group."""
- with require_oauth.acquire("profile group") as the_token:
- group_name=request.form.get("group_name", "").strip()
- if not bool(group_name):
- raise GroupCreationError("Could not create the group.")
-
- db_uri = current_app.config["AUTH_DB"]
- with db.connection(db_uri) as conn:
- user = the_token.user
- new_group = _create_group(
- conn, group_name, user, request.form.get("group_description"))
- return jsonify({
- **dictify(new_group), "group_leader": dictify(user)
- })
-
-@oauth2.route("/role/<uuid:role_id>", methods=["GET"])
-@require_oauth("role")
-def role(role_id: uuid.UUID) -> Response:
- """Retrieve a user role with id `role_id`"""
- def __error__(exc: Exception):
- raise exc
- with require_oauth.acquire("profile role") as the_token:
- db_uri = current_app.config["AUTH_DB"]
- with db.connection(db_uri) as conn:
- the_role = user_role(conn, the_token.user, role_id)
- return the_role.either(
- __error__, lambda a_role: jsonify(dictify(a_role)))
-
-@oauth2.route("/user-group", methods=["GET"])
+@users.route("/group", methods=["GET"])
@require_oauth("profile group")
-def user_group():
+def user_group() -> Response:
"""Retrieve the group in which the user is a member."""
with require_oauth.acquire("profile group") as the_token:
db_uri = current_app.config["AUTH_DB"]
with db.connection(db_uri) as conn, db.cursor(conn) as cursor:
- group = _user_group(cursor, the_token.user).maybe(
- False, lambda grp: grp)
+ group = _user_group(cursor, the_token.user).maybe(# type: ignore[misc]
+ False, lambda grp: grp)# type: ignore[arg-type]
if group:
return jsonify(dictify(group))
raise NotFoundError("User is not a member of any group.")
-@oauth2.route("/user-resources")
+@users.route("/resources")
@require_oauth("profile resource")
-def user_resources():
+def user_resources() -> Response:
"""Retrieve the resources a user has access to."""
with require_oauth.acquire("profile resource") as the_token:
db_uri = current_app.config["AUTH_DB"]
@@ -185,13 +147,3 @@ def user_resources():
return jsonify([
dictify(resource) for resource in
_user_resources(conn, the_token.user)])
-
-@oauth2.route("/group-users/<uuid:group_id>", methods=["GET"])
-@require_oauth("profile group")
-def group_users(group_id: uuid.UUID) -> Response:
- """Retrieve all the members of a group."""
- with require_oauth.acquire("profile group") as the_token:
- db_uri = current_app.config["AUTH_DB"]
- with db.connection(db_uri) as conn:
- return jsonify(tuple(
- dictify(user) for user in _group_users(conn, group_id)))
diff --git a/gn3/auth/blueprint.py b/gn3/auth/blueprint.py
deleted file mode 100644
index 39a031b..0000000
--- a/gn3/auth/blueprint.py
+++ /dev/null
@@ -1,4 +0,0 @@
-"""Setup blueprint for the auth system"""
-from flask import Blueprint
-
-oauth2 = Blueprint("oauth2", __name__)