From b5515c8b17f953fd07298cee0d1da6f9a3d32823 Mon Sep 17 00:00:00 2001 From: Matthew Pritchard <46708056+MattPrit@users.noreply.github.com> Date: Tue, 26 May 2026 15:23:06 +0100 Subject: [PATCH 1/4] feat: add ulims authz policy --- policy/diamond/policy/ulims/ulims.rego | 115 +++++++++++++++++ policy/diamond/policy/ulims/ulims_test.rego | 134 ++++++++++++++++++++ 2 files changed, 249 insertions(+) create mode 100644 policy/diamond/policy/ulims/ulims.rego create mode 100644 policy/diamond/policy/ulims/ulims_test.rego diff --git a/policy/diamond/policy/ulims/ulims.rego b/policy/diamond/policy/ulims/ulims.rego new file mode 100644 index 0000000..4c9f909 --- /dev/null +++ b/policy/diamond/policy/ulims/ulims.rego @@ -0,0 +1,115 @@ +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] +} + +# 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 { + 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 v if { + "*" in user_sessions + some v in input.instrument_sessions +} + +filter_sessions contains v if { + some v in input.instrument_sessions + proposal_number := format_int(v[0], 10) + session_number := format_int(v[1], 10) + format_int(data.diamond.data.proposals[proposal_number].sessions[session_number], 10) in user_sessions +} diff --git a/policy/diamond/policy/ulims/ulims_test.rego b/policy/diamond/policy/ulims/ulims_test.rego new file mode 100644 index 0000000..1c8b9a7 --- /dev/null +++ b/policy/diamond/policy/ulims/ulims_test.rego @@ -0,0 +1,134 @@ +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 data.diamond.policy.token as {"claims": {"fedid": "carol"}} + with input.instrument_sessions as [[1, 1], [1, 2], [2, 1], [2, 2]] +} + +test_filter_sessions_beamline_admin if { + ulims.filter_sessions == {[1, 2], [2, 1], [2, 2]} with data.diamond.data as diamond_data + with data.diamond.policy.token as {"claims": {"fedid": "bob"}} + with input.instrument_sessions as [[1, 1], [1, 2], [2, 1], [2, 2]] +} + +test_filter_sessions_for_non_admin_1 if { + ulims.filter_sessions == {[1, 1], [1, 2]} with data.diamond.data as diamond_data + with data.diamond.policy.token as {"claims": {"fedid": "alice"}} + with input.instrument_sessions as [[1, 1], [1, 2], [2, 1], [2, 2]] +} + +test_filter_sessions_for_non_admin_2 if { + ulims.filter_sessions == set() with data.diamond.data as diamond_data + with data.diamond.policy.token as {"claims": {"fedid": "oscar"}} + with input.instrument_sessions as [[1, 1], [1, 2], [2, 1], [2, 2]] +} + +test_filter_sessions_service_account if { + ulims.filter_sessions == {[1, 1]} with data.diamond.data as diamond_data + with data.diamond.policy.token as {"claims": {"beamline": "i03"}} + with input.instrument_sessions as [[1, 1], [1, 2], [2, 1], [2, 2]] +} From 2afbdb17c6437c0d13bf429c274510b70367bfb7 Mon Sep 17 00:00:00 2001 From: Matthew Pritchard <46708056+MattPrit@users.noreply.github.com> Date: Tue, 26 May 2026 15:43:23 +0100 Subject: [PATCH 2/4] fix: ulims lint errors --- policy/diamond/policy/ulims/ulims_test.rego | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/policy/diamond/policy/ulims/ulims_test.rego b/policy/diamond/policy/ulims/ulims_test.rego index 1c8b9a7..dba615d 100644 --- a/policy/diamond/policy/ulims/ulims_test.rego +++ b/policy/diamond/policy/ulims/ulims_test.rego @@ -1,4 +1,4 @@ -package diamond.policy.ulims.test +package diamond.policy.ulims_test import data.diamond.policy.ulims import rego.v1 @@ -99,7 +99,11 @@ test_session_restrictions_for_non_admin_2 if { } test_session_restrictions_service_account if { - ulims.session_restrictions == [{"beamline": "i03", "proposal_number": 1, "visit_number": 1}] with data.diamond.data as diamond_data + 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"} } From 6e60748074cd922c198f89290a0efdebbc7d0ac0 Mon Sep 17 00:00:00 2001 From: Matthew Pritchard <46708056+MattPrit@users.noreply.github.com> Date: Wed, 27 May 2026 11:35:22 +0100 Subject: [PATCH 3/4] feat: add ulims.filter_instruments rule --- policy/diamond/policy/ulims/ulims.rego | 36 +++++++++++++++++---- policy/diamond/policy/ulims/ulims_test.rego | 34 ++++++++++++++++--- 2 files changed, 59 insertions(+), 11 deletions(-) diff --git a/policy/diamond/policy/ulims/ulims.rego b/policy/diamond/policy/ulims/ulims.rego index 4c9f909..6b7f23d 100644 --- a/policy/diamond/policy/ulims/ulims.rego +++ b/policy/diamond/policy/ulims/ulims.rego @@ -102,14 +102,38 @@ session_restrictions := [data.diamond.data.sessions[session_id] | some session_i # - `input.token`, a JWT # - `input.instrument_sessions`, an array representing a list of instrument sessions, [(proposal, visit), ...] # entrypoint: true -filter_sessions contains v if { +filter_sessions contains session if { "*" in user_sessions - some v in input.instrument_sessions + some session in input.instrument_sessions } -filter_sessions contains v if { - some v in input.instrument_sessions - proposal_number := format_int(v[0], 10) - session_number := format_int(v[1], 10) +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 } + +# 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 + instrument in beamlines +} + +filter_instruments contains instrument if { + admin.is_admin(token.claims.fedid) + some instrument in input.instruments +} + +filter_instruments contains instrument if { + token.claims.beamline + some instrument in input.instruments + instrument == token.claims.beamline +} diff --git a/policy/diamond/policy/ulims/ulims_test.rego b/policy/diamond/policy/ulims/ulims_test.rego index dba615d..d5ec3e8 100644 --- a/policy/diamond/policy/ulims/ulims_test.rego +++ b/policy/diamond/policy/ulims/ulims_test.rego @@ -109,30 +109,54 @@ test_session_restrictions_service_account if { 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 data.diamond.policy.token as {"claims": {"fedid": "carol"}} 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 data.diamond.policy.token as {"claims": {"fedid": "bob"}} 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 data.diamond.policy.token as {"claims": {"fedid": "alice"}} 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 data.diamond.policy.token as {"claims": {"fedid": "oscar"}} 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 data.diamond.policy.token as {"claims": {"beamline": "i03"}} 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"}} } From fd6feeb7019ff9028f1f02677ae18157edf3b427 Mon Sep 17 00:00:00 2001 From: Matthew Pritchard <46708056+MattPrit@users.noreply.github.com> Date: Tue, 2 Jun 2026 14:47:31 +0100 Subject: [PATCH 4/4] apply suggestions from pr --- policy/diamond/policy/beamline/beamline.rego | 29 +++++ .../policy/beamline/beamline_test.rego | 98 +++++++++++++++ policy/diamond/policy/session/session.rego | 50 ++++++++ .../diamond/policy/session/session_test.rego | 55 ++++++++- policy/diamond/policy/token/token.rego | 13 ++ policy/diamond/policy/ulims/ulims.rego | 112 ++++-------------- policy/diamond/policy/ulims/ulims_test.rego | 12 ++ 7 files changed, 272 insertions(+), 97 deletions(-) create mode 100644 policy/diamond/policy/beamline/beamline.rego create mode 100644 policy/diamond/policy/beamline/beamline_test.rego diff --git a/policy/diamond/policy/beamline/beamline.rego b/policy/diamond/policy/beamline/beamline.rego new file mode 100644 index 0000000..c9c8bec --- /dev/null +++ b/policy/diamond/policy/beamline/beamline.rego @@ -0,0 +1,29 @@ +package diamond.policy.beamline + +import data.diamond.policy.admin +import data.diamond.policy.token +import rego.v1 + +subject := data.diamond.data.subjects[token.claims.fedid] + +# METADATA +# title: User Beamlines +# description: | +# Identifies all beamlines the subject is authorized to access +# based on their assigned permissions. +# entrypoint: true +user_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, []) +} + +user_beamlines contains beamline if { + admin.is_admin(token.claims.fedid) + some beamline in object.keys(data.diamond.data.beamlines) +} + +user_beamlines contains token.claims.beamline if { + token.claims.beamline in object.keys(data.diamond.data.beamlines) +} diff --git a/policy/diamond/policy/beamline/beamline_test.rego b/policy/diamond/policy/beamline/beamline_test.rego new file mode 100644 index 0000000..78cdc2e --- /dev/null +++ b/policy/diamond/policy/beamline/beamline_test.rego @@ -0,0 +1,98 @@ +package diamond.policy.beamline_test + +import data.diamond.policy.beamline +import rego.v1 + +diamond_data := { + "subjects": { + "alice": { + "permissions": [], + "proposals": [1], + "sessions": [], + }, + "bob": { + "permissions": ["b07_admin"], + "proposals": [], + "sessions": [11], + }, + "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_user_beamlines_super_admin if { + beamline.user_beamlines == {"i03", "b07"} with data.diamond.policy.token.claims as {"fedid": "carol"} + with data.diamond.data as diamond_data +} + +test_user_beamlines_beamline_admin if { + beamline.user_beamlines == {"b07"} with data.diamond.policy.token.claims as {"fedid": "bob"} + with data.diamond.data as diamond_data +} + +test_user_beamlines_non_admin if { + beamline.user_beamlines == set() with data.diamond.policy.token.claims as {"fedid": "alice"} + with data.diamond.data as diamond_data +} + +test_user_beamlines_service_account if { + beamline.user_beamlines == {"b07"} with data.diamond.policy.token.claims as {"beamline": "b07"} + with data.diamond.data as diamond_data +} + +test_user_beamlines_service_account_bad_beamline_claim if { + beamline.user_beamlines == set() with data.diamond.policy.token.claims as {"beamline": "area-51-beamline"} + with data.diamond.data as diamond_data +} diff --git a/policy/diamond/policy/session/session.rego b/policy/diamond/policy/session/session.rego index b3a878f..674a525 100644 --- a/policy/diamond/policy/session/session.rego +++ b/policy/diamond/policy/session/session.rego @@ -1,6 +1,7 @@ package diamond.policy.session import data.diamond.policy.admin +import data.diamond.policy.beamline as beamline_policy import data.diamond.policy.proposal import data.diamond.policy.token import rego.v1 @@ -52,3 +53,52 @@ write_to_beamline_visit if { access input.beamline == beamline } + +subject := data.diamond.data.subjects[token.claims.fedid] + +# METADATA +# title: User Sessions +# description: | +# 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 +# entrypoint: false +# scope: document +user_sessions contains "*" if { + subject + admin.is_admin(token.claims.fedid) +} + +# Direct session membership +user_sessions contains format_int(session, 10) if { + subject + not admin.is_admin(token.claims.fedid) + some session in subject.sessions +} + +# Access via beamline permissions +user_sessions contains format_int(session, 10) if { + subject + not admin.is_admin(token.claims.fedid) + some _beamline in beamline_policy.user_beamlines + some session in data.diamond.data.beamlines[_beamline].sessions +} + +# Access via beamline permissions (service accounts) +user_sessions contains format_int(session, 10) if { + not subject + some _beamline in beamline_policy.user_beamlines + some session in data.diamond.data.beamlines[_beamline].sessions +} + +# Access via proposal permissions +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 +} diff --git a/policy/diamond/policy/session/session_test.rego b/policy/diamond/policy/session/session_test.rego index 2762432..a13ac94 100644 --- a/policy/diamond/policy/session/session_test.rego +++ b/policy/diamond/policy/session/session_test.rego @@ -20,6 +20,16 @@ diamond_data := { "proposals": [], "sessions": [], }, + "desmond": { + "permissions": [], + "proposals": [2], + "sessions": [13], + }, + "edna": { + "permissions": [], + "proposals": [2], + "sessions": [13, 14], + }, "oscar": { "permissions": [], "proposals": [], @@ -37,12 +47,28 @@ diamond_data := { "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, + }}, }, - "proposals": {"1": {"sessions": { - "1": 11, - "2": 12, - }}}, - "beamlines": {"i03": {"sessions": [11]}, "b07": {"sessions": [12]}}, + "beamlines": {"i03": {"sessions": [11]}, "b07": {"sessions": [12, 13, 14]}}, "admin": {"b07_admin": ["b07"]}, } @@ -175,3 +201,22 @@ test_session_beamline if { with data.diamond.data as diamond_data bl2 == "b07" } + +test_user_sessions if { + session.user_sessions == set() with data.diamond.data as diamond_data + with data.diamond.policy.token.claims as {"fedid": "oscar"} + session.user_sessions == {"11", "12"} with data.diamond.data as diamond_data + with data.diamond.policy.token.claims as {"fedid": "alice"} + session.user_sessions == {"11", "12", "13", "14"} with data.diamond.data as diamond_data + with data.diamond.policy.token.claims as {"fedid": "bob"} + session.user_sessions == {"*"} with data.diamond.data as diamond_data + with data.diamond.policy.token.claims as {"fedid": "carol"} + session.user_sessions == {"13", "14"} with data.diamond.data as diamond_data + with data.diamond.policy.token.claims as {"fedid": "desmond"} + session.user_sessions == {"13", "14"} with data.diamond.data as diamond_data + with data.diamond.policy.token.claims as {"fedid": "edna"} + session.user_sessions == {"11"} with data.diamond.data as diamond_data + with data.diamond.policy.token.claims as {"beamline": "i03"} + session.user_sessions == set() with data.diamond.data as diamond_data + with data.diamond.policy.token.claims as {"beamline": "area-51-beamline"} +} diff --git a/policy/diamond/policy/token/token.rego b/policy/diamond/policy/token/token.rego index b4826a5..de99528 100644 --- a/policy/diamond/policy/token/token.rego +++ b/policy/diamond/policy/token/token.rego @@ -35,4 +35,17 @@ verified := io.jwt.decode_verify(input.token, { "aud": input.audience, }) +# METADATA +# title: Valid Token +# description: | +# Returns whether or not input.token is a valid JWT for our identity provider +# Requires: +# - `input.token`, a JWT +# entrypoint: true +default valid_token := false + +valid_token if { + verified[0] +} + claims := verified[2] if verified[0] diff --git a/policy/diamond/policy/ulims/ulims.rego b/policy/diamond/policy/ulims/ulims.rego index 6b7f23d..105be86 100644 --- a/policy/diamond/policy/ulims/ulims.rego +++ b/policy/diamond/policy/ulims/ulims.rego @@ -1,78 +1,11 @@ package diamond.policy.ulims -# import data.diamond.data import data.diamond.policy.admin +import data.diamond.policy.beamline 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] -} - # METADATA # title: Session Restrictions # description: | @@ -86,11 +19,11 @@ session_restrictions := null if { admin.is_admin(token.claims.fedid) } -session_restrictions := [data.diamond.data.sessions[session_id] | some session_id in user_sessions] if { +session_restrictions := [data.diamond.data.sessions[session_id] | some session_id in session.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 { +session_restrictions := [data.diamond.data.sessions[session_id] | some session_id in session.user_sessions] if { not token.claims.fedid } @@ -102,16 +35,21 @@ session_restrictions := [data.diamond.data.sessions[session_id] | some session_i # - `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 { + "*" in session.user_sessions + some _session in input.instrument_sessions + proposal_number := format_int(_session[0], 10) + proposal_number in object.keys(data.diamond.data.proposals) + session_number := format_int(_session[1], 10) + session_number in object.keys(data.diamond.data.proposals[proposal_number].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 +filter_sessions contains _session if { + not "*" in session.user_sessions + 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 session.user_sessions } # METADATA @@ -122,18 +60,8 @@ filter_sessions contains session if { # - `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 - instrument in beamlines -} - -filter_instruments contains instrument if { - admin.is_admin(token.claims.fedid) - some instrument in input.instruments -} - -filter_instruments contains instrument if { - token.claims.beamline - some instrument in input.instruments - instrument == token.claims.beamline +filter_instruments contains _beamline if { + some _beamline in input.instruments + _beamline in object.keys(data.diamond.data.beamlines) + _beamline in beamline.user_beamlines } diff --git a/policy/diamond/policy/ulims/ulims_test.rego b/policy/diamond/policy/ulims/ulims_test.rego index d5ec3e8..ba965d4 100644 --- a/policy/diamond/policy/ulims/ulims_test.rego +++ b/policy/diamond/policy/ulims/ulims_test.rego @@ -137,6 +137,12 @@ test_filter_sessions_service_account if { with data.diamond.policy.token as {"claims": {"beamline": "i03"}} } +test_filter_sessions_non_existent_session if { + ulims.filter_sessions == set() with data.diamond.data as diamond_data + with input.instrument_sessions as [[999, 999]] + with data.diamond.policy.token as {"claims": {"fedid": "carol"}} +} + test_filter_instruments_user if { ulims.filter_instruments == set() with data.diamond.data as diamond_data with input.instruments as ["i03", "b07"] @@ -160,3 +166,9 @@ test_filter_instruments_service_account if { with input.instruments as ["i03", "b07"] with data.diamond.policy.token as {"claims": {"beamline": "i03"}} } + +test_filter_instruments_non_existent_instrument if { + ulims.filter_instruments == set() with data.diamond.data as diamond_data + with input.instruments as ["area-51-beamline"] + with data.diamond.policy.token as {"claims": {"fedid": "carol"}} +}