chore: add built in organization roles to match site (#13938)
* chore: add built in organization roles to match site Added org user admin, org template admin, and org auditor
This commit is contained in:
@@ -103,7 +103,7 @@ func TestCheckPermissions(t *testing.T) {
|
||||
Client: orgAdminClient,
|
||||
UserID: orgAdminUser.ID,
|
||||
Check: map[string]bool{
|
||||
readAllUsers: false,
|
||||
readAllUsers: true,
|
||||
readMyself: true,
|
||||
readOwnWorkspaces: true,
|
||||
readOrgWorkspaces: true,
|
||||
|
||||
+10
-7
@@ -33,20 +33,23 @@ func TestAddMember(t *testing.T) {
|
||||
// Make a user not in the second organization
|
||||
_, user := coderdtest.CreateAnotherUser(t, owner, first.OrganizationID)
|
||||
|
||||
members, err := owner.OrganizationMembers(ctx, org.ID)
|
||||
// Use scoped user admin in org to add the user
|
||||
client, userAdmin := coderdtest.CreateAnotherUser(t, owner, org.ID, rbac.ScopedRoleOrgUserAdmin(org.ID))
|
||||
|
||||
members, err := client.OrganizationMembers(ctx, org.ID)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, members, 1) // Verify just the 1 member
|
||||
require.Len(t, members, 2) // Verify the 2 members at the start
|
||||
|
||||
// Add user to org
|
||||
_, err = owner.PostOrganizationMember(ctx, org.ID, user.Username)
|
||||
_, err = client.PostOrganizationMember(ctx, org.ID, user.Username)
|
||||
require.NoError(t, err)
|
||||
|
||||
members, err = owner.OrganizationMembers(ctx, org.ID)
|
||||
members, err = client.OrganizationMembers(ctx, org.ID)
|
||||
require.NoError(t, err)
|
||||
// Owner + new member
|
||||
require.Len(t, members, 2)
|
||||
// Owner + user admin + new member
|
||||
require.Len(t, members, 3)
|
||||
require.ElementsMatch(t,
|
||||
[]uuid.UUID{first.UserID, user.ID},
|
||||
[]uuid.UUID{first.UserID, user.ID, userAdmin.ID},
|
||||
db2sdk.List(members, onlyIDs))
|
||||
})
|
||||
|
||||
|
||||
+102
-11
@@ -27,8 +27,11 @@ const (
|
||||
customSiteRole string = "custom-site-role"
|
||||
customOrganizationRole string = "custom-organization-role"
|
||||
|
||||
orgAdmin string = "organization-admin"
|
||||
orgMember string = "organization-member"
|
||||
orgAdmin string = "organization-admin"
|
||||
orgMember string = "organization-member"
|
||||
orgAuditor string = "organization-auditor"
|
||||
orgUserAdmin string = "organization-user-admin"
|
||||
orgTemplateAdmin string = "organization-template-admin"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -144,18 +147,38 @@ func RoleOrgMember() string {
|
||||
return orgMember
|
||||
}
|
||||
|
||||
func RoleOrgAuditor() string {
|
||||
return orgAuditor
|
||||
}
|
||||
|
||||
func RoleOrgUserAdmin() string {
|
||||
return orgUserAdmin
|
||||
}
|
||||
|
||||
func RoleOrgTemplateAdmin() string {
|
||||
return orgTemplateAdmin
|
||||
}
|
||||
|
||||
// ScopedRoleOrgAdmin is the org role with the organization ID
|
||||
// Deprecated This was used before organization scope was included as a
|
||||
// field in all user facing APIs. Usage of 'ScopedRoleOrgAdmin()' is preferred.
|
||||
func ScopedRoleOrgAdmin(organizationID uuid.UUID) RoleIdentifier {
|
||||
return RoleIdentifier{Name: orgAdmin, OrganizationID: organizationID}
|
||||
return RoleIdentifier{Name: RoleOrgAdmin(), OrganizationID: organizationID}
|
||||
}
|
||||
|
||||
// ScopedRoleOrgMember is the org role with the organization ID
|
||||
// Deprecated This was used before organization scope was included as a
|
||||
// field in all user facing APIs. Usage of 'ScopedRoleOrgMember()' is preferred.
|
||||
func ScopedRoleOrgMember(organizationID uuid.UUID) RoleIdentifier {
|
||||
return RoleIdentifier{Name: orgMember, OrganizationID: organizationID}
|
||||
return RoleIdentifier{Name: RoleOrgMember(), OrganizationID: organizationID}
|
||||
}
|
||||
|
||||
func ScopedRoleOrgAuditor(organizationID uuid.UUID) RoleIdentifier {
|
||||
return RoleIdentifier{Name: RoleOrgAuditor(), OrganizationID: organizationID}
|
||||
}
|
||||
|
||||
func ScopedRoleOrgUserAdmin(organizationID uuid.UUID) RoleIdentifier {
|
||||
return RoleIdentifier{Name: RoleOrgUserAdmin(), OrganizationID: organizationID}
|
||||
}
|
||||
|
||||
func ScopedRoleOrgTemplateAdmin(organizationID uuid.UUID) RoleIdentifier {
|
||||
return RoleIdentifier{Name: RoleOrgTemplateAdmin(), OrganizationID: organizationID}
|
||||
}
|
||||
|
||||
func allPermsExcept(excepts ...Objecter) []Permission {
|
||||
@@ -365,7 +388,11 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
|
||||
return Role{
|
||||
Identifier: RoleIdentifier{Name: orgAdmin, OrganizationID: organizationID},
|
||||
DisplayName: "Organization Admin",
|
||||
Site: []Permission{},
|
||||
Site: Permissions(map[string][]policy.Action{
|
||||
// To assign organization members, we need to be able to read
|
||||
// users at the site wide to know they exist.
|
||||
ResourceUser.Type: {policy.ActionRead},
|
||||
}),
|
||||
Org: map[string][]Permission{
|
||||
// Org admins should not have workspace exec perms.
|
||||
organizationID.String(): append(allPermsExcept(ResourceWorkspace, ResourceWorkspaceDormant, ResourceAssignRole), Permissions(map[string][]policy.Action{
|
||||
@@ -377,8 +404,7 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
|
||||
}
|
||||
},
|
||||
|
||||
// orgMember has an empty set of permissions, this just implies their membership
|
||||
// in an organization.
|
||||
// orgMember is an implied role to any member in an organization.
|
||||
orgMember: func(organizationID uuid.UUID) Role {
|
||||
return Role{
|
||||
Identifier: RoleIdentifier{Name: orgMember, OrganizationID: organizationID},
|
||||
@@ -406,6 +432,59 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
|
||||
},
|
||||
}
|
||||
},
|
||||
orgAuditor: func(organizationID uuid.UUID) Role {
|
||||
return Role{
|
||||
Identifier: RoleIdentifier{Name: orgAuditor, OrganizationID: organizationID},
|
||||
DisplayName: "Organization Auditor",
|
||||
Site: []Permission{},
|
||||
Org: map[string][]Permission{
|
||||
organizationID.String(): Permissions(map[string][]policy.Action{
|
||||
ResourceAuditLog.Type: {policy.ActionRead},
|
||||
}),
|
||||
},
|
||||
User: []Permission{},
|
||||
}
|
||||
},
|
||||
orgUserAdmin: func(organizationID uuid.UUID) Role {
|
||||
// Manages organization members and groups.
|
||||
return Role{
|
||||
Identifier: RoleIdentifier{Name: orgUserAdmin, OrganizationID: organizationID},
|
||||
DisplayName: "Organization User Admin",
|
||||
Site: Permissions(map[string][]policy.Action{
|
||||
// To assign organization members, we need to be able to read
|
||||
// users at the site wide to know they exist.
|
||||
ResourceUser.Type: {policy.ActionRead},
|
||||
}),
|
||||
Org: map[string][]Permission{
|
||||
organizationID.String(): Permissions(map[string][]policy.Action{
|
||||
// Assign, remove, and read roles in the organization.
|
||||
ResourceAssignOrgRole.Type: {policy.ActionAssign, policy.ActionDelete, policy.ActionRead},
|
||||
ResourceOrganizationMember.Type: {policy.ActionCreate, policy.ActionRead, policy.ActionUpdate, policy.ActionDelete},
|
||||
ResourceGroup.Type: ResourceGroup.AvailableActions(),
|
||||
}),
|
||||
},
|
||||
User: []Permission{},
|
||||
}
|
||||
},
|
||||
orgTemplateAdmin: func(organizationID uuid.UUID) Role {
|
||||
// Manages organization members and groups.
|
||||
return Role{
|
||||
Identifier: RoleIdentifier{Name: orgTemplateAdmin, OrganizationID: organizationID},
|
||||
DisplayName: "Organization Template Admin",
|
||||
Site: []Permission{},
|
||||
Org: map[string][]Permission{
|
||||
organizationID.String(): Permissions(map[string][]policy.Action{
|
||||
ResourceTemplate.Type: {policy.ActionCreate, policy.ActionRead, policy.ActionUpdate, policy.ActionDelete, policy.ActionViewInsights},
|
||||
ResourceFile.Type: {policy.ActionCreate, policy.ActionRead},
|
||||
ResourceWorkspace.Type: {policy.ActionRead},
|
||||
// Assigning template perms requires this permission.
|
||||
ResourceOrganizationMember.Type: {policy.ActionRead},
|
||||
ResourceGroup.Type: {policy.ActionRead},
|
||||
}),
|
||||
},
|
||||
User: []Permission{},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -421,6 +500,9 @@ var assignRoles = map[string]map[string]bool{
|
||||
member: true,
|
||||
orgAdmin: true,
|
||||
orgMember: true,
|
||||
orgAuditor: true,
|
||||
orgUserAdmin: true,
|
||||
orgTemplateAdmin: true,
|
||||
templateAdmin: true,
|
||||
userAdmin: true,
|
||||
customSiteRole: true,
|
||||
@@ -432,6 +514,9 @@ var assignRoles = map[string]map[string]bool{
|
||||
member: true,
|
||||
orgAdmin: true,
|
||||
orgMember: true,
|
||||
orgAuditor: true,
|
||||
orgUserAdmin: true,
|
||||
orgTemplateAdmin: true,
|
||||
templateAdmin: true,
|
||||
userAdmin: true,
|
||||
customSiteRole: true,
|
||||
@@ -444,8 +529,14 @@ var assignRoles = map[string]map[string]bool{
|
||||
orgAdmin: {
|
||||
orgAdmin: true,
|
||||
orgMember: true,
|
||||
orgAuditor: true,
|
||||
orgUserAdmin: true,
|
||||
orgTemplateAdmin: true,
|
||||
customOrganizationRole: true,
|
||||
},
|
||||
orgUserAdmin: {
|
||||
orgMember: true,
|
||||
},
|
||||
}
|
||||
|
||||
// ExpandableRoles is any type that can be expanded into a []Role. This is implemented
|
||||
|
||||
+157
-113
@@ -14,12 +14,22 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/rbac/policy"
|
||||
)
|
||||
|
||||
type hasAuthSubjects interface {
|
||||
Subjects() []authSubject
|
||||
}
|
||||
|
||||
type authSubjectSet []authSubject
|
||||
|
||||
func (a authSubjectSet) Subjects() []authSubject { return a }
|
||||
|
||||
type authSubject struct {
|
||||
// Name is helpful for test assertions
|
||||
Name string
|
||||
Actor rbac.Subject
|
||||
}
|
||||
|
||||
func (a authSubject) Subjects() []authSubject { return []authSubject{a} }
|
||||
|
||||
// TestBuiltInRoles makes sure our built-in roles are valid by our own policy
|
||||
// rules. If this is incorrect, that is a mistake.
|
||||
func TestBuiltInRoles(t *testing.T) {
|
||||
@@ -89,6 +99,8 @@ func TestRolePermissions(t *testing.T) {
|
||||
currentUser := uuid.New()
|
||||
adminID := uuid.New()
|
||||
templateAdminID := uuid.New()
|
||||
userAdminID := uuid.New()
|
||||
auditorID := uuid.New()
|
||||
orgID := uuid.New()
|
||||
otherOrg := uuid.New()
|
||||
workspaceID := uuid.New()
|
||||
@@ -102,17 +114,30 @@ func TestRolePermissions(t *testing.T) {
|
||||
orgMemberMe := authSubject{Name: "org_member_me", Actor: rbac.Subject{ID: currentUser.String(), Roles: rbac.RoleIdentifiers{rbac.RoleMember(), rbac.ScopedRoleOrgMember(orgID)}}}
|
||||
|
||||
owner := authSubject{Name: "owner", Actor: rbac.Subject{ID: adminID.String(), Roles: rbac.RoleIdentifiers{rbac.RoleMember(), rbac.RoleOwner()}}}
|
||||
templateAdmin := authSubject{Name: "template-admin", Actor: rbac.Subject{ID: templateAdminID.String(), Roles: rbac.RoleIdentifiers{rbac.RoleMember(), rbac.RoleTemplateAdmin()}}}
|
||||
userAdmin := authSubject{Name: "user-admin", Actor: rbac.Subject{ID: userAdminID.String(), Roles: rbac.RoleIdentifiers{rbac.RoleMember(), rbac.RoleUserAdmin()}}}
|
||||
|
||||
orgAdmin := authSubject{Name: "org_admin", Actor: rbac.Subject{ID: adminID.String(), Roles: rbac.RoleIdentifiers{rbac.RoleMember(), rbac.ScopedRoleOrgMember(orgID), rbac.ScopedRoleOrgAdmin(orgID)}}}
|
||||
orgAuditor := authSubject{Name: "org_auditor", Actor: rbac.Subject{ID: auditorID.String(), Roles: rbac.RoleIdentifiers{rbac.RoleMember(), rbac.ScopedRoleOrgMember(orgID), rbac.ScopedRoleOrgAuditor(orgID)}}}
|
||||
orgUserAdmin := authSubject{Name: "org_user_admin", Actor: rbac.Subject{ID: templateAdminID.String(), Roles: rbac.RoleIdentifiers{rbac.RoleMember(), rbac.ScopedRoleOrgMember(orgID), rbac.ScopedRoleOrgUserAdmin(orgID)}}}
|
||||
orgTemplateAdmin := authSubject{Name: "org_template_admin", Actor: rbac.Subject{ID: userAdminID.String(), Roles: rbac.RoleIdentifiers{rbac.RoleMember(), rbac.ScopedRoleOrgMember(orgID), rbac.ScopedRoleOrgTemplateAdmin(orgID)}}}
|
||||
setOrgNotMe := authSubjectSet{orgAdmin, orgAuditor, orgUserAdmin, orgTemplateAdmin}
|
||||
|
||||
otherOrgMember := authSubject{Name: "org_member_other", Actor: rbac.Subject{ID: uuid.NewString(), Roles: rbac.RoleIdentifiers{rbac.RoleMember(), rbac.ScopedRoleOrgMember(otherOrg)}}}
|
||||
otherOrgAdmin := authSubject{Name: "org_admin_other", Actor: rbac.Subject{ID: uuid.NewString(), Roles: rbac.RoleIdentifiers{rbac.RoleMember(), rbac.ScopedRoleOrgMember(otherOrg), rbac.ScopedRoleOrgAdmin(otherOrg)}}}
|
||||
|
||||
templateAdmin := authSubject{Name: "template-admin", Actor: rbac.Subject{ID: templateAdminID.String(), Roles: rbac.RoleIdentifiers{rbac.RoleMember(), rbac.RoleTemplateAdmin()}}}
|
||||
userAdmin := authSubject{Name: "user-admin", Actor: rbac.Subject{ID: templateAdminID.String(), Roles: rbac.RoleIdentifiers{rbac.RoleMember(), rbac.RoleUserAdmin()}}}
|
||||
otherOrgAuditor := authSubject{Name: "org_auditor_other", Actor: rbac.Subject{ID: adminID.String(), Roles: rbac.RoleIdentifiers{rbac.RoleMember(), rbac.ScopedRoleOrgMember(otherOrg), rbac.ScopedRoleOrgAuditor(otherOrg)}}}
|
||||
otherOrgUserAdmin := authSubject{Name: "org_user_admin_other", Actor: rbac.Subject{ID: adminID.String(), Roles: rbac.RoleIdentifiers{rbac.RoleMember(), rbac.ScopedRoleOrgMember(otherOrg), rbac.ScopedRoleOrgUserAdmin(otherOrg)}}}
|
||||
otherOrgTemplateAdmin := authSubject{Name: "org_template_admin_other", Actor: rbac.Subject{ID: adminID.String(), Roles: rbac.RoleIdentifiers{rbac.RoleMember(), rbac.ScopedRoleOrgMember(otherOrg), rbac.ScopedRoleOrgTemplateAdmin(otherOrg)}}}
|
||||
setOtherOrg := authSubjectSet{otherOrgMember, otherOrgAdmin, otherOrgAuditor, otherOrgUserAdmin, otherOrgTemplateAdmin}
|
||||
|
||||
// requiredSubjects are required to be asserted in each test case. This is
|
||||
// to make sure one is not forgotten.
|
||||
requiredSubjects := []authSubject{memberMe, owner, orgMemberMe, orgAdmin, otherOrgAdmin, otherOrgMember, templateAdmin, userAdmin}
|
||||
requiredSubjects := []authSubject{
|
||||
memberMe, owner,
|
||||
orgMemberMe, orgAdmin,
|
||||
otherOrgAdmin, otherOrgMember, orgAuditor, orgUserAdmin, orgTemplateAdmin,
|
||||
templateAdmin, userAdmin, otherOrgAuditor, otherOrgUserAdmin, otherOrgTemplateAdmin,
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
// Name the test case to better locate the failing test case.
|
||||
@@ -125,24 +150,27 @@ func TestRolePermissions(t *testing.T) {
|
||||
// "false".
|
||||
// true: Subjects who Authorize should return no error
|
||||
// false: Subjects who Authorize should return forbidden.
|
||||
AuthorizeMap map[bool][]authSubject
|
||||
AuthorizeMap map[bool][]hasAuthSubjects
|
||||
}{
|
||||
{
|
||||
Name: "MyUser",
|
||||
Actions: []policy.Action{policy.ActionRead},
|
||||
Resource: rbac.ResourceUserObject(currentUser),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
true: {orgMemberMe, owner, memberMe, templateAdmin, userAdmin},
|
||||
false: {otherOrgMember, otherOrgAdmin, orgAdmin},
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {orgMemberMe, owner, memberMe, templateAdmin, userAdmin, orgUserAdmin, otherOrgAdmin, otherOrgUserAdmin, orgAdmin},
|
||||
false: {
|
||||
orgTemplateAdmin, orgAuditor,
|
||||
otherOrgMember, otherOrgAuditor, otherOrgTemplateAdmin,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "AUser",
|
||||
Actions: []policy.Action{policy.ActionCreate, policy.ActionUpdate, policy.ActionDelete},
|
||||
Resource: rbac.ResourceUser,
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, userAdmin},
|
||||
false: {memberMe, orgMemberMe, orgAdmin, otherOrgMember, otherOrgAdmin, templateAdmin},
|
||||
false: {setOtherOrg, setOrgNotMe, memberMe, orgMemberMe, templateAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -150,9 +178,9 @@ func TestRolePermissions(t *testing.T) {
|
||||
// When creating the WithID won't be set, but it does not change the result.
|
||||
Actions: []policy.Action{policy.ActionRead},
|
||||
Resource: rbac.ResourceWorkspace.WithID(workspaceID).InOrg(orgID).WithOwner(currentUser.String()),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
true: {owner, orgMemberMe, orgAdmin, templateAdmin},
|
||||
false: {memberMe, otherOrgAdmin, otherOrgMember, userAdmin},
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgMemberMe, orgAdmin, templateAdmin, orgTemplateAdmin},
|
||||
false: {setOtherOrg, memberMe, userAdmin, orgAuditor, orgUserAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -160,9 +188,9 @@ func TestRolePermissions(t *testing.T) {
|
||||
// When creating the WithID won't be set, but it does not change the result.
|
||||
Actions: []policy.Action{policy.ActionCreate, policy.ActionUpdate, policy.ActionDelete},
|
||||
Resource: rbac.ResourceWorkspace.WithID(workspaceID).InOrg(orgID).WithOwner(currentUser.String()),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgMemberMe, orgAdmin},
|
||||
false: {memberMe, otherOrgAdmin, otherOrgMember, userAdmin, templateAdmin},
|
||||
false: {setOtherOrg, memberMe, userAdmin, templateAdmin, orgTemplateAdmin, orgUserAdmin, orgAuditor},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -170,9 +198,9 @@ func TestRolePermissions(t *testing.T) {
|
||||
// When creating the WithID won't be set, but it does not change the result.
|
||||
Actions: []policy.Action{policy.ActionSSH},
|
||||
Resource: rbac.ResourceWorkspace.WithID(workspaceID).InOrg(orgID).WithOwner(currentUser.String()),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgMemberMe},
|
||||
false: {orgAdmin, memberMe, otherOrgAdmin, otherOrgMember, templateAdmin, userAdmin},
|
||||
false: {setOtherOrg, setOrgNotMe, memberMe, templateAdmin, userAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -180,98 +208,100 @@ func TestRolePermissions(t *testing.T) {
|
||||
// When creating the WithID won't be set, but it does not change the result.
|
||||
Actions: []policy.Action{policy.ActionApplicationConnect},
|
||||
Resource: rbac.ResourceWorkspace.WithID(workspaceID).InOrg(orgID).WithOwner(currentUser.String()),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgMemberMe},
|
||||
false: {memberMe, otherOrgAdmin, otherOrgMember, templateAdmin, userAdmin, orgAdmin},
|
||||
false: {setOtherOrg, setOrgNotMe, memberMe, templateAdmin, userAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Templates",
|
||||
Actions: []policy.Action{policy.ActionCreate, policy.ActionUpdate, policy.ActionDelete, policy.ActionViewInsights},
|
||||
Resource: rbac.ResourceTemplate.WithID(templateID).InOrg(orgID),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
true: {owner, orgAdmin, templateAdmin},
|
||||
false: {memberMe, orgMemberMe, otherOrgAdmin, otherOrgMember, userAdmin},
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgAdmin, templateAdmin, orgTemplateAdmin},
|
||||
false: {setOtherOrg, orgAuditor, orgUserAdmin, memberMe, orgMemberMe, userAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "ReadTemplates",
|
||||
Actions: []policy.Action{policy.ActionRead},
|
||||
Resource: rbac.ResourceTemplate.InOrg(orgID),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
true: {owner, orgAdmin, templateAdmin},
|
||||
false: {memberMe, otherOrgAdmin, otherOrgMember, userAdmin, orgMemberMe},
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgAdmin, templateAdmin, orgTemplateAdmin},
|
||||
false: {setOtherOrg, orgAuditor, orgUserAdmin, memberMe, userAdmin, orgMemberMe},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Files",
|
||||
Actions: []policy.Action{policy.ActionCreate},
|
||||
Resource: rbac.ResourceFile.WithID(fileID),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
true: {owner, templateAdmin},
|
||||
false: {orgMemberMe, orgAdmin, memberMe, otherOrgAdmin, otherOrgMember, userAdmin},
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, templateAdmin},
|
||||
// Org template admins can only read org scoped files.
|
||||
// File scope is currently not org scoped :cry:
|
||||
false: {setOtherOrg, orgTemplateAdmin, orgMemberMe, orgAdmin, memberMe, userAdmin, orgAuditor, orgUserAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "MyFile",
|
||||
Actions: []policy.Action{policy.ActionCreate, policy.ActionRead},
|
||||
Resource: rbac.ResourceFile.WithID(fileID).WithOwner(currentUser.String()),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, memberMe, orgMemberMe, templateAdmin},
|
||||
false: {orgAdmin, otherOrgAdmin, otherOrgMember, userAdmin},
|
||||
false: {setOtherOrg, setOrgNotMe, userAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "CreateOrganizations",
|
||||
Actions: []policy.Action{policy.ActionCreate},
|
||||
Resource: rbac.ResourceOrganization,
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner},
|
||||
false: {orgAdmin, otherOrgAdmin, otherOrgMember, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
false: {setOtherOrg, setOrgNotMe, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Organizations",
|
||||
Actions: []policy.Action{policy.ActionUpdate, policy.ActionDelete},
|
||||
Resource: rbac.ResourceOrganization.WithID(orgID).InOrg(orgID),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgAdmin},
|
||||
false: {otherOrgAdmin, otherOrgMember, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
false: {setOtherOrg, orgTemplateAdmin, orgUserAdmin, orgAuditor, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "ReadOrganizations",
|
||||
Actions: []policy.Action{policy.ActionRead},
|
||||
Resource: rbac.ResourceOrganization.WithID(orgID).InOrg(orgID),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
true: {owner, orgAdmin, orgMemberMe, templateAdmin},
|
||||
false: {otherOrgAdmin, otherOrgMember, memberMe, userAdmin},
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgAdmin, orgMemberMe, templateAdmin, orgTemplateAdmin, orgAuditor, orgUserAdmin},
|
||||
false: {setOtherOrg, memberMe, userAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "CreateCustomRole",
|
||||
Actions: []policy.Action{policy.ActionCreate},
|
||||
Resource: rbac.ResourceAssignRole,
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner},
|
||||
false: {userAdmin, orgAdmin, orgMemberMe, otherOrgAdmin, otherOrgMember, memberMe, templateAdmin},
|
||||
false: {setOtherOrg, setOrgNotMe, userAdmin, orgMemberMe, memberMe, templateAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "RoleAssignment",
|
||||
Actions: []policy.Action{policy.ActionAssign, policy.ActionDelete},
|
||||
Resource: rbac.ResourceAssignRole,
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, userAdmin},
|
||||
false: {orgAdmin, orgMemberMe, otherOrgAdmin, otherOrgMember, memberMe, templateAdmin},
|
||||
false: {setOtherOrg, setOrgNotMe, orgMemberMe, memberMe, templateAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "ReadRoleAssignment",
|
||||
Actions: []policy.Action{policy.ActionRead},
|
||||
Resource: rbac.ResourceAssignRole,
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
true: {owner, orgAdmin, orgMemberMe, otherOrgAdmin, otherOrgMember, memberMe, templateAdmin, userAdmin},
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {setOtherOrg, setOrgNotMe, owner, orgMemberMe, memberMe, templateAdmin, userAdmin},
|
||||
false: {},
|
||||
},
|
||||
},
|
||||
@@ -279,63 +309,63 @@ func TestRolePermissions(t *testing.T) {
|
||||
Name: "OrgRoleAssignment",
|
||||
Actions: []policy.Action{policy.ActionAssign, policy.ActionDelete},
|
||||
Resource: rbac.ResourceAssignOrgRole.InOrg(orgID),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
true: {owner, orgAdmin, userAdmin},
|
||||
false: {orgMemberMe, otherOrgAdmin, otherOrgMember, memberMe, templateAdmin},
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgAdmin, userAdmin, orgUserAdmin},
|
||||
false: {setOtherOrg, orgMemberMe, memberMe, templateAdmin, orgTemplateAdmin, orgAuditor},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "CreateOrgRoleAssignment",
|
||||
Actions: []policy.Action{policy.ActionCreate},
|
||||
Resource: rbac.ResourceAssignOrgRole.InOrg(orgID),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgAdmin},
|
||||
false: {orgMemberMe, otherOrgAdmin, otherOrgMember, memberMe, templateAdmin, userAdmin},
|
||||
false: {setOtherOrg, orgUserAdmin, orgTemplateAdmin, orgAuditor, orgMemberMe, memberMe, templateAdmin, userAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "ReadOrgRoleAssignment",
|
||||
Actions: []policy.Action{policy.ActionRead},
|
||||
Resource: rbac.ResourceAssignOrgRole.InOrg(orgID),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
true: {owner, orgAdmin, orgMemberMe, userAdmin, userAdmin},
|
||||
false: {otherOrgAdmin, otherOrgMember, memberMe, templateAdmin},
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, setOrgNotMe, orgMemberMe, userAdmin},
|
||||
false: {setOtherOrg, memberMe, templateAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "APIKey",
|
||||
Actions: []policy.Action{policy.ActionCreate, policy.ActionRead, policy.ActionDelete, policy.ActionUpdate},
|
||||
Resource: rbac.ResourceApiKey.WithID(apiKeyID).WithOwner(currentUser.String()),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgMemberMe, memberMe},
|
||||
false: {orgAdmin, otherOrgAdmin, otherOrgMember, templateAdmin, userAdmin},
|
||||
false: {setOtherOrg, setOrgNotMe, templateAdmin, userAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "UserData",
|
||||
Actions: []policy.Action{policy.ActionReadPersonal, policy.ActionUpdatePersonal},
|
||||
Resource: rbac.ResourceUserObject(currentUser),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgMemberMe, memberMe, userAdmin},
|
||||
false: {orgAdmin, otherOrgAdmin, otherOrgMember, templateAdmin},
|
||||
false: {setOtherOrg, setOrgNotMe, templateAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "ManageOrgMember",
|
||||
Actions: []policy.Action{policy.ActionCreate, policy.ActionUpdate, policy.ActionDelete},
|
||||
Resource: rbac.ResourceOrganizationMember.WithID(currentUser).InOrg(orgID).WithOwner(currentUser.String()),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
true: {owner, orgAdmin, userAdmin},
|
||||
false: {orgMemberMe, memberMe, otherOrgAdmin, otherOrgMember, templateAdmin},
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgAdmin, userAdmin, orgUserAdmin},
|
||||
false: {setOtherOrg, orgTemplateAdmin, orgAuditor, orgMemberMe, memberMe, templateAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "ReadOrgMember",
|
||||
Actions: []policy.Action{policy.ActionRead},
|
||||
Resource: rbac.ResourceOrganizationMember.WithID(currentUser).InOrg(orgID).WithOwner(currentUser.String()),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
true: {owner, orgAdmin, userAdmin, orgMemberMe, templateAdmin},
|
||||
false: {memberMe, otherOrgAdmin, otherOrgMember},
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgAdmin, userAdmin, orgMemberMe, templateAdmin, orgUserAdmin, orgTemplateAdmin},
|
||||
false: {memberMe, setOtherOrg, orgAuditor},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -346,54 +376,54 @@ func TestRolePermissions(t *testing.T) {
|
||||
orgID.String(): {policy.ActionRead},
|
||||
}),
|
||||
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
true: {owner, orgAdmin, orgMemberMe, templateAdmin},
|
||||
false: {memberMe, otherOrgAdmin, otherOrgMember, userAdmin},
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgAdmin, orgMemberMe, templateAdmin, orgUserAdmin, orgTemplateAdmin, orgAuditor},
|
||||
false: {setOtherOrg, memberMe, userAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Groups",
|
||||
Actions: []policy.Action{policy.ActionCreate, policy.ActionDelete, policy.ActionUpdate},
|
||||
Resource: rbac.ResourceGroup.WithID(groupID).InOrg(orgID),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
true: {owner, orgAdmin, userAdmin},
|
||||
false: {memberMe, otherOrgAdmin, orgMemberMe, otherOrgMember, templateAdmin},
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgAdmin, userAdmin, orgUserAdmin},
|
||||
false: {setOtherOrg, memberMe, orgMemberMe, templateAdmin, orgTemplateAdmin, orgAuditor},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "GroupsRead",
|
||||
Actions: []policy.Action{policy.ActionRead},
|
||||
Resource: rbac.ResourceGroup.WithID(groupID).InOrg(orgID),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
true: {owner, orgAdmin, userAdmin, templateAdmin},
|
||||
false: {memberMe, otherOrgAdmin, orgMemberMe, otherOrgMember},
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgAdmin, userAdmin, templateAdmin, orgTemplateAdmin, orgUserAdmin},
|
||||
false: {setOtherOrg, memberMe, orgMemberMe, orgAuditor},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "WorkspaceDormant",
|
||||
Actions: append(crud, policy.ActionWorkspaceStop),
|
||||
Resource: rbac.ResourceWorkspaceDormant.WithID(uuid.New()).InOrg(orgID).WithOwner(memberMe.Actor.ID),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {orgMemberMe, orgAdmin, owner},
|
||||
false: {userAdmin, otherOrgAdmin, otherOrgMember, memberMe, templateAdmin},
|
||||
false: {setOtherOrg, userAdmin, memberMe, templateAdmin, orgTemplateAdmin, orgUserAdmin, orgAuditor},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "WorkspaceDormantUse",
|
||||
Actions: []policy.Action{policy.ActionWorkspaceStart, policy.ActionApplicationConnect, policy.ActionSSH},
|
||||
Resource: rbac.ResourceWorkspaceDormant.WithID(uuid.New()).InOrg(orgID).WithOwner(memberMe.Actor.ID),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {},
|
||||
false: {memberMe, orgAdmin, userAdmin, otherOrgAdmin, otherOrgMember, orgMemberMe, owner, templateAdmin},
|
||||
false: {setOtherOrg, setOrgNotMe, memberMe, userAdmin, orgMemberMe, owner, templateAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "WorkspaceBuild",
|
||||
Actions: []policy.Action{policy.ActionWorkspaceStart, policy.ActionWorkspaceStop},
|
||||
Resource: rbac.ResourceWorkspace.WithID(uuid.New()).InOrg(orgID).WithOwner(memberMe.Actor.ID),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgAdmin, orgMemberMe},
|
||||
false: {userAdmin, otherOrgAdmin, otherOrgMember, templateAdmin, memberMe},
|
||||
false: {setOtherOrg, userAdmin, templateAdmin, memberMe, orgTemplateAdmin, orgUserAdmin, orgAuditor},
|
||||
},
|
||||
},
|
||||
// Some admin style resources
|
||||
@@ -401,81 +431,81 @@ func TestRolePermissions(t *testing.T) {
|
||||
Name: "Licenses",
|
||||
Actions: []policy.Action{policy.ActionCreate, policy.ActionRead, policy.ActionDelete},
|
||||
Resource: rbac.ResourceLicense,
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner},
|
||||
false: {orgAdmin, otherOrgAdmin, otherOrgMember, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
false: {setOtherOrg, setOrgNotMe, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "DeploymentStats",
|
||||
Actions: []policy.Action{policy.ActionRead},
|
||||
Resource: rbac.ResourceDeploymentStats,
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner},
|
||||
false: {orgAdmin, otherOrgAdmin, otherOrgMember, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
false: {setOtherOrg, setOrgNotMe, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "DeploymentConfig",
|
||||
Actions: []policy.Action{policy.ActionRead, policy.ActionUpdate},
|
||||
Resource: rbac.ResourceDeploymentConfig,
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner},
|
||||
false: {orgAdmin, otherOrgAdmin, otherOrgMember, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
false: {setOtherOrg, setOrgNotMe, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "DebugInfo",
|
||||
Actions: []policy.Action{policy.ActionRead},
|
||||
Resource: rbac.ResourceDebugInfo,
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner},
|
||||
false: {orgAdmin, otherOrgAdmin, otherOrgMember, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
false: {setOtherOrg, setOrgNotMe, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Replicas",
|
||||
Actions: []policy.Action{policy.ActionRead},
|
||||
Resource: rbac.ResourceReplicas,
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner},
|
||||
false: {orgAdmin, otherOrgAdmin, otherOrgMember, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
false: {setOtherOrg, setOrgNotMe, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TailnetCoordinator",
|
||||
Actions: crud,
|
||||
Resource: rbac.ResourceTailnetCoordinator,
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner},
|
||||
false: {orgAdmin, otherOrgAdmin, otherOrgMember, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
false: {setOtherOrg, setOrgNotMe, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "AuditLogs",
|
||||
Actions: []policy.Action{policy.ActionRead, policy.ActionCreate},
|
||||
Resource: rbac.ResourceAuditLog,
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner},
|
||||
false: {orgAdmin, otherOrgAdmin, otherOrgMember, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
false: {setOtherOrg, setOrgNotMe, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "ProvisionerDaemons",
|
||||
Actions: []policy.Action{policy.ActionCreate, policy.ActionUpdate, policy.ActionDelete},
|
||||
Resource: rbac.ResourceProvisionerDaemon.InOrg(orgID),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, templateAdmin, orgAdmin},
|
||||
false: {otherOrgAdmin, otherOrgMember, memberMe, orgMemberMe, userAdmin},
|
||||
false: {setOtherOrg, orgTemplateAdmin, orgUserAdmin, memberMe, orgMemberMe, userAdmin, orgAuditor},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "ProvisionerDaemonsRead",
|
||||
Actions: []policy.Action{policy.ActionRead},
|
||||
Resource: rbac.ResourceProvisionerDaemon.InOrg(orgID),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
// This should be fixed when multi-org goes live
|
||||
true: {owner, templateAdmin, orgAdmin, otherOrgAdmin, otherOrgMember, memberMe, orgMemberMe, userAdmin},
|
||||
true: {setOtherOrg, owner, templateAdmin, setOrgNotMe, memberMe, orgMemberMe, userAdmin},
|
||||
false: {},
|
||||
},
|
||||
},
|
||||
@@ -483,44 +513,44 @@ func TestRolePermissions(t *testing.T) {
|
||||
Name: "UserProvisionerDaemons",
|
||||
Actions: []policy.Action{policy.ActionCreate, policy.ActionUpdate, policy.ActionDelete},
|
||||
Resource: rbac.ResourceProvisionerDaemon.WithOwner(currentUser.String()).InOrg(orgID),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, templateAdmin, orgMemberMe, orgAdmin},
|
||||
false: {memberMe, otherOrgAdmin, otherOrgMember, userAdmin},
|
||||
false: {setOtherOrg, memberMe, userAdmin, orgTemplateAdmin, orgUserAdmin, orgAuditor},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "ProvisionerKeys",
|
||||
Actions: []policy.Action{policy.ActionCreate, policy.ActionRead, policy.ActionDelete},
|
||||
Resource: rbac.ResourceProvisionerKeys.InOrg(orgID),
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgAdmin},
|
||||
false: {otherOrgAdmin, otherOrgMember, memberMe, orgMemberMe, userAdmin, templateAdmin},
|
||||
false: {setOtherOrg, memberMe, orgMemberMe, userAdmin, templateAdmin, orgTemplateAdmin, orgUserAdmin, orgAuditor},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "System",
|
||||
Actions: crud,
|
||||
Resource: rbac.ResourceSystem,
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner},
|
||||
false: {orgAdmin, otherOrgAdmin, otherOrgMember, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
false: {setOtherOrg, setOrgNotMe, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Oauth2App",
|
||||
Actions: []policy.Action{policy.ActionCreate, policy.ActionUpdate, policy.ActionDelete},
|
||||
Resource: rbac.ResourceOauth2App,
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner},
|
||||
false: {orgAdmin, otherOrgAdmin, otherOrgMember, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
false: {setOtherOrg, setOrgNotMe, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Oauth2AppRead",
|
||||
Actions: []policy.Action{policy.ActionRead},
|
||||
Resource: rbac.ResourceOauth2App,
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
true: {owner, orgAdmin, otherOrgAdmin, otherOrgMember, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, setOrgNotMe, setOtherOrg, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
false: {},
|
||||
},
|
||||
},
|
||||
@@ -528,35 +558,35 @@ func TestRolePermissions(t *testing.T) {
|
||||
Name: "Oauth2AppSecret",
|
||||
Actions: crud,
|
||||
Resource: rbac.ResourceOauth2AppSecret,
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner},
|
||||
false: {orgAdmin, otherOrgAdmin, otherOrgMember, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
false: {setOrgNotMe, setOtherOrg, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Oauth2Token",
|
||||
Actions: []policy.Action{policy.ActionCreate, policy.ActionRead, policy.ActionDelete},
|
||||
Resource: rbac.ResourceOauth2AppCodeToken,
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner},
|
||||
false: {orgAdmin, otherOrgAdmin, otherOrgMember, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
false: {setOrgNotMe, setOtherOrg, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "WorkspaceProxy",
|
||||
Actions: []policy.Action{policy.ActionCreate, policy.ActionUpdate, policy.ActionDelete},
|
||||
Resource: rbac.ResourceWorkspaceProxy,
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner},
|
||||
false: {orgAdmin, otherOrgAdmin, otherOrgMember, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
false: {setOrgNotMe, setOtherOrg, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "WorkspaceProxyRead",
|
||||
Actions: []policy.Action{policy.ActionRead},
|
||||
Resource: rbac.ResourceWorkspaceProxy,
|
||||
AuthorizeMap: map[bool][]authSubject{
|
||||
true: {owner, orgAdmin, otherOrgAdmin, otherOrgMember, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, setOrgNotMe, setOtherOrg, memberMe, orgMemberMe, templateAdmin, userAdmin},
|
||||
false: {},
|
||||
},
|
||||
},
|
||||
@@ -590,8 +620,19 @@ func TestRolePermissions(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
for result, subjs := range c.AuthorizeMap {
|
||||
for result, sets := range c.AuthorizeMap {
|
||||
subjs := make([]authSubject, 0)
|
||||
for _, set := range sets {
|
||||
subjs = append(subjs, set.Subjects()...)
|
||||
}
|
||||
used := make(map[string]bool)
|
||||
|
||||
for _, subj := range subjs {
|
||||
if _, ok := used[subj.Name]; ok {
|
||||
assert.False(t, true, "duplicate subject %q", subj.Name)
|
||||
}
|
||||
used[subj.Name] = true
|
||||
|
||||
delete(remainingSubjs, subj.Name)
|
||||
msg := fmt.Sprintf("%s as %q doing %q on %q", c.Name, subj.Name, action, c.Resource.Type)
|
||||
// TODO: scopey
|
||||
@@ -704,6 +745,9 @@ func TestListRoles(t *testing.T) {
|
||||
require.ElementsMatch(t, []string{
|
||||
fmt.Sprintf("organization-admin:%s", orgID.String()),
|
||||
fmt.Sprintf("organization-member:%s", orgID.String()),
|
||||
fmt.Sprintf("organization-auditor:%s", orgID.String()),
|
||||
fmt.Sprintf("organization-user-admin:%s", orgID.String()),
|
||||
fmt.Sprintf("organization-template-admin:%s", orgID.String()),
|
||||
},
|
||||
orgRoleNames)
|
||||
}
|
||||
|
||||
+12
-3
@@ -64,7 +64,10 @@ func TestListRoles(t *testing.T) {
|
||||
return member.ListOrganizationRoles(ctx, owner.OrganizationID)
|
||||
},
|
||||
ExpectedRoles: convertRoles(map[rbac.RoleIdentifier]bool{
|
||||
{Name: codersdk.RoleOrganizationAdmin, OrganizationID: owner.OrganizationID}: false,
|
||||
{Name: codersdk.RoleOrganizationAdmin, OrganizationID: owner.OrganizationID}: false,
|
||||
{Name: codersdk.RoleOrganizationAuditor, OrganizationID: owner.OrganizationID}: false,
|
||||
{Name: codersdk.RoleOrganizationTemplateAdmin, OrganizationID: owner.OrganizationID}: false,
|
||||
{Name: codersdk.RoleOrganizationUserAdmin, OrganizationID: owner.OrganizationID}: false,
|
||||
}),
|
||||
},
|
||||
{
|
||||
@@ -93,7 +96,10 @@ func TestListRoles(t *testing.T) {
|
||||
return orgAdmin.ListOrganizationRoles(ctx, owner.OrganizationID)
|
||||
},
|
||||
ExpectedRoles: convertRoles(map[rbac.RoleIdentifier]bool{
|
||||
{Name: codersdk.RoleOrganizationAdmin, OrganizationID: owner.OrganizationID}: true,
|
||||
{Name: codersdk.RoleOrganizationAdmin, OrganizationID: owner.OrganizationID}: true,
|
||||
{Name: codersdk.RoleOrganizationAuditor, OrganizationID: owner.OrganizationID}: true,
|
||||
{Name: codersdk.RoleOrganizationTemplateAdmin, OrganizationID: owner.OrganizationID}: true,
|
||||
{Name: codersdk.RoleOrganizationUserAdmin, OrganizationID: owner.OrganizationID}: true,
|
||||
}),
|
||||
},
|
||||
{
|
||||
@@ -122,7 +128,10 @@ func TestListRoles(t *testing.T) {
|
||||
return client.ListOrganizationRoles(ctx, owner.OrganizationID)
|
||||
},
|
||||
ExpectedRoles: convertRoles(map[rbac.RoleIdentifier]bool{
|
||||
{Name: codersdk.RoleOrganizationAdmin, OrganizationID: owner.OrganizationID}: true,
|
||||
{Name: codersdk.RoleOrganizationAdmin, OrganizationID: owner.OrganizationID}: true,
|
||||
{Name: codersdk.RoleOrganizationAuditor, OrganizationID: owner.OrganizationID}: true,
|
||||
{Name: codersdk.RoleOrganizationTemplateAdmin, OrganizationID: owner.OrganizationID}: true,
|
||||
{Name: codersdk.RoleOrganizationUserAdmin, OrganizationID: owner.OrganizationID}: true,
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -49,10 +49,13 @@ func TestPostTemplateByOrganization(t *testing.T) {
|
||||
t.Run("Create", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
auditor := audit.NewMock()
|
||||
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true, Auditor: auditor})
|
||||
owner := coderdtest.CreateFirstUser(t, client)
|
||||
ownerClient := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true, Auditor: auditor})
|
||||
owner := coderdtest.CreateFirstUser(t, ownerClient)
|
||||
|
||||
// Use org scoped template admin
|
||||
client, _ := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID, rbac.ScopedRoleOrgTemplateAdmin(owner.OrganizationID))
|
||||
// By default, everyone in the org can read the template.
|
||||
user, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
|
||||
user, _ := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID)
|
||||
auditor.ResetLogs()
|
||||
|
||||
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil)
|
||||
@@ -79,14 +82,16 @@ func TestPostTemplateByOrganization(t *testing.T) {
|
||||
|
||||
t.Run("AlreadyExists", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, nil)
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
||||
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||
ownerClient := coderdtest.New(t, nil)
|
||||
owner := coderdtest.CreateFirstUser(t, ownerClient)
|
||||
client, _ := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID, rbac.ScopedRoleOrgTemplateAdmin(owner.OrganizationID))
|
||||
|
||||
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil)
|
||||
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
|
||||
_, err := client.CreateTemplate(ctx, user.OrganizationID, codersdk.CreateTemplateRequest{
|
||||
_, err := client.CreateTemplate(ctx, owner.OrganizationID, codersdk.CreateTemplateRequest{
|
||||
Name: template.Name,
|
||||
VersionID: version.ID,
|
||||
})
|
||||
|
||||
@@ -8,6 +8,9 @@ const (
|
||||
RoleUserAdmin string = "user-admin"
|
||||
RoleAuditor string = "auditor"
|
||||
|
||||
RoleOrganizationAdmin string = "organization-admin"
|
||||
RoleOrganizationMember string = "organization-member"
|
||||
RoleOrganizationAdmin string = "organization-admin"
|
||||
RoleOrganizationMember string = "organization-member"
|
||||
RoleOrganizationAuditor string = "organization-auditor"
|
||||
RoleOrganizationTemplateAdmin string = "organization-template-admin"
|
||||
RoleOrganizationUserAdmin string = "organization-user-admin"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user