about summary refs log tree commit diff
path: root/gn3
diff options
context:
space:
mode:
authorFrederick Muriuki Muriithi2023-03-09 05:23:39 +0300
committerFrederick Muriuki Muriithi2023-03-09 05:23:39 +0300
commitdc8fdfdee59136b2b324042622ed012b296e4fa9 (patch)
tree62028df63cfe8f1837efd7228d2ec2c2c8f94c67 /gn3
parentdee42dd14dc7786b1ccf9465bb28dfe74024166c (diff)
downloadgenenetwork3-dc8fdfdee59136b2b324042622ed012b296e4fa9.tar.gz
auth: data migration: Data migration outline
Provide an outline of the data migration steps to be taken from some results
of the experiments with the data in redis.
Diffstat (limited to 'gn3')
-rw-r--r--gn3/auth/authorisation/data/views.py49
-rw-r--r--gn3/auth/authorisation/users/views.py5
-rw-r--r--gn3/settings.py11
3 files changed, 62 insertions, 3 deletions
diff --git a/gn3/auth/authorisation/data/views.py b/gn3/auth/authorisation/data/views.py
index 08032db..89898c6 100644
--- a/gn3/auth/authorisation/data/views.py
+++ b/gn3/auth/authorisation/data/views.py
@@ -2,17 +2,21 @@
 import uuid
 import json
 
+from email_validator import validate_email, EmailNotValidError
 from authlib.integrations.flask_oauth2.errors import _HTTPException
 from flask import request, jsonify, Response, Blueprint, current_app as app
 
 from gn3.db.traits import build_trait_name
 
 from gn3.auth import db
-from gn3.auth.authentication.oauth2.resource_server import require_oauth
+from gn3.auth.authorisation.users.views import validate_password
 from gn3.auth.authorisation.resources.checks import authorised_for
+from gn3.auth.authorisation.errors import ForbiddenAccess, AuthorisationError
 from gn3.auth.authorisation.resources.models import (
     user_resources, public_resources, attach_resources_data)
 
+from gn3.auth.authentication.oauth2.resource_server import require_oauth
+
 data = Blueprint("data", __name__)
 
 @data.route("/authorisation", methods=["GET"])
@@ -83,3 +87,46 @@ def authorisation() -> Response:
             } for trait in
             (build_trait_name(trait_fullname)
              for trait_fullname in traits_names)))
+
+@data.route("/user/migrate", methods=["POST"])
+@require_oauth("migrate-data")
+def migrate_user_data():
+    """
+    Special, protected endpoint to enable the migration of data from the older
+    system to the newer system with groups, resources and privileges.
+
+    This is a temporary endpoint and should be removed after all the data has
+    been migrated.
+    """
+    authorised_clients = app.config.get(
+        "OAUTH2_CLIENTS_WITH_DATA_MIGRATION_PRIVILEGE", [])
+    with require_oauth.acquire("migrate-data") as the_token:
+        if the_token.client.client_id in authorised_clients:
+            try:
+                _user_id = uuid.UUID(request.form.get("user_id", ""))
+                _email = validate_email(request.form.get("email", ""))
+                _password = validate_password(
+                    request.form.get("password", ""),
+                    request.form.get("confirm_password", ""))
+                ## TODO: Save the user: possible exception for duplicate emails
+                ##       Create group from user's name
+                ##       Filter all resources from redis owned by this user
+                ##         resources = {key: json.loads(val)
+                ##                      for key,val
+                ##                      in rconn.hgetall("resources").items()}
+                ##         filtered = dict((
+                ##             (key,val) for key,val
+                ##             in resources.items()
+                ##             if uuid.UUID(val.get("owner_id")) == user_id))
+                ##       Check that no resource is owned by existing user, use
+                ##         'name' and 'type' fields to check in
+                ##         `linked_group_data` table
+                ##       Link remaining data to the new group
+                ##       Delete user from redis
+                return "WOULD TRIGGER DATA MIGRATION ..."
+            except EmailNotValidError as enve:
+                raise AuthorisationError(f"Email Error: {str(enve)}") from enve
+            except ValueError as verr:
+                raise AuthorisationError(verr.args[0]) from verr
+
+        raise ForbiddenAccess("You cannot access this endpoint.")
diff --git a/gn3/auth/authorisation/users/views.py b/gn3/auth/authorisation/users/views.py
index 5015cac..e3901b4 100644
--- a/gn3/auth/authorisation/users/views.py
+++ b/gn3/auth/authorisation/users/views.py
@@ -51,7 +51,8 @@ def user_roles() -> Response:
             return jsonify(tuple(
                 dictify(role) for role in _user_roles(conn, token.user)))
 
-def __valid_password__(password, confirm_password) -> str:
+def validate_password(password, confirm_password) -> str:
+    """Validate the provided password."""
     if len(password) < 8:
         raise PasswordError("The password must be at least 8 characters long.")
 
@@ -85,7 +86,7 @@ def register_user() -> Response:
             form = request.form
             email = validate_email(form.get("email", "").strip(),
                                    check_deliverability=True)
-            password = __valid_password__(
+            password = validate_password(
                 form.get("password", "").strip(),
                 form.get("confirm_password", "").strip())
             user_name = __valid_username__(form.get("user_name", "").strip())
diff --git a/gn3/settings.py b/gn3/settings.py
index 1b4a105..22bdc98 100644
--- a/gn3/settings.py
+++ b/gn3/settings.py
@@ -81,3 +81,14 @@ try:
             "OAUTH2_CLIENTS_WITH_INTROSPECTION_PRIVILEGE", "").split(","))
 except ValueError as _valerr:
     OAUTH2_CLIENTS_WITH_INTROSPECTION_PRIVILEGE = tuple()
+
+try:
+    # *** SECURITY CONCERN ***
+    # Clients with access to this privileges create a security concern.
+    # Be careful when adding to this configuration
+    OAUTH2_CLIENTS_WITH_DATA_MIGRATION_PRIVILEGE = tuple(
+        uuid.UUID(client_id) for client_id in
+        os.environ.get(
+            "OAUTH2_CLIENTS_WITH_DATA_MIGRATION_PRIVILEGE", "").split(","))
+except ValueError as _valerr:
+    OAUTH2_CLIENTS_WITH_DATA_MIGRATION_PRIVILEGE = tuple()