Skip to content

Commit 579eb3c

Browse files
committed
feat: Update tiled authz policy to use session
1 parent bc5c2f4 commit 579eb3c

File tree

2 files changed

+200
-53
lines changed

2 files changed

+200
-53
lines changed
Lines changed: 92 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,117 @@
11
package diamond.policy.tiled
22

3+
import data.diamond.policy.admin
34
import data.diamond.policy.session
45
import data.diamond.policy.token
56
import rego.v1
67

7-
read_scopes := {
8+
# Assign read & write scopes to clients with tiled-writer audience
9+
# defaults to read-only scopes
10+
default scopes := {
811
"read:metadata",
912
"read:data",
1013
}
1114

12-
write_scopes := {
15+
scopes := {
16+
"read:metadata",
17+
"read:data",
1318
"write:metadata",
1419
"write:data",
1520
"create:node",
1621
"register",
22+
} if {
23+
"tiled-writer" in token.claims.aud
24+
}
25+
26+
_session := data.diamond.data.proposals[format_int(input.proposal, 10)].sessions[format_int(input.visit, 10)]
27+
28+
# Returns the session ID if the subject has write permissions for the
29+
# specific beamline, visit and proposal requested in the input.
30+
user_session := to_number(_session) if {
31+
session.write_to_beamline_visit
32+
_session
33+
}
34+
35+
user_session := to_number(_session) if {
36+
input.proposal in token.claims.subject.proposals
37+
}
38+
39+
user_session := to_number(_session) if {
40+
_session in token.claims.subject.sessions
41+
}
42+
43+
user_session := to_number(_session) if {
44+
input.beamline in beamlines
45+
input.beamline == session.beamline_for(input.proposal, input.visit)
46+
_session in data.diamond.data.beamlines[input.beamline].sessions
47+
}
48+
49+
default fedid := ""
50+
51+
fedid := token.claims.fedid
52+
53+
# Validates if the subject has permission to modify
54+
# the specific session in the input.
55+
default modify_session := false
56+
57+
modify_session if session.access_session(
58+
fedid,
59+
data.diamond.data.sessions[input.session].proposal_number,
60+
data.diamond.data.sessions[input.session].visit_number,
61+
)
62+
63+
modify_session if {
64+
data.diamond.data.sessions[input.session].proposal_number in token.claims.subject.proposals
65+
}
66+
67+
modify_session if {
68+
to_number(input.session) in token.claims.subject.sessions
1769
}
1870

19-
scopes_for(claims) := read_scopes | write_scopes if {
20-
"azp" in object.keys(claims)
21-
endswith(claims.azp, "-blueapi")
71+
modify_session if {
72+
session.beamline_for(
73+
data.diamond.data.sessions[input.session].proposal_number,
74+
data.diamond.data.sessions[input.session].visit_number,
75+
) in beamlines
2276
}
2377

24-
scopes_for(claims) := read_scopes if {
25-
"azp" in object.keys(claims)
26-
not endswith(claims.azp, "-blueapi")
78+
subject := data.diamond.data.subjects[token.claims.fedid] if token.claims.fedid
79+
80+
else := token.claims.subject if token.claims.subject
81+
82+
# Identifies all beamlines the subject is authorized to access
83+
# based on their assigned permissions.
84+
beamlines contains beamline if {
85+
not admin.is_admin(fedid)
86+
some p in subject.permissions
87+
some beamline in object.get(data.diamond.data.admin, p, [])
2788
}
2889

29-
scopes_for(claims) := read_scopes if {
30-
not "azp" in object.keys(claims)
90+
# Aggregates all session IDs the subject is authorized to view.
91+
# Admins receive a wildcard "*" granting access to all sessions.
92+
93+
# Regular users gain session access through three pathways:
94+
# 1. Direct session membership
95+
# 2. Access via beamline-level permissions
96+
# 3. Access via proposal-level permissions
97+
user_sessions contains "*" if {
98+
admin.is_admin(fedid)
3199
}
32100

33-
default scopes := set()
101+
user_sessions contains to_number(session) if {
102+
not admin.is_admin(fedid)
103+
some session in subject.sessions
104+
}
34105

35-
scopes := scopes_for(token.claims)
106+
user_sessions contains to_number(session) if {
107+
not admin.is_admin(fedid)
108+
some beamline in beamlines
109+
some session in data.diamond.data.beamlines[beamline].sessions
110+
}
36111

37-
user_sessions contains user_session if {
38-
some i in data.diamond.data.sessions
39-
session.access_session(token.claims.fedid, i.proposal_number, i.visit_number)
40-
user_session := sprintf(
41-
`{"proposal": %d, "visit": %d, "beamline": "%s"}`,
42-
[i.proposal_number, i.visit_number, i.beamline],
43-
)
112+
user_sessions contains to_number(session) if {
113+
not admin.is_admin(fedid)
114+
some p in subject.proposals
115+
some i in data.diamond.data.proposals[format_int(p, 10)]
116+
some session in i
44117
}

policy/diamond/policy/tiled/tiled_test.rego

Lines changed: 108 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,22 @@ package diamond.policy.tiled_test
33
import data.diamond.policy.tiled
44
import rego.v1
55

6-
test_default_no_scopes if {
7-
tiled.scopes == set()
8-
}
9-
10-
test_wrong_azp_read_scopes if {
11-
tiled.scopes == tiled.read_scopes with data.diamond.policy.token.claims as {}
12-
tiled.scopes == tiled.read_scopes with data.diamond.policy.token.claims as {"sub": "foo"}
13-
tiled.scopes == tiled.read_scopes with data.diamond.policy.token.claims as {"azp": "foo"}
6+
test_read_scopes if {
7+
tiled.scopes == {
8+
"read:metadata",
9+
"read:data",
10+
} with data.diamond.policy.token.claims as {}
1411
}
1512

16-
test_blueapi_given_write_scopes if {
13+
test_tiled_writer_given_write_scopes if {
1714
tiled.scopes == {
1815
"read:metadata",
1916
"read:data",
2017
"write:metadata",
2118
"write:data",
2219
"create:node",
2320
"register",
24-
} with data.diamond.policy.token.claims as {"azp": "foo-blueapi"}
21+
} with data.diamond.policy.token.claims as {"aud": ["tiled-writer"]}
2522
}
2623

2724
diamond_data := {
@@ -96,33 +93,110 @@ diamond_data := {
9693
test_user_session_tags if {
9794
tiled.user_sessions == set() with data.diamond.data as diamond_data
9895
with data.diamond.policy.token.claims as {"fedid": "oscar"}
99-
tiled.user_sessions == {
100-
`{"proposal": 1, "visit": 2, "beamline": "b07"}`,
101-
`{"proposal": 1, "visit": 1, "beamline": "i03"}`,
102-
} with data.diamond.data as diamond_data
96+
tiled.user_sessions == {11, 12} with data.diamond.data as diamond_data
10397
with data.diamond.policy.token.claims as {"fedid": "alice"}
104-
tiled.user_sessions == {
105-
`{"proposal": 1, "visit": 2, "beamline": "b07"}`,
106-
`{"proposal": 1, "visit": 1, "beamline": "i03"}`,
107-
`{"proposal": 2, "visit": 1, "beamline": "b07"}`,
108-
`{"proposal": 2, "visit": 2, "beamline": "b07"}`,
109-
} with data.diamond.data as diamond_data
98+
tiled.user_sessions == {11, 12, 13, 14} with data.diamond.data as diamond_data
11099
with data.diamond.policy.token.claims as {"fedid": "bob"}
111-
tiled.user_sessions == {
112-
`{"proposal": 1, "visit": 2, "beamline": "b07"}`,
113-
`{"proposal": 1, "visit": 1, "beamline": "i03"}`,
114-
`{"proposal": 2, "visit": 1, "beamline": "b07"}`,
115-
`{"proposal": 2, "visit": 2, "beamline": "b07"}`,
116-
} with data.diamond.data as diamond_data
100+
tiled.user_sessions == {"*"} with data.diamond.data as diamond_data
117101
with data.diamond.policy.token.claims as {"fedid": "carol"}
118-
tiled.user_sessions == {
119-
`{"proposal": 2, "visit": 1, "beamline": "b07"}`,
120-
`{"proposal": 2, "visit": 2, "beamline": "b07"}`,
121-
} with data.diamond.data as diamond_data
102+
tiled.user_sessions == {13, 14} with data.diamond.data as diamond_data
122103
with data.diamond.policy.token.claims as {"fedid": "desmond"}
123-
tiled.user_sessions == {
124-
`{"proposal": 2, "visit": 1, "beamline": "b07"}`,
125-
`{"proposal": 2, "visit": 2, "beamline": "b07"}`,
126-
} with data.diamond.data as diamond_data
104+
tiled.user_sessions == {13, 14} with data.diamond.data as diamond_data
127105
with data.diamond.policy.token.claims as {"fedid": "edna"}
128106
}
107+
108+
test_user_session_allow if {
109+
tiled.user_session == 11 with data.diamond.data as diamond_data
110+
with input as {"beamline": "i03", "proposal": 1, "visit": 1}
111+
with data.diamond.policy.token.claims as {"fedid": "carol"}
112+
}
113+
114+
test_user_session_not_allowed if {
115+
not tiled.user_session with data.diamond.data as diamond_data
116+
with input as {"beamline": "i03", "proposal": 1, "visit": 1}
117+
with data.diamond.policy.token.claims as {"fedid": "oscar"}
118+
}
119+
120+
test_not_modify_session if {
121+
not tiled.modify_session with data.diamond.data as diamond_data
122+
with input as {"session": "13"}
123+
with data.diamond.policy.token.claims as {"fedid": "alice"}
124+
}
125+
126+
test_modify_session if {
127+
tiled.modify_session with data.diamond.data as diamond_data
128+
with input as {"session": "11"}
129+
with data.diamond.policy.token.claims as {"fedid": "alice"}
130+
}
131+
132+
# Service account tests
133+
134+
test_user_session_allow_service_account_on_proposal if {
135+
tiled.user_session == 11 with data.diamond.data as diamond_data
136+
with input as {"beamline": "i03", "proposal": 1, "visit": 1}
137+
with data.diamond.policy.token.claims as {"subject": {"proposals": [1], "sessions": [], "permissions": []}}
138+
}
139+
140+
test_user_session_allow_service_account_on_session if {
141+
tiled.user_session == 11 with data.diamond.data as diamond_data
142+
with input as {"beamline": "i03", "proposal": 1, "visit": 1}
143+
with data.diamond.policy.token.claims as {"subject": {"proposals": [], "sessions": [11], "permissions": []}}
144+
}
145+
146+
test_user_session_not_allow_service_account_wrong_beamline if {
147+
not tiled.user_session with data.diamond.data as diamond_data
148+
with input as {"beamline": "i03", "proposal": 1, "visit": 2}
149+
with data.diamond.policy.token.claims as {"subject": {"proposals": [], "sessions": [], "permissions": ["b07_admin"]}}
150+
}
151+
152+
test_user_session_allow_service_account_with_beamline if {
153+
tiled.user_session with data.diamond.data as diamond_data
154+
with input as {"beamline": "b07", "proposal": 1, "visit": 2}
155+
with data.diamond.policy.token.claims as {
156+
"subject": {"proposals": [], "sessions": [], "permissions": ["b07_admin"]},
157+
"fedid": "",
158+
}
159+
}
160+
161+
test_modify_session_on_proposal if {
162+
tiled.modify_session with data.diamond.data as diamond_data
163+
with input as {"session": "11"}
164+
with data.diamond.policy.token.claims as {"subject": {"proposals": [1], "sessions": [], "permissions": []}}
165+
}
166+
167+
test_modify_session_on_session if {
168+
tiled.modify_session with data.diamond.data as diamond_data
169+
with input as {"session": "11"}
170+
with data.diamond.policy.token.claims as {"subject": {"proposals": [], "sessions": [11], "permissions": []}}
171+
}
172+
173+
test_modify_session_on_permission if {
174+
tiled.modify_session with data.diamond.data as diamond_data
175+
with input as {"session": "12"}
176+
with data.diamond.policy.token.claims as {"subject": {
177+
"proposals": [],
178+
"sessions": [],
179+
"permissions": ["b07_admin"],
180+
}}
181+
}
182+
183+
test_user_session_tags_service_account if {
184+
tiled.user_sessions == {11} with data.diamond.data as diamond_data
185+
with data.diamond.policy.token.claims as {"subject": {
186+
"proposals": [],
187+
"sessions": [11],
188+
"permissions": [],
189+
}}
190+
tiled.user_sessions == {11, 12} with data.diamond.data as diamond_data
191+
with data.diamond.policy.token.claims as {"subject": {
192+
"proposals": [1],
193+
"sessions": [],
194+
"permissions": [],
195+
}}
196+
tiled.user_sessions == {12, 13, 14} with data.diamond.data as diamond_data
197+
with data.diamond.policy.token.claims as {"subject": {
198+
"proposals": [],
199+
"sessions": [],
200+
"permissions": ["b07_admin"],
201+
}}
202+
}

0 commit comments

Comments
 (0)