aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gn3/auth/authentication/oauth2/models/oauth2client.py19
-rw-r--r--gn3/auth/authorisation/data/views.py135
2 files changed, 104 insertions, 50 deletions
diff --git a/gn3/auth/authentication/oauth2/models/oauth2client.py b/gn3/auth/authentication/oauth2/models/oauth2client.py
index 14f4d5d..5054393 100644
--- a/gn3/auth/authentication/oauth2/models/oauth2client.py
+++ b/gn3/auth/authentication/oauth2/models/oauth2client.py
@@ -154,3 +154,22 @@ def client(conn: db.DbConnection, client_id: uuid.UUID,
the_user))# type: ignore[arg-type]
return Nothing
+
+def client_by_id_and_secret(conn: db.DbConnection, client_id: uuid.UUID,
+ client_secret: str) -> OAuth2Client:
+ """Retrieve a client by its ID and secret"""
+ with db.cursor(conn) as cursor:
+ cursor.execute(
+ "SELECT * FROM oauth2_clients WHERE client_id=? AND "
+ "client_secret=?",
+ (str(client_id), client_secret))
+ row = cursor.fetchone()
+ if bool(row):
+ return OAuth2Client(
+ client_id, client_secret,
+ datetime.datetime.fromtimestamp(row["client_id_issued_at"]),
+ datetime.datetime.fromtimestamp(row["client_secret_expires_at"]),
+ json.loads(row["client_metadata"]),
+ user_by_id(conn, uuid.UUID(row["user_id"])))
+
+ raise NotFoundError(f"Could not find client with ID '{client_id}'")
diff --git a/gn3/auth/authorisation/data/views.py b/gn3/auth/authorisation/data/views.py
index 1b453a3..bde5f9b 100644
--- a/gn3/auth/authorisation/data/views.py
+++ b/gn3/auth/authorisation/data/views.py
@@ -38,6 +38,8 @@ from gn3.auth.authorisation.errors import ForbiddenAccess, AuthorisationError
from gn3.auth.authentication.users import User, user_by_id, set_user_password
from gn3.auth.authentication.oauth2.resource_server import require_oauth
+from gn3.auth.authentication.oauth2.models.oauth2client import (
+ client_by_id_and_secret)
data = Blueprint("data", __name__)
@@ -110,21 +112,6 @@ def authorisation() -> Response:
(build_trait_name(trait_fullname)
for trait_fullname in traits_names)))
-def migrate_user(conn: db.DbConnection, user_id: uuid.UUID, email: str,
- username: str, password: str) -> User:
- """Migrate the user, if not already migrated."""
- try:
- return user_by_id(conn, user_id)
- except NotFoundError as _nfe:
- user = User(user_id, email, username)
- with db.cursor(conn) as cursor:
- cursor.execute(
- "INSERT INTO users(user_id, email, name) "
- "VALUES (?, ?, ?)",
- (str(user.user_id), user.email, user.name))
- set_user_password(cursor, user, password)
- return user
-
def migrate_user_group(conn: db.DbConnection, user: User) -> Group:
"""Create a group for the user if they don't already have a group."""
group = user_group(conn, user).maybe(# type: ignore[misc]
@@ -171,26 +158,32 @@ def __parametrise__(group: Group, datasets: Sequence[dict],
"accession_id": dataset["accession_id"]
} for dataset in datasets)
-def migrate_data(
- authconn: db.DbConnection, gn3conn: gn3db.Connection,
- rconn: redis.Redis, user: User,
- group: Group) -> tuple[dict[str, str], ...]:
- """Migrate data attached to the user to the user's group."""
- redis_mrna, redis_geno, redis_pheno = reduce(# type: ignore[var-annotated]
+def user_redis_resources(rconn: redis.Redis, user_id: uuid.UUID) -> tuple[
+ tuple[dict], tuple[dict], tuple[dict]]:
+ """Acquire any resources from redis."""
+ return reduce(# type: ignore[var-annotated]
__redis_datasets_by_type__,
(dataset for dataset in
(dataset for _key,dataset in {
key: json.loads(val)
for key,val in rconn.hgetall("resources").items()
}.items())
- if dataset["owner_id"] == str(user.user_id)),
+ if dataset["owner_id"] == str(user_id)),
(tuple(), tuple(), tuple()))
+
+def migrate_data(
+ authconn: db.DbConnection, gn3conn: gn3db.Connection,
+ redis_resources: tuple[tuple[dict], tuple[dict], tuple[dict]],
+ user: User, group: Group) -> tuple[dict[str, str], ...]:
+ """Migrate data attached to the user to the user's group."""
+ redis_mrna, redis_geno, redis_pheno = redis_resources
mrna_datasets = __unmigrated_data__(
retrieve_ungrouped_data(authconn, gn3conn, "mrna"), redis_mrna)
geno_datasets = __unmigrated_data__(
retrieve_ungrouped_data(authconn, gn3conn, "genotype"), redis_geno)
pheno_datasets = __unmigrated_data__(
retrieve_ungrouped_data(authconn, gn3conn, "phenotype"), redis_pheno)
+ print(f"MRNA DATASETS: {tuple(mrna_datasets)}")
params = (
__parametrise__(group, mrna_datasets, "mRNA") +
__parametrise__(group, geno_datasets, "Genotype") +
@@ -206,8 +199,62 @@ def migrate_data(
return params
@data.route("/user/migrate", methods=["POST"])
+# @require_oauth("migrate-data")
+def migrate_user() -> Response:
+ """Migrate the user"""
+ def __migrate_user__(conn: db.DbConnection, user_id: uuid.UUID, email: str,
+ username: str, password: str) -> User:
+ """Migrate the user, if not already migrated."""
+ try:
+ return user_by_id(conn, user_id)
+ except NotFoundError as _nfe:
+ user = User(user_id, email, username)
+ with db.cursor(conn) as cursor:
+ cursor.execute(
+ "INSERT INTO users(user_id, email, name) "
+ "VALUES (?, ?, ?)",
+ (str(user.user_id), user.email, user.name))
+ set_user_password(cursor, user, password)
+ return user
+ try:
+ db_uri = app.config.get("AUTH_DB").strip()
+ with (db.connection(db_uri) as authconn,
+ redis.Redis(decode_responses=True) as rconn):
+ client_id = uuid.UUID(request.form.get("client_id"))
+ client_secret = request.form.get("client_secret", "NOTASECRET")
+ client = client_by_id_and_secret(authconn, client_id, client_secret)
+ authorised_clients = app.config.get(
+ "OAUTH2_CLIENTS_WITH_DATA_MIGRATION_PRIVILEGE", [])
+ if client.client_id not in authorised_clients:
+ raise ForbiddenAccess("You cannot access this endpoint.")
+
+ user_id = uuid.UUID(request.form.get("user_id"))
+ redis_dets = rconn.hget("users", str(user_id))
+ user_details = json.loads(redis_dets)
+ if user_details:
+ email = validate_email(user_details["email_address"])
+ user = __migrate_user__(
+ authconn, user_id, email["email"],
+ validate_username(user_details.get("full_name", "")),
+ validate_password(
+ request.form.get("password", ""),
+ request.form.get("confirm_password", "")))
+ return jsonify({
+ "user": dictify(user),
+ "description": "Successfully migrated user."
+ })
+ raise NotFoundError(
+ f"No user with ID '{user_id}'")
+ except EmailNotValidError as enve:
+ raise AuthorisationError(f"Email Error: {str(enve)}") from enve
+ except ValueError as verr:
+ import traceback
+ print(traceback.format_exc())
+ raise AuthorisationError(verr.args[0]) from verr
+
+@data.route("/user/<uuid:user_id>/migrate", methods=["POST"])
@require_oauth("migrate-data")
-def migrate_user_data():
+def migrate_user_data(user_id: uuid.UUID) -> Response:
"""
Special, protected endpoint to enable the migration of data from the older
system to the newer system with groups, resources and privileges.
@@ -221,36 +268,24 @@ def migrate_user_data():
"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", ""))
- fullname = validate_username(
- request.form.get("fullname", ""))
- password = validate_password(
- request.form.get("password", ""),
- request.form.get("confirm_password", ""))
-
- with (db.connection(db_uri) as authconn,
- redis.Redis(decode_responses=True) as rconn,
- gn3db.database_connection() as gn3conn):
- user = migrate_user(
- authconn, user_id, email["email"], fullname,
- password)
+ user = the_token.user
+ with (db.connection(db_uri) as authconn,
+ redis.Redis(decode_responses=True) as rconn,
+ gn3db.database_connection() as gn3conn):
+ redis_resources = user_redis_resources(rconn, user.user_id)
+ user_resource_data = tuple()
+ if any(bool(item) for item in redis_resources):
group = migrate_user_group(authconn, user)
user_resource_data = migrate_data(
- authconn, gn3conn, rconn, user, group)
+ authconn, gn3conn, redis_resources, user, group)
## TODO: Maybe delete user from redis...
- return jsonify({
- "description": (
- f"Migrated {len(user_resource_data)} resource data "
- "items."),
- "user": dictify(user),
- "group": dictify(group)
- })
- except EmailNotValidError as enve:
- raise AuthorisationError(f"Email Error: {str(enve)}") from enve
- except ValueError as verr:
- raise AuthorisationError(verr.args[0]) from verr
+ return jsonify({
+ "description": (
+ f"Migrated {len(user_resource_data)} resource data "
+ "items."),
+ "user": dictify(user),
+ "group": dictify(group)
+ })
raise ForbiddenAccess("You cannot access this endpoint.")