-
Notifications
You must be signed in to change notification settings - Fork 5
feat: add ulims authz policy #310
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,139 @@ | ||||||||||||||||||||||||||||
| package diamond.policy.ulims | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # import data.diamond.data | ||||||||||||||||||||||||||||
| import data.diamond.policy.admin | ||||||||||||||||||||||||||||
| import data.diamond.policy.session | ||||||||||||||||||||||||||||
| import data.diamond.policy.token | ||||||||||||||||||||||||||||
| import rego.v1 | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # --- Start section copied from tiled.rego --- | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| subject := data.diamond.data.subjects[token.claims.fedid] | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # METADATA | ||||||||||||||||||||||||||||
| # title: Beamlines | ||||||||||||||||||||||||||||
| # description: | | ||||||||||||||||||||||||||||
| # Identifies all beamlines the subject is authorized to access | ||||||||||||||||||||||||||||
| # based on their assigned permissions. | ||||||||||||||||||||||||||||
| beamlines contains beamline if { | ||||||||||||||||||||||||||||
| token.claims.fedid | ||||||||||||||||||||||||||||
| not admin.is_admin(token.claims.fedid) | ||||||||||||||||||||||||||||
| some p in subject.permissions | ||||||||||||||||||||||||||||
| some beamline in object.get(data.diamond.data.admin, p, []) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Aggregates all session IDs the subject is authorized to view. | ||||||||||||||||||||||||||||
| # Admins receive a wildcard "*" granting access to all sessions. | ||||||||||||||||||||||||||||
| # Regular users gain session access through three pathways: | ||||||||||||||||||||||||||||
| # 1. Direct session membership | ||||||||||||||||||||||||||||
| # 2. Access via beamline-level permissions | ||||||||||||||||||||||||||||
| # 3. Access via proposal-level permissions | ||||||||||||||||||||||||||||
| user_sessions contains "*" if { | ||||||||||||||||||||||||||||
| subject | ||||||||||||||||||||||||||||
| admin.is_admin(token.claims.fedid) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| user_sessions contains format_int(session, 10) if { | ||||||||||||||||||||||||||||
| subject | ||||||||||||||||||||||||||||
| not admin.is_admin(token.claims.fedid) | ||||||||||||||||||||||||||||
| some session in subject.sessions | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| user_sessions contains format_int(session, 10) if { | ||||||||||||||||||||||||||||
| subject | ||||||||||||||||||||||||||||
| not admin.is_admin(token.claims.fedid) | ||||||||||||||||||||||||||||
| some beamline in beamlines | ||||||||||||||||||||||||||||
| some session in data.diamond.data.beamlines[beamline].sessions | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| user_sessions contains format_int(session, 10) if { | ||||||||||||||||||||||||||||
| subject | ||||||||||||||||||||||||||||
| not admin.is_admin(token.claims.fedid) | ||||||||||||||||||||||||||||
| some p in subject.proposals | ||||||||||||||||||||||||||||
| some i in data.diamond.data.proposals[format_int(p, 10)] | ||||||||||||||||||||||||||||
| some session in i | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # service account check | ||||||||||||||||||||||||||||
| user_sessions contains format_int(session, 10) if { | ||||||||||||||||||||||||||||
| not subject | ||||||||||||||||||||||||||||
| some session in data.diamond.data.beamlines[token.claims.beamline].sessions | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # --- End section copied from tiled.rego --- | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # METADATA | ||||||||||||||||||||||||||||
| # description: Allow verified tokens | ||||||||||||||||||||||||||||
| # entrypoint: true | ||||||||||||||||||||||||||||
| main := {"allow": allow} | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| default allow := false | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| allow if { | ||||||||||||||||||||||||||||
| token.verified[0] | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can move this to token.rego as valid_token True/False, looks like common policy to me. Do you make call to OPA to verify your token? |
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # METADATA | ||||||||||||||||||||||||||||
| # title: Session Restrictions | ||||||||||||||||||||||||||||
| # description: | | ||||||||||||||||||||||||||||
| # Return the instrument sessions the current user is allowed to see, or null if the user is an admin | ||||||||||||||||||||||||||||
| # Requires: | ||||||||||||||||||||||||||||
| # - `input.token`, a JWT | ||||||||||||||||||||||||||||
| # entrypoint: true | ||||||||||||||||||||||||||||
| default session_restrictions := [] | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| session_restrictions := null if { | ||||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I personally don't like the "null" restrictions, But I understand what you are trying to do here |
||||||||||||||||||||||||||||
| admin.is_admin(token.claims.fedid) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| session_restrictions := [data.diamond.data.sessions[session_id] | some session_id in user_sessions] if { | ||||||||||||||||||||||||||||
| not admin.is_admin(token.claims.fedid) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| session_restrictions := [data.diamond.data.sessions[session_id] | some session_id in user_sessions] if { | ||||||||||||||||||||||||||||
| not token.claims.fedid | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # METADATA | ||||||||||||||||||||||||||||
| # title: Filter sessions | ||||||||||||||||||||||||||||
| # description: | | ||||||||||||||||||||||||||||
| # Filter a provided list of instrument sessions, returning just those that the user has access to | ||||||||||||||||||||||||||||
| # Requires: | ||||||||||||||||||||||||||||
| # - `input.token`, a JWT | ||||||||||||||||||||||||||||
| # - `input.instrument_sessions`, an array representing a list of instrument sessions, [(proposal, visit), ...] | ||||||||||||||||||||||||||||
| # entrypoint: true | ||||||||||||||||||||||||||||
| filter_sessions contains session if { | ||||||||||||||||||||||||||||
| "*" in user_sessions | ||||||||||||||||||||||||||||
| some session in input.instrument_sessions | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| filter_sessions contains session if { | ||||||||||||||||||||||||||||
| some session in input.instrument_sessions | ||||||||||||||||||||||||||||
| proposal_number := format_int(session[0], 10) | ||||||||||||||||||||||||||||
| session_number := format_int(session[1], 10) | ||||||||||||||||||||||||||||
| format_int(data.diamond.data.proposals[proposal_number].sessions[session_number], 10) in user_sessions | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
Comment on lines
+110
to
+115
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # METADATA | ||||||||||||||||||||||||||||
| # title: Filter instruments | ||||||||||||||||||||||||||||
| # description: | | ||||||||||||||||||||||||||||
| # Filter a provided list of instruments, returning just those that the user has access to | ||||||||||||||||||||||||||||
| # Requires: | ||||||||||||||||||||||||||||
| # - `input.token`, a JWT | ||||||||||||||||||||||||||||
| # - `input.instruments`, an array of strings representing a list of instruments | ||||||||||||||||||||||||||||
| # entrypoint: true | ||||||||||||||||||||||||||||
| filter_instruments contains instrument if { | ||||||||||||||||||||||||||||
| some instrument in input.instruments | ||||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||||||||||||||||
| instrument in beamlines | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| filter_instruments contains instrument if { | ||||||||||||||||||||||||||||
| admin.is_admin(token.claims.fedid) | ||||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||||||||||||||||
| some instrument in input.instruments | ||||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this not check if the instrument is a valid instrument? If a admin type input.instrument = ["area-51-beamline"] it should return [] |
||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| filter_instruments contains instrument if { | ||||||||||||||||||||||||||||
| token.claims.beamline | ||||||||||||||||||||||||||||
| some instrument in input.instruments | ||||||||||||||||||||||||||||
| instrument == token.claims.beamline | ||||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here it should verify the beamline is valid |
||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,162 @@ | ||
| package diamond.policy.ulims_test | ||
|
|
||
| import data.diamond.policy.ulims | ||
| import rego.v1 | ||
|
|
||
| diamond_data := { | ||
| "subjects": { | ||
| "alice": { | ||
| "permissions": [], | ||
| "proposals": [1], | ||
| "sessions": [], | ||
| }, | ||
| "bob": { | ||
| "permissions": ["b07_admin"], | ||
| "proposals": [], | ||
| "sessions": [], | ||
| }, | ||
| "carol": { | ||
| "permissions": ["super_admin"], | ||
| "proposals": [], | ||
| "sessions": [], | ||
| }, | ||
| "desmond": { | ||
| "permissions": [], | ||
| "proposals": [2], | ||
| "sessions": [13], | ||
| }, | ||
| "edna": { | ||
| "permissions": [], | ||
| "proposals": [2], | ||
| "sessions": [13, 14], | ||
| }, | ||
| "oscar": { | ||
| "permissions": [], | ||
| "proposals": [], | ||
| "sessions": [], | ||
| }, | ||
| }, | ||
| "sessions": { | ||
| "11": { | ||
| "beamline": "i03", | ||
| "proposal_number": 1, | ||
| "visit_number": 1, | ||
| }, | ||
| "12": { | ||
| "beamline": "b07", | ||
| "proposal_number": 1, | ||
| "visit_number": 2, | ||
| }, | ||
| "13": { | ||
| "beamline": "b07", | ||
| "proposal_number": 2, | ||
| "visit_number": 1, | ||
| }, | ||
| "14": { | ||
| "beamline": "b07", | ||
| "proposal_number": 2, | ||
| "visit_number": 2, | ||
| }, | ||
| }, | ||
| "proposals": { | ||
| "1": {"sessions": { | ||
| "1": 11, | ||
| "2": 12, | ||
| }}, | ||
| "2": {"sessions": { | ||
| "1": 13, | ||
| "2": 14, | ||
| }}, | ||
| }, | ||
| "beamlines": {"i03": {"sessions": [11]}, "b07": {"sessions": [12, 13, 14]}}, | ||
| "admin": {"b07_admin": ["b07"]}, | ||
| } | ||
|
|
||
| test_session_restrictions_for_admin if { | ||
| ulims.session_restrictions == null with data.diamond.data as diamond_data | ||
| with data.diamond.policy.token as {"claims": {"fedid": "carol"}} | ||
| } | ||
|
|
||
| test_session_restrictions_for_non_admin_1 if { | ||
| ulims.session_restrictions == [ | ||
| { | ||
| "beamline": "i03", | ||
| "proposal_number": 1, | ||
| "visit_number": 1, | ||
| }, | ||
| { | ||
| "beamline": "b07", | ||
| "proposal_number": 1, | ||
| "visit_number": 2, | ||
| }, | ||
| ] with data.diamond.data as diamond_data | ||
| with data.diamond.policy.token as {"claims": {"fedid": "alice"}} | ||
| } | ||
|
|
||
| test_session_restrictions_for_non_admin_2 if { | ||
| ulims.session_restrictions == [] with data.diamond.data as diamond_data | ||
| with data.diamond.policy.token as {"claims": {"fedid": "oscar"}} | ||
| } | ||
|
|
||
| test_session_restrictions_service_account if { | ||
| ulims.session_restrictions == [{ | ||
| "beamline": "i03", | ||
| "proposal_number": 1, | ||
| "visit_number": 1, | ||
| }] with data.diamond.data as diamond_data | ||
| with data.diamond.policy.token.claims as {"beamline": "i03"} | ||
| } | ||
|
|
||
| test_filter_sessions_for_admin if { | ||
| ulims.filter_sessions == {[1, 1], [1, 2], [2, 1], [2, 2]} with data.diamond.data as diamond_data | ||
| with input.instrument_sessions as [[1, 1], [1, 2], [2, 1], [2, 2]] | ||
| with data.diamond.policy.token as {"claims": {"fedid": "carol"}} | ||
| } | ||
|
|
||
| test_filter_sessions_beamline_admin if { | ||
| ulims.filter_sessions == {[1, 2], [2, 1], [2, 2]} with data.diamond.data as diamond_data | ||
| with input.instrument_sessions as [[1, 1], [1, 2], [2, 1], [2, 2]] | ||
| with data.diamond.policy.token as {"claims": {"fedid": "bob"}} | ||
| } | ||
|
|
||
| test_filter_sessions_for_non_admin_1 if { | ||
| ulims.filter_sessions == {[1, 1], [1, 2]} with data.diamond.data as diamond_data | ||
| with input.instrument_sessions as [[1, 1], [1, 2], [2, 1], [2, 2]] | ||
| with data.diamond.policy.token as {"claims": {"fedid": "alice"}} | ||
| } | ||
|
|
||
| test_filter_sessions_for_non_admin_2 if { | ||
| ulims.filter_sessions == set() with data.diamond.data as diamond_data | ||
| with input.instrument_sessions as [[1, 1], [1, 2], [2, 1], [2, 2]] | ||
| with data.diamond.policy.token as {"claims": {"fedid": "oscar"}} | ||
| } | ||
|
|
||
| test_filter_sessions_service_account if { | ||
| ulims.filter_sessions == {[1, 1]} with data.diamond.data as diamond_data | ||
| with input.instrument_sessions as [[1, 1], [1, 2], [2, 1], [2, 2]] | ||
| with data.diamond.policy.token as {"claims": {"beamline": "i03"}} | ||
| } | ||
|
|
||
| test_filter_instruments_user if { | ||
| ulims.filter_instruments == set() with data.diamond.data as diamond_data | ||
| with input.instruments as ["i03", "b07"] | ||
| with data.diamond.policy.token as {"claims": {"fedid": "alice"}} | ||
| } | ||
|
|
||
| test_filter_instruments_beamline_admin if { | ||
| ulims.filter_instruments == {"b07"} with data.diamond.data as diamond_data | ||
| with input.instruments as ["i03", "b07"] | ||
| with data.diamond.policy.token as {"claims": {"fedid": "bob"}} | ||
| } | ||
|
|
||
| test_filter_instruments_super_admin if { | ||
| ulims.filter_instruments == {"i03", "b07"} with data.diamond.data as diamond_data | ||
| with input.instruments as ["i03", "b07"] | ||
| with data.diamond.policy.token as {"claims": {"fedid": "carol"}} | ||
| } | ||
|
|
||
| test_filter_instruments_service_account if { | ||
| ulims.filter_instruments == {"i03"} with data.diamond.data as diamond_data | ||
| with input.instruments as ["i03", "b07"] | ||
| with data.diamond.policy.token as {"claims": {"beamline": "i03"}} | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should move this to session because it looks like a common thing rather than application specific.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
beamlinesas well, or is that better placed in a separate file?