Skip to content
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

Beamline policy rules #182

Merged
merged 1 commit into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions policy/diamond/policy/admin/admin.rego
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package diamond.policy.admin

import data.diamond.policy.token
import rego.v1

is_admin(subject) if {
"super_admin" in data.diamond.data.subjects[subject].permissions # regal ignore:external-reference
}
is_admin[subject] := "super_admin" in data.diamond.data.subjects[subject].permissions

is_beamline_admin(subject, beamline) if {
some admin in data.diamond.data.subjects[subject].permissions
beamline in data.diamond.data.admin[admin] # regal ignore:external-reference
beamline_admin_for_subject[subject] contains beamline if {
some subject
some role in data.diamond.data.subjects[subject].permissions
some beamline in data.diamond.data.admin[role]
}

admin := is_admin[token.claims.fedid] # regal ignore:rule-name-repeats-package

beamline_admin := input.beamline in object.get(beamline_admin_for_subject, token.claims.fedid, [])
93 changes: 79 additions & 14 deletions policy/diamond/policy/admin/admin_test.rego
Original file line number Diff line number Diff line change
Expand Up @@ -32,30 +32,95 @@ diamond_data := {
"admin": {"b07_admin": ["b07"], "group_admin": ["b07", "i07"]},
}

test_super_admin_subject if {
admin.is_admin("carol") with data.diamond.data as diamond_data
test_is_admin_for_admin if {
admin.is_admin.carol with data.diamond.data as diamond_data
}

test_beamline_admin_subject_beamline if {
admin.is_beamline_admin("bob", "b07") with data.diamond.data as diamond_data
test_beamline_admin_for_subject_for_beamline_admin if {
admin.beamline_admin_for_subject.bob == {"b07"} with data.diamond.data as diamond_data
}

test_group_admin_subject_beamline if {
admin.is_beamline_admin("oscar", "b07") with data.diamond.data as diamond_data
test_beamlines_admin_for_subject_for_group_admin if {
admin.beamline_admin_for_subject.oscar == {"b07", "i07"} with data.diamond.data as diamond_data
}

test_non_admin if {
not admin.is_admin("alice") with data.diamond.data as diamond_data
test_is_admin_for_non_admin if {
not admin.is_admin.alice with data.diamond.data as diamond_data
}

test_beamline_admin_not_admin if {
not admin.is_admin("bob") with data.diamond.data as diamond_data
test_is_admin_for_beamline_admin_not_admin if {
not admin.is_admin.bob with data.diamond.data as diamond_data
}

test_non_beamline_admin if {
not admin.is_beamline_admin("alice", "b07") with data.diamond.data as diamond_data
test_beamline_admin_for_subject_for_non_beamline_admin if {
not "alice" in admin.beamline_admin_for_subject with data.diamond.data as diamond_data
}

test_super_admin_not_beamline_admin if {
not admin.is_beamline_admin("carol", "b07") with data.diamond.data as diamond_data
test_beamline_admin_for_subject_for_admin if {
not "carol" in admin.beamline_admin_for_subject with data.diamond.data as diamond_data
}

test_admin_rule_for_admin if {
admin.admin with data.diamond.policy.token.claims as {"fedid": "carol"}
with data.diamond.data as diamond_data
}

test_admin_rule_for_non_admin if {
not admin.admin with data.diamond.policy.token.claims as {"fedid": "bob"}
with data.diamond.data as diamond_data
}

# If no user is passed as input, the rule should be undefined
test_admin_rule_for_no_user := false if {
local_admin := admin.admin with data.diamond.policy.token.claims as {}
with data.diamond.data as diamond_data
}

else := true # regal ignore:default-over-else

test_beamline_admin_rule_for_beamline_admin if {
admin.beamline_admin with input as {"beamline": "b07"}
with data.diamond.policy.token.claims as {"fedid": "bob"}
with data.diamond.data as diamond_data
}

# super_admin can access anything but they still aren't automatically beamline admins
test_beamline_admin_rule_for_super_admin if {
not admin.beamline_admin with input as {"beamline": "b07"}
with data.diamond.policy.token.claims as {"fedid": "carol"}
with data.diamond.data as diamond_data
}

test_beamline_admin_rule_for_non_beamline_admin if {
not admin.beamline_admin with input as {"beamline": "b07"}
with data.diamond.policy.token.claims as {"fedid": "alice"}
with data.diamond.data as diamond_data
}

test_beamline_admin_rule_for_wrong_beamline_admin if {
# bob is only beamline admin for b07
not admin.beamline_admin with input as {"beamline": "i07"}
with data.diamond.policy.token.claims as {"fedid": "bob"}
with data.diamond.data as diamond_data
}

test_beamline_admin_rule_for_no_user := false if {
local_admin := admin.beamline_admin with input as {"beamline": "i07"}
with data.diamond.data as diamond_data
}

else := true # regal ignore:default-over-else

test_beamline_admin_rule_for_no_beamline := false if {
local_admin := admin.beamline_admin with data.diamond.policy.token.claims as {"fedid": "bob"}
with data.diamond.data as diamond_data
}

else := true # regal ignore:default-over-else

test_beamline_admin_rule_for_no_input := false if {
local_admin := admin.beamline_admin with input as {}
with data.diamond.data as diamond_data
}

else := true # regal ignore:default-over-else
11 changes: 10 additions & 1 deletion policy/diamond/policy/proposal/proposal.rego
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
package diamond.policy.proposal

import data.diamond.policy.admin
import data.diamond.policy.token
import rego.v1

default on_proposal(_, _) := false

on_proposal(subject, proposal_number) if {
proposal_number in data.diamond.data.subjects[subject].proposals # regal ignore:external-reference
}

default access_proposal(_, _) := false

# Allow if subject has super_admin permission
access_proposal(subject, proposal_number) if admin.is_admin(subject)
access_proposal(subject, proposal_number) if admin.is_admin[subject] # regal ignore:external-reference

# Allow if subject is on proposal
access_proposal(subject, proposal_number) if on_proposal(subject, proposal_number)

access := access_proposal(token.claims.fedid, input.proposal)

named_user := on_proposal(token.claims.fedid, input.proposal)
58 changes: 58 additions & 0 deletions policy/diamond/policy/proposal/proposal_test.rego
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,61 @@ test_member_on_proposal if {
test_admin_not_on_proposal if {
not proposal.on_proposal("carol", 1) with data.diamond.data as diamond_data
}

test_named_user_rule_for_named_user if {
proposal.named_user with input as {"proposal": 1}
with data.diamond.policy.token.claims as {"fedid": "alice"}
with data.diamond.data as diamond_data
}

test_named_user_rule_for_unnamed_user if {
not proposal.named_user with input as {"proposal": 1}
with data.diamond.policy.token.claims as {"fedid": "carol"}
with data.diamond.data as diamond_data
}

test_named_user_rule_for_no_user := false if {
named := proposal.named_user with input as {"proposal": 1}
with data.diamond.data as diamond_data
}

else := true # regal ignore:default-over-else

test_named_user_rule_for_no_proposal := false if {
named := proposal.named_user with data.diamond.policy.token.claims as {"fedid": "carol"}
with data.diamond.data as diamond_data
}

else := true # regal ignore:default-over-else

test_access_rule_for_super_admin if {
proposal.access with input as {"proposal": 1}
with data.diamond.policy.token.claims as {"fedid": "carol"}
with data.diamond.data as diamond_data
}

test_access_rule_for_named_user if {
proposal.access with input as {"proposal": 1}
with data.diamond.policy.token.claims as {"fedid": "alice"}
with data.diamond.data as diamond_data
}

test_access_rule_for_unnamed_user if {
not proposal.access with input as {"proposal": 1}
with data.diamond.policy.token.claims as {"fedid": "oscar"}
with data.diamond.data as diamond_data
}

test_access_rule_for_no_user := false if {
access := proposal.access with input as {"proposal": 1}
with data.diamond.data as diamond_data
}

else := true # regal ignore:default-over-else

test_access_rule_for_no_proposal := false if {
access := proposal.access with data.diamond.policy.token.claims as {"fedid": "alice"}
with data.diamond.data as diamond_data
}

else := true # regal ignore:default-over-else
22 changes: 19 additions & 3 deletions policy/diamond/policy/session/session.rego
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,48 @@ package diamond.policy.session

import data.diamond.policy.admin
import data.diamond.policy.proposal
import data.diamond.policy.token
import rego.v1

beamline(proposal_number, visit_number) := beamline if {
beamline_for(proposal_number, visit_number) := beamline if {
proposal := data.diamond.data.proposals[format_int(proposal_number, 10)] # regal ignore:external-reference
session_id := proposal.sessions[format_int(visit_number, 10)]
session := data.diamond.data.sessions[format_int(session_id, 10)] # regal ignore:external-reference
beamline := session.beamline
}

default on_session(_, _, _) := false

on_session(subject, proposal_number, visit_number) if {
some session_id in data.diamond.data.subjects[subject].sessions # regal ignore:external-reference
subject_session := data.diamond.data.sessions[format_int(session_id, 10)] # regal ignore:external-reference
subject_session.proposal_number == proposal_number
subject_session.visit_number == visit_number
}

default access_session(_, _, _) := false

# Allow if subject has super_admin permission
access_session(subject, proposal_number, visit_number) if admin.is_admin(subject)
access_session(subject, proposal_number, visit_number) if admin.is_admin[subject] # regal ignore:external-reference

# Allow if subject is admin for beamline containing session
access_session(subject, proposal_number, visit_number) if {
admin.is_beamline_admin(subject, beamline(proposal_number, visit_number))
# regal ignore:external-reference
beamline_for(proposal_number, visit_number) in admin.beamline_admin_for_subject[subject]
}

# Allow if subject on proposal which contains session
access_session(subject, proposal_number, visit_number) if proposal.on_proposal(subject, proposal_number)

# Allow if subject directly on session
access_session(subject, proposal_number, visit_number) if on_session(subject, proposal_number, visit_number)

# Rules depending on input data

access := access_session(token.claims.fedid, input.proposal, input.visit)

named_user := on_session(token.claims.fedid, input.proposal, input.visit)

matches_beamline := input.beamline == beamline_for(input.proposal, input.visit) # regal ignore:boolean-assignment

beamline := beamline_for(input.proposal, input.visit)
112 changes: 112 additions & 0 deletions policy/diamond/policy/session/session_test.rego
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,115 @@ test_non_member_denied if {
test_admin_not_on_session if {
not session.on_session("carol", 1, 1) with data.diamond.data as diamond_data
}

test_access_rule_for_named_user if {
session.access with input as {"proposal": 1, "visit": 1}
with data.diamond.policy.token.claims as {"fedid": "alice"}
with data.diamond.data as diamond_data
}

test_access_rule_for_beamline_admin if {
session.access with input as {"proposal": 1, "visit": 2}
with data.diamond.policy.token.claims as {"fedid": "bob"}
with data.diamond.data as diamond_data
}

test_access_rule_for_super_admin if {
session.access with input as {"proposal": 1, "visit": 2}
with data.diamond.policy.token.claims as {"fedid": "carol"}
with data.diamond.data as diamond_data
}

test_access_rule_for_non_user if {
not session.access with input as {"proposal": 1, "visit": 1}
with data.diamond.policy.token.claims as {"fedid": "oscar"}
with data.diamond.data as diamond_data
}

test_access_rule_for_no_user := false if {
access := session.access with input as {"proposal": 1, "visit": 2}
with data.diamond.data as diamond_data
}

else := true # regal ignore:default-over-else

test_access_rule_for_no_proposal := false if {
access := session.access with input as {"visit": 2}
with data.diamond.policy.token.claims as {"fedid": "bob"}
with data.diamond.data as diamond_data
}

else := true # regal ignore:default-over-else

test_access_rule_for_no_visit := false if {
access := session.access with input as {"proposal": 2}
with data.diamond.policy.token.claims as {"fedid": "bob"}
with data.diamond.data as diamond_data
}

else := true # regal ignore:default-over-else

test_named_user_rule_for_named_user if {
session.named_user with input as {"proposal": 1, "visit": 1}
with data.diamond.policy.token.claims as {"fedid": "bob"}
with data.diamond.data as diamond_data
}

test_named_user_rule_for_unnamed_user if {
not session.named_user with input as {"proposal": 1, "visit": 1}
with data.diamond.policy.token.claims as {"fedid": "oscar"}
with data.diamond.data as diamond_data
}

test_named_user_rule_for_super_admin if {
not session.named_user with input as {"proposal": 1, "visit": 1}
with data.diamond.policy.token.claims as {"fedid": "alice"}
with data.diamond.data as diamond_data
}

test_named_user_rule_for_beamline_admin if {
not session.named_user with input as {"proposal": 1, "visit": 2}
with data.diamond.policy.token.claims as {"fedid": "bob"}
with data.diamond.data as diamond_data
}

test_named_user_rule_for_named_proposal if {
# Users on the proposal can access the session but aren't named on it
not session.named_user with input as {"proposal": 1, "visit": 2}
with data.diamond.policy.token.claims as {"fedid": "alice"}
with data.diamond.data as diamond_data
}

test_matches_beamline_rule_for_match if {
session.matches_beamline with input as {"beamline": "b07", "proposal": 1, "visit": 2}
with data.diamond.data as diamond_data
}

test_matches_beamline_rule_for_non_match if {
not session.matches_beamline with input as {"beamline": "b07", "proposal": 1, "visit": 1}
with data.diamond.data as diamond_data
}

test_matches_beamline_rule_for_no_beamline := false if {
match := session.matches_beamline with input as {"proposal": 1, "visit": 1}
with data.diamond.data as diamond_data
}

else := true # regal ignore:default-over-else

test_matches_beamline_rule_for_no_visit := false if {
match := session.matches_beamline with input as {"beamline": "b07"}
with data.diamond.data as diamond_data
}

else := true # regal ignore:default-over-else

test_session_beamline if {
bl1 := session.beamline with input as {"proposal": 1, "visit": 1}
with data.diamond.data as diamond_data
bl2 := session.beamline with input as {"proposal": 1, "visit": 2}
with data.diamond.data as diamond_data

bl1 == "i03"
bl2 == "b07"
}
Loading