Skip to content

Commit 0ef50d8

Browse files
authored
Merge pull request #52 from Pan-Canadian-Genome-Library/daisieh/daco
Add group DACO approvals
2 parents 8e62fc6 + 2312787 commit 0ef50d8

File tree

7 files changed

+125
-4
lines changed

7 files changed

+125
-4
lines changed

app/daemon.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import os
2+
import sys
3+
from src.auth import reload_comanage
4+
5+
if __name__ == "__main__":
6+
if os.path.isfile("/app/reload"):
7+
print("reloading")
8+
result, status_code = reload_comanage()
9+
os.remove("/app/reload")
10+
print(f"reloaded {status_code} {result}")
11+
sys.exit(10)

app/daemon.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
until python daemon.py; do
2+
sleep 5
3+
done

app/dev.entrypoint.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ fi
4848
# make sure that our vault stores have the latest values
4949
python3 /app/refresh_stores.py
5050

51+
# spin up daemon process
52+
bash /app/daemon.sh &
5153

5254
# start server
5355
cd /app/src

app/entrypoint.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ fi
3333
# make sure that our vault stores have the latest values
3434
python3 /app/refresh_stores.py
3535

36+
# spin up daemon process
37+
bash /app/daemon.sh &
3638

3739
# start server
3840
cd /app/src

app/src/auth.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,7 @@ def list_authz_for_user(pcgl_id, service=SERVICE_NAME):
545545
if status_code == 200:
546546
result["groups"] = groups
547547
return result, status_code
548+
return user_dict, status_code
548549

549550

550551

