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
29 changes: 29 additions & 0 deletions policy/diamond/policy/beamline/beamline.rego
Original file line number Diff line number Diff line change
@@ -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)
}
98 changes: 98 additions & 0 deletions policy/diamond/policy/beamline/beamline_test.rego
Original file line number Diff line number Diff line change
@@ -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
}
50 changes: 50 additions & 0 deletions policy/diamond/policy/session/session.rego
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
}
55 changes: 50 additions & 5 deletions policy/diamond/policy/session/session_test.rego
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ diamond_data := {
"proposals": [],
"sessions": [],
},
"desmond": {
"permissions": [],
"proposals": [2],
"sessions": [13],
},
"edna": {
"permissions": [],
"proposals": [2],
"sessions": [13, 14],
},
"oscar": {
"permissions": [],
"proposals": [],
Expand All @@ -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"]},
}

Expand Down Expand Up @@ -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"}
}
13 changes: 13 additions & 0 deletions policy/diamond/policy/token/token.rego
Original file line number Diff line number Diff line change
Expand Up @@ -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]
67 changes: 67 additions & 0 deletions policy/diamond/policy/ulims/ulims.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package diamond.policy.ulims

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

# 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 {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The 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 session.user_sessions] if {
not admin.is_admin(token.claims.fedid)
}

session_restrictions := [data.diamond.data.sessions[session_id] | some session_id in session.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 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 {
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
# 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 _beamline if {
some _beamline in input.instruments
_beamline in object.keys(data.diamond.data.beamlines)
_beamline in beamline.user_beamlines
}
Loading
Loading