From 2110bb13bf81dbddc83e1f95a2ae4bb8af2ef099 Mon Sep 17 00:00:00 2001 From: fnguyen Date: Wed, 18 Dec 2024 17:13:49 -0500 Subject: [PATCH 1/3] Add an endpoint for the user to check their own authorization --- auth.py | 16 ++++++++++++++++ ingest_openapi.yaml | 12 ++++++++++++ ingest_operations.py | 13 +++++++++++++ 3 files changed, 41 insertions(+) diff --git a/auth.py b/auth.py index fe433e4..5421a48 100644 --- a/auth.py +++ b/auth.py @@ -193,6 +193,16 @@ def list_pending_users_in_opa(token): return response, status_code +def is_self_pending(token): + response, status_code = authx.auth.get_service_store_secret("opa", key=f"pending_users") + if status_code == 200: + user_name = get_user_name(token) + response = user_name in response["pending_users"] + else: + response = False + return response, status_code + + def approve_pending_user_in_opa(user_name, token): if not is_site_admin(token): return {"error": f"User not authorized to approve pending users"}, 403 @@ -258,6 +268,12 @@ def get_user_in_opa(user_name, token): return response, status_code +def get_self_in_opa(token): + safe_name = urllib.parse.quote_plus(get_user_name(token)) + response, status_code = authx.auth.get_service_store_secret("opa", key=f"users/{safe_name}") + return response, status_code + + def remove_user_from_opa(user_name, token): if not is_site_admin(token): return {"error": f"User not authorized to remove users"}, 403 diff --git a/ingest_openapi.yaml b/ingest_openapi.yaml index 9cafc86..eb0d7bc 100644 --- a/ingest_openapi.yaml +++ b/ingest_openapi.yaml @@ -317,6 +317,18 @@ paths: application/json: schema: type: object + /user/self_authorize: + get: + summary: List program authorizations + description: List authorizations for programs for the authenticated user + operationId: ingest_operations.is_self_authorized + responses: + 200: + description: Success + content: + application/json: + schema: + type: object /user/{user_id}/authorize: parameters: - in: path diff --git a/ingest_operations.py b/ingest_operations.py index abf37de..debb6b1 100644 --- a/ingest_operations.py +++ b/ingest_operations.py @@ -362,6 +362,19 @@ def clear_pending_users(): # DAC authorization for users #### +def is_self_authorized(): + token = connexion.request.headers['Authorization'].split("Bearer ")[1] + response, status_code = auth.get_self_in_opa(token) + if status_code == 404: + # We next check if the user is pending + response, status_code = auth.is_self_pending(token) + # NB: The results is a string if unauthorized or pending, and a list otherwise + return {"results": "Pending" if response else "Unauthorized"}, status_code + print(response) + # NB: The results is a list if authorized, and a string otherwise + return {"results": list(response["programs"].values())}, status_code + + @app.route('/user//authorize') def list_programs_for_user(user_id): token = connexion.request.headers['Authorization'].split("Bearer ")[1] From 2773da6a9e4674f1d850c4137a774e2b63087792 Mon Sep 17 00:00:00 2001 From: fnguyen Date: Thu, 19 Dec 2024 14:53:44 -0500 Subject: [PATCH 2/3] Rename function to better fit --- ingest_openapi.yaml | 6 +++--- ingest_operations.py | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ingest_openapi.yaml b/ingest_openapi.yaml index eb0d7bc..98e990c 100644 --- a/ingest_openapi.yaml +++ b/ingest_openapi.yaml @@ -317,11 +317,11 @@ paths: application/json: schema: type: object - /user/self_authorize: + /user/self/authorize: get: - summary: List program authorizations + summary: List own program authorizations description: List authorizations for programs for the authenticated user - operationId: ingest_operations.is_self_authorized + operationId: ingest_operations.list_programs_for_self responses: 200: description: Success diff --git a/ingest_operations.py b/ingest_operations.py index debb6b1..062c8a9 100644 --- a/ingest_operations.py +++ b/ingest_operations.py @@ -362,7 +362,8 @@ def clear_pending_users(): # DAC authorization for users #### -def is_self_authorized(): +@app.route('/user/self/authorize') +def list_programs_for_self(): token = connexion.request.headers['Authorization'].split("Bearer ")[1] response, status_code = auth.get_self_in_opa(token) if status_code == 404: From ab21bca6945a9f837df9f9811c158dc6ef05db3d Mon Sep 17 00:00:00 2001 From: fnguyen Date: Thu, 19 Dec 2024 15:07:56 -0500 Subject: [PATCH 3/3] Fold the new endpoint into the old one, but triggered if userID is "me" --- ingest_openapi.yaml | 13 +------------ ingest_operations.py | 25 +++++++++++++++---------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/ingest_openapi.yaml b/ingest_openapi.yaml index 98e990c..9e535b4 100644 --- a/ingest_openapi.yaml +++ b/ingest_openapi.yaml @@ -317,18 +317,6 @@ paths: application/json: schema: type: object - /user/self/authorize: - get: - summary: List own program authorizations - description: List authorizations for programs for the authenticated user - operationId: ingest_operations.list_programs_for_self - responses: - 200: - description: Success - content: - application/json: - schema: - type: object /user/{user_id}/authorize: parameters: - in: path @@ -336,6 +324,7 @@ paths: schema: type: string required: true + description: The user ID to check. If "me", return information about the requesting user get: summary: List program authorizations description: List authorizations for programs for a user diff --git a/ingest_operations.py b/ingest_operations.py index 062c8a9..951d2aa 100644 --- a/ingest_operations.py +++ b/ingest_operations.py @@ -362,29 +362,34 @@ def clear_pending_users(): # DAC authorization for users #### -@app.route('/user/self/authorize') -def list_programs_for_self(): - token = connexion.request.headers['Authorization'].split("Bearer ")[1] +def list_programs_for_self(token): response, status_code = auth.get_self_in_opa(token) if status_code == 404: # We next check if the user is pending response, status_code = auth.is_self_pending(token) # NB: The results is a string if unauthorized or pending, and a list otherwise - return {"results": "Pending" if response else "Unauthorized"}, status_code + return "Pending" if response else "Unauthorized", status_code print(response) # NB: The results is a list if authorized, and a string otherwise - return {"results": list(response["programs"].values())}, status_code + return list(response["programs"].values()), status_code @app.route('/user//authorize') def list_programs_for_user(user_id): token = connexion.request.headers['Authorization'].split("Bearer ")[1] - user_name = urllib.parse.unquote_plus(user_id) - response, status_code = auth.get_user_in_opa(user_name, token) - if status_code != 200: - return response, status_code + response = "" + status_code = 0 + if user_id == "me": + # Grab the user's own authorization + response, status_code = list_programs_for_self(token) + else: + user_name = urllib.parse.unquote_plus(user_id) + response, status_code = auth.get_user_in_opa(user_name, token) + if status_code != 200: + return response, status_code + response = list(response["programs"].values()) print(response) - return {"results": list(response["programs"].values())}, status_code + return {"results": response}, status_code @app.route('/user//authorize')