1
1
package authz
2
- import future.keywords.in
3
- import future.keywords.every
2
+ import future.keywords
3
+ # Helpful cli commands to debug.
4
+ # opa eval --format=pretty 'data.authz.allow = true' -d policy.rego -i input.json
5
+ # opa eval --partial --format=pretty 'data.authz.allow = true' -d policy.rego --unknowns input.object.owner --unknowns input.object.org_owner -i input.json
6
+
4
7
5
- # A great playground: https://play.openpolicyagent.org/
6
- # TODO: Add debug instructions to do in the cli. Running really short on time, the
7
- # playground is sufficient for now imo. In the future we can provide a tidy bash
8
- # script for running this against predefined input.
9
8
10
9
# bool_flip lets you assign a value to an inverted bool.
11
10
# You cannot do 'x := !false', but you can do 'x := bool_flip(false)'
@@ -19,121 +18,95 @@ bool_flip(b) = flipped {
19
18
flipped = true
20
19
}
21
20
22
- # perms_grant returns a set of boolean values {true, false}.
23
- # True means a positive permission in the set, false is a negative permission.
24
- # It will only return `bool_flip(perm.negate)` for permissions that affect a given
25
- # resource_type, and action.
26
- # The empty set is returned if no relevant permissions are found.
27
- perms_grant (permissions) = grants {
28
- # If there are no permissions, this value is the empty set {}.
29
- grants := { x |
30
- # All permissions ...
31
- perm := permissions[_]
32
- # Such that the permission action, and type matches
33
- perm.action in [input.action, " *" ]
34
- perm.resource_type in [input.object.type, " *" ]
35
- x := bool_flip (perm.negate)
36
- }
21
+ number (set) = c {
22
+ count (set) == 0
23
+ c := 0
37
24
}
38
25
39
- # Site & User are both very simple. We default both to the empty set '{}'. If no permissions are present, then the
40
- # result is the default value.
41
- default site = {}
42
- site = grant {
43
- # Boolean set for all site wide permissions.
44
- grant = { v | # Use set comprehension to remove duplicate values
45
- # For each role, grab the site permission.
46
- # Find the grants on this permission list.
47
- v = perms_grant (input.subject.roles[_].site)[_]
48
- }
26
+ number (set) = c {
27
+ false in set
28
+ c := - 1
49
29
}
50
30
51
- default user = {}
52
- user = grant {
53
- # Only apply user permissions if the user owns the resource
54
- input.object.owner != " "
55
- input.object.owner == input.subject.id
56
- grant = { v |
57
- # For each role, grab the user permissions.
58
- # Find the grants on this permission list.
59
- v = perms_grant (input.subject.roles[_].user)[_]
60
- }
31
+ number (set) = c {
32
+ not false in set
33
+ set[_]
34
+ c := 1
61
35
}
62
36
63
- # Organizations are more complex. If the user has no roles that specifically indicate the org_id of the object,
64
- # then we want to block the action. This is because that means the user is not a member of the org.
65
- # A non-member cannot access any org resources.
66
37
67
- # org_member returns the set of permissions associated with a user if the user is a member of the
68
- # organization
69
- org_member = grant {
70
- input.object.org_owner != " "
71
- grant = { v |
72
- v = perms_grant (input.subject.roles[_].org[input.object.org_owner])[_]
38
+ default site = 0
39
+ site := num {
40
+ # relevent are all the permissions that affect the given unknown object
41
+ allow := { x |
42
+ perm := input.subject.roles[_].site[_]
43
+ perm.action in [input.action, " *" ]
44
+ perm.resource_type in [input.object.type, " *" ]
45
+ x := bool_flip (perm.negate)
73
46
}
47
+ num := number (allow)
74
48
}
75
49
76
- # If a user is not part of an organization, 'org_non_member' is set to true
77
- org_non_member {
78
- input.object.org_owner != " "
79
- # Identify if the user is in the org
80
- roles := input.subject.roles
81
- every role in roles {
82
- not role.org[input.object.org_owner]
83
- }
50
+ org_members := { orgID |
51
+ input.subject.roles[_].org[orgID]
84
52
}
85
53
86
- # org is two rules that equate to the following
87
- # if org_non_member { return {false} }
88
- # else { org_member }
89
- #
90
- # It is important both rules cannot be true, as the `org` rules cannot produce multiple outputs.
91
- default org = {}
92
- org = set {
93
- # We have to do !org_non_member because rego rules must evaluate to 'true'
94
- # to have a value set.
95
- # So we do "not not-org-member" which means "subject is in org"
96
- not org_non_member
97
- set = org_member
54
+ default org = 0
55
+ org := num {
56
+ orgPerms := { id: num |
57
+ id := org_members[_]
58
+ set := { x |
59
+ perm := input.subject.roles[_].org[id][_]
60
+ perm.action in [input.action, " *" ]
61
+ perm.resource_type in [input.object.type, " *" ]
62
+ x := bool_flip (perm.negate)
63
+ }
64
+ num := number (set)
65
+ }
66
+
67
+ num := orgPerms[input.object.org_owner]
98
68
}
99
69
100
- org = set {
101
- org_non_member
102
- set = {false }
70
+ # 'org_mem' is set to true if the user is an org member
71
+ # or if the object has no org.
72
+ org_mem := true {
73
+ input.object.org_owner != " "
74
+ input.object.org_owner in org_members
103
75
}
104
76
105
- # The allow block is quite simple. Any set with `false` cascades down in levels.
106
- # Authorization looks for any `allow` statement that is true. Multiple can be true!
107
- # Note that the absence of `allow` means "unauthorized".
108
- # An explicit `"allow": true` is required.
109
-
110
- # site allow
111
- allow {
112
- # No site wide deny
113
- not false in site
114
- # And all permissions are positive
115
- site[_]
77
+ org_mem := true {
78
+ input.object.org_owner == " "
116
79
}
117
80
118
- # OR
81
+ default user = 0
82
+ user := num {
83
+ input.subject.id = input.object.owner
84
+ # relevent are all the permissions that affect the given unknown object
85
+ allow := { x |
86
+ perm := input.subject.roles[_].user[_]
87
+ perm.action in [input.action, " *" ]
88
+ perm.resource_type in [input.object.type, " *" ]
89
+ x := bool_flip (perm.negate)
90
+ }
91
+ num := number (allow)
92
+ }
119
93
120
- # org allow
94
+ default allow = false
95
+ # Site
121
96
allow {
122
- # No site or org deny
123
- not false in site
124
- not false in org
125
- # And all permissions are positive
126
- org[_]
97
+ site = 1
127
98
}
128
99
129
- # OR
100
+ # Org
101
+ allow {
102
+ not site = - 1
103
+ org = 1
104
+ }
130
105
131
- # user allow
106
+ # User
132
107
allow {
133
- # No site, org, or user deny
134
- not false in site
135
- not false in org
136
- not false in user
137
- # And all permissions are positive
138
- user[_]
108
+ not site = - 1
109
+ not org = - 1
110
+ org_mem
111
+ user = 1
139
112
}
0 commit comments