@@ -765,6 +766,12 @@ def get_user_record(comanage_id=None, oidcsub=None, force=False, service=SERVICE
765766
for email in response.json()["EmailAddresses"]:
766767
if email["Mail"] not in emails and email["Verified"]:
767768
emails.append({"address": email["Mail"], "type": email["Type"]})
769+
# see if we have any DAC auths for this email address:
770+
temp_user, status_code = get_service_store_secret(service, key=f"users/{email["Mail"]}")
771+
if status_code == 200:
772+
for auth in temp_user["study_authorizations"]:
773+
user["study_authorizations"][auth] = temp_user["study_authorizations"][auth]
774+
delete_service_store_secret(service, key=f"users/{email["Mail"]}")
768775
user["emails"] = emails
769776

770777
set_service_store_secret(service, key=f"users/{comanage_id}", value=json.dumps(user))

app/src/authz_openapi.yaml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,21 @@ paths:
185185
schema:
186186
type: string
187187
required: true
188+
post:
189+
summary: Add a DAC authorization for a study for a group of users
190+
description: Authorize a study for a group of users (or update a study auth for a set of users)
191+
operationId: authz_operations.authorize_study_for_users
192+
security:
193+
- bearerAuth: []
194+
requestBody:
195+
$ref: '#/components/requestBodies/StudyDACAuthorizationRequest'
196+
responses:
197+
200:
198+
description: Success
199+
content:
200+
application/json:
201+
schema:
202+
type: object
188203
get:
189204
summary: Get authorization information for a study
190205
description: Get authorization information for a study
@@ -391,6 +406,11 @@ components:
391406
'application/json':
392407
schema:
393408
$ref: "#/components/schemas/StudyAuthorization"
409+
StudyDACAuthorizationRequest:
410+
content:
411+
'application/json':
412+
schema:
413+
$ref: "#/components/schemas/StudyDACAuthorization"
394414
DACAuthorizationRequest:
395415
content:
396416
'application/json':
@@ -491,6 +511,22 @@ components:
491511
- study_id
492512
- start_date
493513
- end_date
514+
StudyDACAuthorization:
515+
type: object
516+
description: a DAC approval for multiple users for the given study
517+
properties:
518+
user_emails:
519+
type: array
520+
items:
521+
type: string
522+
start_date:
523+
type: string
524+
end_date:
525+
type: string
526+
required:
527+
- user_emails
528+
- start_date
529+
- end_date
494530
Action:
495531
type: object
496532
description: an action for which authorization is requested

app/src/authz_operations.py

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,60 @@ async def add_study_authorization():
209209
return {"error": f"{type(e)} {str(e)}"}, 500
210210

211211

212+
@app.route('/study/<path:study_id>')
213+
async def authorize_study_for_users(study_id):
214+
study_dict = await connexion.request.json()
215+
study_dict["study_id"] = study_id
216+
service = "opa"
217+
if "X-Test-Mode" in connexion.request.headers and connexion.request.headers["X-Test-Mode"] == os.getenv("TEST_KEY"):
218+
service = "test"
219+
try:
220+
if auth.is_action_allowed_for_study(connexion.request, method="POST", path=f"/study/{study_id}", study=study_dict["study_id"]):
221+
# we need to check to see if the study even exists in the system
222+
all_studies, status_code = auth.list_studies(service=service)
223+
if status_code != 200:
224+
return all_studies, status_code
225+
if study_dict["study_id"] not in all_studies:
226+
return {"error": f"Study {study_dict['study_id']} does not exist in {all_studies}"}
227+
228+
# for each user, look up user by email:
229+
user_emails = list(set(study_dict["user_emails"]))
230+
result = {"success": [], "error": []}
231+
study_auth = {
232+
"study_id": study_dict["study_id"],
233+
"start_date": study_dict["start_date"],
234+
"end_date": study_dict["end_date"]
235+
}
236+
for user_email in user_emails:
237+
user_dict, status_code = auth.lookup_user_by_email(user_email)
238+
if status_code == 404:
239+
# create a temp user
240+
user_dict = {"study_authorizations": {}, "id": user_email}
241+
user_dict["study_authorizations"][study_dict["study_id"]] = study_auth
242+
response, status_code = auth.write_user(user_dict, service=service)
243+
if status_code == 200:
244+
result["success"].append(user_email)
245+
else:
246+
result["error"].append(f"failed to write auth for {user_email}: {response}")
247+
else:
248+
# the result from lookup_user_by_email is an array, so grab the first thing:
249+
user_dict = user_dict[0]
250+
user_dict["study_authorizations"][study_dict["study_id"]] = study_auth
251+
response, status_code = auth.write_user(user_dict, service=service)
252+
if status_code == 200:
253+
result["success"].append(user_email)
254+
else:
255+
result["error"].append(f"failed to write auth for {user_email}")
256+
return result, 200
257+
return {"error": "User is not authorized to authorize studies"}, 403
258+
except auth.UserTokenError as e:
259+
return {"error": f"{type(e)} {str(e)}"}, 401
260+
except auth.AuthzError as e:
261+
return {"error": f"{type(e)} {str(e)}"}, 403
262+
# except Exception as e:
263+
# return {"error": f"{type(e)} {str(e)}"}, 500
264+
265+
212266
@app.route('/study/<path:study_id>')
213267
def get_study_authorization(study_id):
214268
service = "opa"
@@ -356,7 +410,7 @@ def lookup_user(email=None):
356410
# only add users that have a pcgl id:
357411
if "pcglid" in user:
358412
result.append(user["pcglid"])
359-
return result, status_code
413+
return {"result": result}, status_code
360414
return {"error": "User is not authorized to look up users"}, 403
361415
except auth.UserTokenError as e:
362416
return {"error": f"{type(e)} {str(e)}"}, 401
@@ -394,6 +448,12 @@ async def reload_comanage():
394448
return {"error": f"{type(e)} {str(e)}"}, 403
395449
except Exception as e:
396450
return {"error": f"{type(e)} {str(e)}"}, 500
397-
result, status_code = auth.reload_comanage()
398-
print(result)
399-
return result, status_code
451+
452+
try:
453+
open("/app/reload", "x")
454+
except FileExistsError:
455+
pass
456+
except Exception as e:
457+
return {"error": f"couldn't reload: {type(e)} {str(e)}"}, 500
458+
459+
return {"status": "reloading: should be complete in a minute or two"}, 200

0 commit comments

Comments
 (0)