11package authz
2+
23import rego.v1
34
45# A great playground: https://play.openpolicyagent.org/
@@ -31,13 +32,13 @@ import rego.v1
3132# bool_flip lets you assign a value to an inverted bool.
3233# You cannot do 'x := !false', but you can do 'x := bool_flip(false)'
3334bool_flip (b) = flipped if {
34- b
35- flipped = false
35+ b
36+ flipped = false
3637}
3738
3839bool_flip (b) = flipped if {
39- not b
40- flipped = true
40+ not b
41+ flipped = true
4142}
4243
4344# number is a quick way to get a set of {true, false} and convert it to
@@ -46,51 +47,58 @@ bool_flip(b) = flipped if {
4647# 1: {true}
4748number (set) = c if {
4849 count (set) == 0
49- c := 0
50+ c := 0
5051}
5152
5253number (set) = c if {
5354 false in set
54- c := - 1
55+ c := - 1
5556}
5657
5758number (set) = c if {
5859 not false in set
5960 set[_]
60- c := 1
61+ c := 1
6162}
6263
6364# site, org, and user rules are all similar. Each rule should return a number
6465# from [-1, 1]. The number corresponds to "negative", "abstain", and "positive"
6566# for the given level. See the 'allow' rules for how these numbers are used.
6667default site = 0
68+
6769site := site_allow (input.subject.roles)
70+
6871default scope_site := 0
72+
6973scope_site := site_allow ([input.subject.scope])
7074
7175site_allow (roles) := num if {
7276 # allow is a set of boolean values without duplicates.
73- allow := { x |
77+ allow := {x |
7478 # Iterate over all site permissions in all roles
75- perm := roles[_].site[_]
76- perm.action in [input.action, " *" ]
79+ perm := roles[_].site[_]
80+ perm.action in [input.action, " *" ]
7781 perm.resource_type in [input.object.type, " *" ]
82+
7883 # x is either 'true' or 'false' if a matching permission exists.
79- x := bool_flip (perm.negate)
80- }
81- num := number (allow)
84+ x := bool_flip (perm.negate)
85+ }
86+ num := number (allow)
8287}
8388
8489# org_members is the list of organizations the actor is apart of.
85- org_members := { orgID |
90+ org_members := {orgID |
8691 input.subject.roles[_].org[orgID]
8792}
8893
8994# org is the same as 'site' except we need to iterate over each organization
9095# that the actor is a member of.
9196default org = 0
97+
9298org := org_allow (input.subject.roles)
99+
93100default scope_org := 0
101+
94102scope_org := org_allow ([input.scope])
95103
96104# org_allow_set is a helper function that iterates over all orgs that the actor
@@ -104,9 +112,9 @@ scope_org := org_allow([input.scope])
104112# is that sometimes the input.object.org_owner is unknown. In those cases
105113# we have a list of org_ids that can we use in a SQL 'WHERE' clause.
106114org_allow_set (roles) := allow_set if {
107- allow_set := { id: num |
115+ allow_set := {id: num |
108116 id := org_members[_]
109- set := { x |
117+ set := {x |
110118 perm := roles[_].org[id][_]
111119 perm.action in [input.action, " *" ]
112120 perm.resource_type in [input.object.type, " *" ]
@@ -140,33 +148,34 @@ org_allow(roles) := num if {
140148 input.object.any_org # if this is false, this code block is not used
141149 allow := org_allow_set (roles)
142150
143-
144151 # allow is a map of {"<org_id>": <number>}. We only care about values
145152 # that are 1, and ignore the rest.
146153 num := number ([
147- keep |
148- # for every value in the mapping
149- value := allow[_]
150- # only keep values > 0.
151- # 1 = allow, 0 = abstain, -1 = deny
152- # We only need 1 explicit allow to allow the action.
153- # deny's and abstains are intentionally ignored.
154- value > 0
155- # result set is a set of [true,false,...]
156- # which "number()" will convert to a number.
157- keep := true
154+ keep |
155+ # for every value in the mapping
156+ value := allow[_]
157+
158+ # only keep values > 0.
159+ # 1 = allow, 0 = abstain, -1 = deny
160+ # We only need 1 explicit allow to allow the action.
161+ # deny's and abstains are intentionally ignored.
162+ value > 0
163+
164+ # result set is a set of [true,false,...]
165+ # which "number()" will convert to a number.
166+ keep := true
158167 ])
159168}
160169
161170# 'org_mem' is set to true if the user is an org member
162171# If 'any_org' is set to true, use the other block to determine org membership.
163- org_mem := true if {
172+ org_mem if {
164173 not input.object.any_org
165174 input.object.org_owner != " "
166175 input.object.org_owner in org_members
167176}
168177
169- org_mem := true if {
178+ org_mem if {
170179 input.object.any_org
171180 count (org_members) > 0
172181}
@@ -185,20 +194,23 @@ org_ok if {
185194# User is the same as the site, except it only applies if the user owns the object and
186195# the user is apart of the org (if the object has an org).
187196default user = 0
197+
188198user := user_allow (input.subject.roles)
199+
189200default user_scope := 0
201+
190202scope_user := user_allow ([input.scope])
191203
192204user_allow (roles) := num if {
193- input.object.owner != " "
194- input.subject.id = input.object.owner
195- allow := { x |
196- perm := roles[_].user[_]
197- perm.action in [input.action, " *" ]
205+ input.object.owner != " "
206+ input.subject.id = input.object.owner
207+ allow := {x |
208+ perm := roles[_].user[_]
209+ perm.action in [input.action, " *" ]
198210 perm.resource_type in [input.object.type, " *" ]
199- x := bool_flip (perm.negate)
200- }
201- num := number (allow)
211+ x := bool_flip (perm.negate)
212+ }
213+ num := number (allow)
202214}
203215
204216# Scope allow_list is a list of resource IDs explicitly allowed by the scope.
@@ -239,6 +251,7 @@ role_allow if {
239251role_allow if {
240252 not site = - 1
241253 not org = - 1
254+
242255 # If we are not a member of an org, and the object has an org, then we are
243256 # not authorized. This is an "implied -1" for not being in the org.
244257 org_ok
@@ -260,6 +273,7 @@ scope_allow if {
260273 scope_allow_list
261274 not scope_site = - 1
262275 not scope_org = - 1
276+
263277 # If we are not a member of an org, and the object has an org, then we are
264278 # not authorized. This is an "implied -1" for not being in the org.
265279 org_ok
@@ -270,6 +284,7 @@ scope_allow if {
270284acl_allow if {
271285 # Should you have to be a member of the org too?
272286 perms := input.object.acl_user_list[input.subject.id]
287+
273288 # Either the input action or wildcard
274289 [input.action, " *" ][_] in perms
275290}
@@ -281,6 +296,7 @@ acl_allow if {
281296 org_mem
282297 group := input.subject.groups[_]
283298 perms := input.object.acl_group_list[group]
299+
284300 # Either the input action or wildcard
285301 [input.action, " *" ][_] in perms
286302}
0 commit comments