Skip to content
Open
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
111 changes: 92 additions & 19 deletions policy/diamond/policy/tiled/tiled.rego
Original file line number Diff line number Diff line change
@@ -1,44 +1,117 @@
package diamond.policy.tiled

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

read_scopes := {
# Assign read & write scopes to clients with tiled-writer audience
# defaults to read-only scopes
default scopes := {
"read:metadata",
"read:data",
}

write_scopes := {
scopes := {
"read:metadata",
"read:data",
"write:metadata",
"write:data",
"create:node",
"register",
} if {
"tiled-writer" in token.claims.aud
}

_session := data.diamond.data.proposals[format_int(input.proposal, 10)].sessions[format_int(input.visit, 10)]

# Returns the session ID if the subject has write permissions for the
# specific beamline, visit and proposal requested in the input.
user_session := to_number(_session) if {
session.write_to_beamline_visit
_session
}

user_session := to_number(_session) if {
input.proposal in token.claims.subject.proposals
}

user_session := to_number(_session) if {
_session in token.claims.subject.sessions
}

user_session := to_number(_session) if {
input.beamline in beamlines
input.beamline == session.beamline_for(input.proposal, input.visit)
_session in data.diamond.data.beamlines[input.beamline].sessions
}

default fedid := ""

fedid := token.claims.fedid

# Validates if the subject has permission to modify
# the specific session in the input.
default modify_session := false

modify_session if session.access_session(
fedid,
data.diamond.data.sessions[input.session].proposal_number,
data.diamond.data.sessions[input.session].visit_number,
)

modify_session if {
data.diamond.data.sessions[input.session].proposal_number in token.claims.subject.proposals
}

modify_session if {
to_number(input.session) in token.claims.subject.sessions
}

scopes_for(claims) := read_scopes | write_scopes if {
"azp" in object.keys(claims)
endswith(claims.azp, "-blueapi")
modify_session if {
session.beamline_for(
data.diamond.data.sessions[input.session].proposal_number,
data.diamond.data.sessions[input.session].visit_number,
) in beamlines
}

scopes_for(claims) := read_scopes if {
"azp" in object.keys(claims)
not endswith(claims.azp, "-blueapi")
subject := data.diamond.data.subjects[token.claims.fedid] if token.claims.fedid

else := token.claims.subject if token.claims.subject

# Identifies all beamlines the subject is authorized to access
# based on their assigned permissions.
beamlines contains beamline if {
not admin.is_admin(fedid)
some p in subject.permissions
some beamline in object.get(data.diamond.data.admin, p, [])
}

scopes_for(claims) := read_scopes if {
not "azp" in object.keys(claims)
# 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 {
admin.is_admin(fedid)
}

default scopes := set()
user_sessions contains to_number(session) if {
not admin.is_admin(fedid)
some session in subject.sessions
}

scopes := scopes_for(token.claims)
user_sessions contains to_number(session) if {
not admin.is_admin(fedid)
some beamline in beamlines
some session in data.diamond.data.beamlines[beamline].sessions
}

user_sessions contains user_session if {
some i in data.diamond.data.sessions
session.access_session(token.claims.fedid, i.proposal_number, i.visit_number)
user_session := sprintf(
`{"proposal": %d, "visit": %d, "beamline": "%s"}`,
[i.proposal_number, i.visit_number, i.beamline],
)
user_sessions contains to_number(session) if {
not admin.is_admin(fedid)
some p in subject.proposals
some i in data.diamond.data.proposals[format_int(p, 10)]
some session in i
}
142 changes: 108 additions & 34 deletions policy/diamond/policy/tiled/tiled_test.rego
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,22 @@ package diamond.policy.tiled_test
import data.diamond.policy.tiled
import rego.v1

test_default_no_scopes if {
tiled.scopes == set()
}

test_wrong_azp_read_scopes if {
tiled.scopes == tiled.read_scopes with data.diamond.policy.token.claims as {}
tiled.scopes == tiled.read_scopes with data.diamond.policy.token.claims as {"sub": "foo"}
tiled.scopes == tiled.read_scopes with data.diamond.policy.token.claims as {"azp": "foo"}
test_read_scopes if {
tiled.scopes == {
"read:metadata",
"read:data",
} with data.diamond.policy.token.claims as {}
}

test_blueapi_given_write_scopes if {
test_tiled_writer_given_write_scopes if {
tiled.scopes == {
"read:metadata",
"read:data",
"write:metadata",
"write:data",
"create:node",
"register",
} with data.diamond.policy.token.claims as {"azp": "foo-blueapi"}
} with data.diamond.policy.token.claims as {"aud": ["tiled-writer"]}
}

diamond_data := {
Expand Down Expand Up @@ -96,33 +93,110 @@ diamond_data := {
test_user_session_tags if {
tiled.user_sessions == set() with data.diamond.data as diamond_data
with data.diamond.policy.token.claims as {"fedid": "oscar"}
tiled.user_sessions == {
`{"proposal": 1, "visit": 2, "beamline": "b07"}`,
`{"proposal": 1, "visit": 1, "beamline": "i03"}`,
} with data.diamond.data as diamond_data
tiled.user_sessions == {11, 12} with data.diamond.data as diamond_data
with data.diamond.policy.token.claims as {"fedid": "alice"}
tiled.user_sessions == {
`{"proposal": 1, "visit": 2, "beamline": "b07"}`,
`{"proposal": 1, "visit": 1, "beamline": "i03"}`,
`{"proposal": 2, "visit": 1, "beamline": "b07"}`,
`{"proposal": 2, "visit": 2, "beamline": "b07"}`,
} with data.diamond.data as diamond_data
tiled.user_sessions == {11, 12, 13, 14} with data.diamond.data as diamond_data
with data.diamond.policy.token.claims as {"fedid": "bob"}
tiled.user_sessions == {
`{"proposal": 1, "visit": 2, "beamline": "b07"}`,
`{"proposal": 1, "visit": 1, "beamline": "i03"}`,
`{"proposal": 2, "visit": 1, "beamline": "b07"}`,
`{"proposal": 2, "visit": 2, "beamline": "b07"}`,
} with data.diamond.data as diamond_data
tiled.user_sessions == {"*"} with data.diamond.data as diamond_data
with data.diamond.policy.token.claims as {"fedid": "carol"}
tiled.user_sessions == {
`{"proposal": 2, "visit": 1, "beamline": "b07"}`,
`{"proposal": 2, "visit": 2, "beamline": "b07"}`,
} with data.diamond.data as diamond_data
tiled.user_sessions == {13, 14} with data.diamond.data as diamond_data
with data.diamond.policy.token.claims as {"fedid": "desmond"}
tiled.user_sessions == {
`{"proposal": 2, "visit": 1, "beamline": "b07"}`,
`{"proposal": 2, "visit": 2, "beamline": "b07"}`,
} with data.diamond.data as diamond_data
tiled.user_sessions == {13, 14} with data.diamond.data as diamond_data
with data.diamond.policy.token.claims as {"fedid": "edna"}
}

test_user_session_allow if {
tiled.user_session == 11 with data.diamond.data as diamond_data
with input as {"beamline": "i03", "proposal": 1, "visit": 1}
with data.diamond.policy.token.claims as {"fedid": "carol"}
}

test_user_session_not_allowed if {
not tiled.user_session with data.diamond.data as diamond_data
with input as {"beamline": "i03", "proposal": 1, "visit": 1}
with data.diamond.policy.token.claims as {"fedid": "oscar"}
}

test_not_modify_session if {
not tiled.modify_session with data.diamond.data as diamond_data
with input as {"session": "13"}
with data.diamond.policy.token.claims as {"fedid": "alice"}
}

test_modify_session if {
tiled.modify_session with data.diamond.data as diamond_data
with input as {"session": "11"}
with data.diamond.policy.token.claims as {"fedid": "alice"}
}

# Service account tests

test_user_session_allow_service_account_on_proposal if {
tiled.user_session == 11 with data.diamond.data as diamond_data
with input as {"beamline": "i03", "proposal": 1, "visit": 1}
with data.diamond.policy.token.claims as {"subject": {"proposals": [1], "sessions": [], "permissions": []}}
}

test_user_session_allow_service_account_on_session if {
tiled.user_session == 11 with data.diamond.data as diamond_data
with input as {"beamline": "i03", "proposal": 1, "visit": 1}
with data.diamond.policy.token.claims as {"subject": {"proposals": [], "sessions": [11], "permissions": []}}
}

test_user_session_not_allow_service_account_wrong_beamline if {
not tiled.user_session with data.diamond.data as diamond_data
with input as {"beamline": "i03", "proposal": 1, "visit": 2}
with data.diamond.policy.token.claims as {"subject": {"proposals": [], "sessions": [], "permissions": ["b07_admin"]}}
}

test_user_session_allow_service_account_with_beamline if {
tiled.user_session with data.diamond.data as diamond_data
with input as {"beamline": "b07", "proposal": 1, "visit": 2}
with data.diamond.policy.token.claims as {
"subject": {"proposals": [], "sessions": [], "permissions": ["b07_admin"]},
"fedid": "",
}
}

test_modify_session_on_proposal if {
tiled.modify_session with data.diamond.data as diamond_data
with input as {"session": "11"}
with data.diamond.policy.token.claims as {"subject": {"proposals": [1], "sessions": [], "permissions": []}}
}

test_modify_session_on_session if {
tiled.modify_session with data.diamond.data as diamond_data
with input as {"session": "11"}
with data.diamond.policy.token.claims as {"subject": {"proposals": [], "sessions": [11], "permissions": []}}
}

test_modify_session_on_permission if {
tiled.modify_session with data.diamond.data as diamond_data
with input as {"session": "12"}
with data.diamond.policy.token.claims as {"subject": {
"proposals": [],
"sessions": [],
"permissions": ["b07_admin"],
}}
}

test_user_session_tags_service_account if {
tiled.user_sessions == {11} with data.diamond.data as diamond_data
with data.diamond.policy.token.claims as {"subject": {
"proposals": [],
"sessions": [11],
"permissions": [],
}}
tiled.user_sessions == {11, 12} with data.diamond.data as diamond_data
with data.diamond.policy.token.claims as {"subject": {
"proposals": [1],
"sessions": [],
"permissions": [],
}}
tiled.user_sessions == {12, 13, 14} with data.diamond.data as diamond_data
with data.diamond.policy.token.claims as {"subject": {
"proposals": [],
"sessions": [],
"permissions": ["b07_admin"],
}}
}
Loading