Skip to content

Commit 9500f84

Browse files
committed
add rbac to dos
1 parent 1b7b6e3 commit 9500f84

4 files changed

Lines changed: 72 additions & 6 deletions

File tree

indexd/dos/blueprint.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
import sys
2+
import traceback
3+
14
import flask
25

6+
from indexd.auth import AuthzError
37
from indexd.blueprint import dist_get_record
48

59
from indexd.errors import AuthError
@@ -15,12 +19,32 @@
1519
blueprint.dist = []
1620

1721

22+
@blueprint.errorhandler(Exception)
23+
def handle_uncaught_exception(err):
24+
print(f"Uncaught Exception: {err}", file=sys.stderr)
25+
traceback.print_exc(file=sys.stderr)
26+
return flask.jsonify(error=f"Internal server error"), 500
27+
28+
29+
@blueprint.errorhandler(AuthzError)
30+
def handle_authz_error(err):
31+
ret = {"msg": str(err), "status_code": 401}
32+
return flask.jsonify(ret), 401
33+
34+
35+
@blueprint.errorhandler(AuthError)
36+
def handle_requester_auth_error(err):
37+
ret = {"msg": str(err), "status_code": 403}
38+
return flask.jsonify(ret), 403
39+
40+
1841
@blueprint.route("/ga4gh/dos/v1/dataobjects/<path:record>", methods=["GET"])
1942
def get_dos_record(record):
2043
"""
2144
Returns a record from the local ids, alias, or global resolvers.
2245
Returns DOS Schema
2346
"""
47+
2448
try:
2549
ret = blueprint.index_driver.get(record)
2650
# record may be a baseID or a DID / GUID. If record is a baseID, ret["did"] is the latest GUID for that record.
@@ -157,3 +181,6 @@ def get_config(setup_state):
157181
blueprint.alias_driver = alias_config["driver"]
158182
if "DIST" in setup_state.app.config:
159183
blueprint.dist = setup_state.app.config["DIST"]
184+
blueprint.rbac = False
185+
if "RBAC" in setup_state.app.config:
186+
blueprint.rbac = setup_state.app.config["RBAC"]

indexd/index/drivers/alchemy.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1225,7 +1225,9 @@ def get(self, did, expand=True):
12251225
# overwrite the "no bundle found" message
12261226
raise NoRecordFound("no record found")
12271227

1228-
return record.to_document_dict()
1228+
document_dict = record.to_document_dict()
1229+
_enforce_record_authz(document_dict)
1230+
return document_dict
12291231

