1
1
package authz
2
+
2
3
import rego.v1
3
4
4
5
# A great playground: https://play.openpolicyagent.org/
@@ -31,13 +32,13 @@ import rego.v1
31
32
# bool_flip lets you assign a value to an inverted bool.
32
33
# You cannot do 'x := !false', but you can do 'x := bool_flip(false)'
33
34
bool_flip (b) = flipped if {
34
- b
35
- flipped = false
35
+ b
36
+ flipped = false
36
37
}
37
38
38
39
bool_flip (b) = flipped if {
39
- not b
40
- flipped = true
40
+ not b
41
+ flipped = true
41
42
}
42
43
43
44
# 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 {
46
47
# 1: {true}
47
48
number (set) = c if {
48
49
count (set) == 0
49
- c := 0
50
+ c := 0
50
51
}
51
52
52
53
number (set) = c if {
53
54
false in set
54
- c := - 1
55
+ c := - 1
55
56
}
56
57
57
58
number (set) = c if {
58
59
not false in set
59
60
set[_]
60
- c := 1
61
+ c := 1
61
62
}
62
63
63
64
# site, org, and user rules are all similar. Each rule should return a number
64
65
# from [-1, 1]. The number corresponds to "negative", "abstain", and "positive"
65
66
# for the given level. See the 'allow' rules for how these numbers are used.
66
67
default site = 0
68
+
67
69
site := site_allow (input.subject.roles)
70
+
68
71
default scope_site := 0
72
+
69
73
scope_site := site_allow ([input.subject.scope])
70
74
71
75
site_allow (roles) := num if {
72
76
# allow is a set of boolean values without duplicates.
73
- allow := { x |
77
+ allow := {x |
74
78
# 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, " *" ]
77
81
perm.resource_type in [input.object.type, " *" ]
82
+
78
83
# 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)
82
87
}
83
88
84
89
# org_members is the list of organizations the actor is apart of.
85
- org_members := { orgID |
90
+ org_members := {orgID |
86
91
input.subject.roles[_].org[orgID]
87
92
}
88
93
89
94
# org is the same as 'site' except we need to iterate over each organization
90
95
# that the actor is a member of.
91
96
default org = 0
97
+
92
98
org := org_allow (input.subject.roles)
99
+
93
100
default scope_org := 0
101
+
94
102
scope_org := org_allow ([input.scope])
95
103
96
104
# 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])
104
112
# is that sometimes the input.object.org_owner is unknown. In those cases
105
113
# we have a list of org_ids that can we use in a SQL 'WHERE' clause.
106
114
org_allow_set (roles) := allow_set if {
107
- allow_set := { id: num |
115
+ allow_set := {id: num |
108
116
id := org_members[_]
109
- set := { x |
117
+ set := {x |
110
118
perm := roles[_].org[id][_]
111
119
perm.action in [input.action, " *" ]
112
120
perm.resource_type in [input.object.type, " *" ]
@@ -140,33 +148,34 @@ org_allow(roles) := num if {
140
148
input.object.any_org # if this is false, this code block is not used
141
149
allow := org_allow_set (roles)
142
150
143
-
144
151
# allow is a map of {"<org_id>": <number>}. We only care about values
145
152
# that are 1, and ignore the rest.
146
153
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
158
167
])
159
168
}
160
169
161
170
# 'org_mem' is set to true if the user is an org member
162
171
# If 'any_org' is set to true, use the other block to determine org membership.
163
- org_mem := true if {
172
+ org_mem if {
164
173
not input.object.any_org
165
174
input.object.org_owner != " "
166
175
input.object.org_owner in org_members
167
176
}
168
177
169
- org_mem := true if {
178
+ org_mem if {
170
179
input.object.any_org
171
180
count (org_members) > 0
172
181
}
@@ -185,20 +194,23 @@ org_ok if {
185
194
# User is the same as the site, except it only applies if the user owns the object and
186
195
# the user is apart of the org (if the object has an org).
187
196
default user = 0
197
+
188
198
user := user_allow (input.subject.roles)
199
+
189
200
default user_scope := 0
201
+
190
202
scope_user := user_allow ([input.scope])
191
203
192
204
user_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, " *" ]
198
210
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)
202
214
}
203
215
204
216
# Scope allow_list is a list of resource IDs explicitly allowed by the scope.
@@ -239,6 +251,7 @@ role_allow if {
239
251
role_allow if {
240
252
not site = - 1
241
253
not org = - 1
254
+
242
255
# If we are not a member of an org, and the object has an org, then we are
243
256
# not authorized. This is an "implied -1" for not being in the org.
244
257
org_ok
@@ -260,6 +273,7 @@ scope_allow if {
260
273
scope_allow_list
261
274
not scope_site = - 1
262
275
not scope_org = - 1
276
+
263
277
# If we are not a member of an org, and the object has an org, then we are
264
278
# not authorized. This is an "implied -1" for not being in the org.
265
279
org_ok
@@ -270,6 +284,7 @@ scope_allow if {
270
284
acl_allow if {
271
285
# Should you have to be a member of the org too?
272
286
perms := input.object.acl_user_list[input.subject.id]
287
+
273
288
# Either the input action or wildcard
274
289
[input.action, " *" ][_] in perms
275
290
}
@@ -281,6 +296,7 @@ acl_allow if {
281
296
org_mem
282
297
group := input.subject.groups[_]
283
298
perms := input.object.acl_group_list[group]
299
+
284
300
# Either the input action or wildcard
285
301
[input.action, " *" ][_] in perms
286
302
}
0 commit comments