Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d527f91

Browse files
authored
chore: update rego policy to respect user and organisation scopes (#19741)
Prior to this change, user and org scopes were always rejected
1 parent f3b152b commit d527f91

File tree

2 files changed

+60
-2
lines changed

2 files changed

+60
-2
lines changed

coderd/rbac/authz_internal_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,6 +1110,57 @@ func TestAuthorizeScope(t *testing.T) {
11101110
{resource: ResourceOrganization.WithID(defOrg)},
11111111
}),
11121112
)
1113+
1114+
// Test setting a scope on the org and the user level
1115+
// This is a bit of a contrived example that would not exist in practice.
1116+
// It combines a specific organization scope with a user scope to verify
1117+
// that both are applied.
1118+
// The test uses the `Owner` role, so by default the user can do everything.
1119+
user = Subject{
1120+
ID: "me",
1121+
Roles: Roles{
1122+
must(RoleByName(RoleOwner())),
1123+
// TODO: There is a __bug__ in the policy.rego. If the user is not a
1124+
// member of the organization, the org_scope fails. This happens because
1125+
// the org_allow_set uses "org_members".
1126+
// This is odd behavior, as without this membership role, the test for
1127+
// the workspace fails. Maybe scopes should just assume the user
1128+
// is a member.
1129+
must(RoleByName(ScopedRoleOrgMember(defOrg))),
1130+
},
1131+
Scope: Scope{
1132+
Role: Role{
1133+
Identifier: RoleIdentifier{
1134+
Name: "org-and-user-scope",
1135+
OrganizationID: defOrg,
1136+
},
1137+
DisplayName: "OrgAndUserScope",
1138+
Site: nil,
1139+
Org: map[string][]Permission{
1140+
defOrg.String(): Permissions(map[string][]policy.Action{
1141+
ResourceWorkspace.Type: {policy.ActionRead},
1142+
}),
1143+
},
1144+
User: Permissions(map[string][]policy.Action{
1145+
ResourceUser.Type: {policy.ActionRead},
1146+
}),
1147+
},
1148+
AllowIDList: []string{policy.WildcardSymbol},
1149+
},
1150+
}
1151+
1152+
testAuthorize(t, "OrgAndUserScope", user,
1153+
// Allowed by scope:
1154+
[]authTestCase{
1155+
{resource: ResourceWorkspace.InOrg(defOrg).WithOwner(user.ID), allow: true, actions: []policy.Action{policy.ActionRead}},
1156+
{resource: ResourceUser.WithOwner(user.ID), allow: true, actions: []policy.Action{policy.ActionRead}},
1157+
},
1158+
// Not allowed by scope:
1159+
[]authTestCase{
1160+
{resource: ResourceWorkspace.InOrg(defOrg).WithOwner(user.ID), allow: false, actions: []policy.Action{policy.ActionCreate}},
1161+
{resource: ResourceUser.WithOwner(user.ID), allow: false, actions: []policy.Action{policy.ActionUpdate}},
1162+
},
1163+
)
11131164
}
11141165

11151166
// cases applies a given function to all test cases. This makes generalities easier to create.

coderd/rbac/policy.rego

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,13 @@ site_allow(roles) := num if {
106106
# -------------------
107107

108108
# org_members is the list of organizations the actor is apart of.
109+
# TODO: Should there be an org_members for the scope too? Without it,
110+
# the membership is determined by the user's roles, not their scope permissions.
111+
# So if an owner (who is not an org member) has an org scope, that org scope
112+
# will fail to return '1'. Since we assume all non members return '-1' for org
113+
# level permissions.
114+
# Adding a second org_members set might affect the partial evaluation.
115+
# This is being left until org scopes are used.
109116
org_members := {orgID |
110117
input.subject.roles[_].org[orgID]
111118
}
@@ -116,7 +123,7 @@ default org := 0
116123
org := org_allow(input.subject.roles)
117124

118125
default scope_org := 0
119-
scope_org := org_allow([input.scope])
126+
scope_org := org_allow([input.subject.scope])
120127

121128
# org_allow_set is a helper function that iterates over all orgs that the actor
122129
# is a member of. For each organization it sets the numerical allow value
@@ -221,7 +228,7 @@ default user := 0
221228
user := user_allow(input.subject.roles)
222229

223230
default scope_user := 0
224-
scope_user := user_allow([input.scope])
231+
scope_user := user_allow([input.subject.scope])
225232

226233
user_allow(roles) := num if {
227234
input.object.owner != ""

0 commit comments

Comments
 (0)