12301232
def get_with_nonstrict_prefix(self, did, expand=True):
12311233
"""

tests/test_client.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2640,13 +2640,17 @@ def test_bad_hashes(client, user, typ, h, combined_default_and_single_table_sett
26402640
assert "does not match" in json_resp["error"]
26412641

26422642

2643-
def test_dos_get(client, user, combined_default_and_single_table_settings):
2643+
def test_dos_get(client, user, combined_default_and_single_table_settings, is_rbac_configured):
26442644
data = get_doc(has_urls_metadata=True, has_metadata=True, has_baseid=True)
26452645

26462646
res_1 = client.post("/index/", json=data, headers=user)
26472647
assert res_1.status_code == 200
26482648
rec_1 = res_1.json
2649-
res_2 = client.get("/ga4gh/dos/v1/dataobjects/" + rec_1["did"])
2649+
if is_rbac_configured:
2650+
res_2 = client.get("/ga4gh/dos/v1/dataobjects/" + rec_1["did"])
2651+
assert res_2.status_code == 403 # No authz in request
2652+
2653+
res_2 = client.get("/ga4gh/dos/v1/dataobjects/" + rec_1["did"], headers=user)
26502654
assert res_2.status_code == 200
26512655
rec_2 = res_2.json
26522656
assert rec_2["data_object"]["id"] == rec_1["did"]
@@ -2662,8 +2666,13 @@ def test_dos_get(client, user, combined_default_and_single_table_settings):
26622666
rec_2["data_object"]["urls"][0]["system_metadata"]["project_id"]
26632667
== "bpa-UChicago"
26642668
)
2665-
res_3 = client.get("/ga4gh/dos/v1/dataobjects/" + rec_1["baseid"])
2669+
if is_rbac_configured:
2670+
res_3 = client.get("/ga4gh/dos/v1/dataobjects/" + rec_1["baseid"])
2671+
assert res_3.status_code == 403
2672+
2673+
res_3 = client.get("/ga4gh/dos/v1/dataobjects/" + rec_1["baseid"], headers=user)
26662674
assert res_3.status_code == 200
2675+
26672676
rec_3 = res_3.json
26682677
assert rec_3["data_object"]["id"] == rec_1["did"]
26692678

@@ -2675,15 +2684,20 @@ def test_get_dos_record_error(client, user, combined_default_and_single_table_se
26752684
assert res.status_code == 404
26762685

26772686

2678-
def test_dos_list(client, user, combined_default_and_single_table_settings):
2687+
def test_dos_list(client, user, combined_default_and_single_table_settings, is_rbac_configured):
26792688
data = get_doc(has_urls_metadata=True, has_metadata=True, has_baseid=True)
26802689

26812690
res_1 = client.post("/index/", json=data, headers=user)
26822691
assert res_1.status_code == 200
26832692
rec_1 = res_1.json
26842693

2685-
res_2 = client.get("/ga4gh/dos/v1/dataobjects?page_size=100")
2694+
if is_rbac_configured:
2695+
res_2 = client.get("/ga4gh/dos/v1/dataobjects?page_size=100")
2696+
assert res_2.status_code == 403
2697+
2698+
res_2 = client.get("/ga4gh/dos/v1/dataobjects?page_size=100", headers=user)
26862699
assert res_2.status_code == 200
2700+
26872701
rec_2 = res_2.json
26882702
assert len(rec_2["data_objects"]) == 1
26892703
assert rec_2["data_objects"][0]["id"] == rec_1["did"]

tests/test_rbac.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,19 @@ def test_multiple_endpoints(client, user, mock_arborist_requests, is_rbac_config
277277
data_2 = client.get(f"/ga4gh/drs/v1/objects/{res2_did}", headers=user)
278278
assert data_2.status_code == 401, f"Expected status code 401, got {data_2.status_code}"
279279

280+
print(f"DEBUG >>>>>> User should not have access to /ga4gh/dos/v1/dataobjects", file=sys.stderr)
281+
data_2 = client.get(f"/ga4gh/dos/v1/dataobjects", headers=user)
282+
assert data_2.status_code == 200, f"Expected status code 200, got {data_2.status_code}"
283+
data_all_list = data_2.json
284+
assert 'data_objects' in data_all_list, data_all_list
285+
assert len(data_all_list[
286+
"data_objects"]) == 0, f"Should have access to 0 records, got {len(data_all_list['data_objects'])} records: {data_all_list}"
287+
288+
print(f"DEBUG >>>>>> User should not have access to /ga4gh/dos/v1/dataobjects/{res2_did}", file=sys.stderr)
289+
data_2 = client.get(f"/ga4gh/dos/v1/dataobjects/{res2_did}", headers=user)
290+
assert data_2.status_code == 401, f"Expected status code 401, got {data_2.status_code}"
291+
292+
280293
# user has no access to anything
281294
mock_arborist_requests(
282295
resource_method_to_authorized={
@@ -293,3 +306,13 @@ def test_multiple_endpoints(client, user, mock_arborist_requests, is_rbac_config
293306
print("DEBUG >>>>>> User missing", file=sys.stderr)
294307
data_all_by_md = client.get("/ga4gh/drs/v1/objects")
295308
assert data_all_by_md.status_code == 403, f"Expected status code 403, got {data_all_by_md.status_code}"
309+
310+
311+
def test_indexclient(client, user, mock_arborist_requests, is_rbac_configured):
312+
"""
313+
Test multiple endpoints, ensure rbac.
314+
"""
315+
if not is_rbac_configured:
316+
pytest.skip("RBAC is not configured, skipping test.")
317+
318+
# TODO

0 commit comments

Comments
 (0)