From 3688b954973a8ada4ac13bdd817e3b42ca3619fd Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 26 May 2022 10:18:21 -0500 Subject: [PATCH 1/4] test: Unit test to assert role permissions This unit test allows for asserting which roles can perform actions on various objects. This is much easier than making unit tests to hit the api. --- coderd/rbac/builtin_test.go | 231 ++++++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) diff --git a/coderd/rbac/builtin_test.go b/coderd/rbac/builtin_test.go index 44f54a3626400..232705e41a713 100644 --- a/coderd/rbac/builtin_test.go +++ b/coderd/rbac/builtin_test.go @@ -1,9 +1,12 @@ package rbac_test import ( + "context" "fmt" "testing" + "github.com/stretchr/testify/assert" + "github.com/google/uuid" "github.com/stretchr/testify/require" @@ -11,6 +14,234 @@ import ( "github.com/coder/coder/coderd/rbac" ) +type authSubject struct { + // Name is helpful for test assertions + Name string + UserID string + Roles []string +} + +func TestRolePermissions(t *testing.T) { + t.Parallel() + + auth, err := rbac.NewAuthorizer() + require.NoError(t, err, "new rego authorizer") + + meID := uuid.New() + adminID := uuid.New() + orgID := uuid.New() + otherOrg := uuid.New() + + // Subjects to user + member := authSubject{Name: "member", UserID: meID.String(), Roles: []string{rbac.RoleMember()}} + admin := authSubject{Name: "admin", UserID: adminID.String(), Roles: []string{rbac.RoleMember(), rbac.RoleAdmin()}} + + orgMember := authSubject{Name: "org_member", UserID: meID.String(), Roles: []string{rbac.RoleMember(), rbac.RoleOrgMember(orgID)}} + orgAdmin := authSubject{Name: "org_admin", UserID: adminID.String(), Roles: []string{rbac.RoleMember(), rbac.RoleOrgMember(orgID), rbac.RoleOrgAdmin(orgID)}} + otherOrgMember := authSubject{Name: "other_org_member", UserID: uuid.NewString(), Roles: []string{rbac.RoleMember(), rbac.RoleOrgMember(otherOrg)}} + otherOrgAdmin := authSubject{Name: "other_org_admin", UserID: uuid.NewString(), Roles: []string{rbac.RoleMember(), rbac.RoleOrgMember(otherOrg), rbac.RoleOrgAdmin(otherOrg)}} + + allSubj := []authSubject{member, admin, orgMember, orgAdmin, otherOrgAdmin, otherOrgMember} + + testCases := []struct { + Name string + Resource rbac.Object + Actions []rbac.Action + Assertions map[bool][]authSubject + }{ + { + Name: "MyUser", + Actions: []rbac.Action{rbac.ActionRead}, + Resource: rbac.ResourceUser.WithID(meID.String()), + Assertions: map[bool][]authSubject{ + true: {admin, member, orgMember, orgAdmin, otherOrgMember, otherOrgAdmin}, + false: {}, + }, + }, + { + Name: "AUser", + Actions: []rbac.Action{rbac.ActionCreate, rbac.ActionUpdate, rbac.ActionDelete}, + Resource: rbac.ResourceUser, + Assertions: map[bool][]authSubject{ + true: {admin}, + false: {member, orgMember, orgAdmin, otherOrgMember, otherOrgAdmin}, + }, + }, + { + Name: "MyWorkspaceInOrg", + // When creating the WithID won't be set, but it does not change the result. + Actions: []rbac.Action{rbac.ActionCreate, rbac.ActionRead, rbac.ActionUpdate, rbac.ActionDelete}, + Resource: rbac.ResourceWorkspace.InOrg(orgID).WithOwner(meID.String()).WithID(uuid.NewString()), + Assertions: map[bool][]authSubject{ + true: {admin, orgMember, orgAdmin}, + false: {member, otherOrgAdmin, otherOrgMember}, + }, + }, + { + Name: "Templates", + Actions: []rbac.Action{rbac.ActionCreate, rbac.ActionUpdate, rbac.ActionDelete}, + Resource: rbac.ResourceTemplate.InOrg(orgID).WithID(uuid.NewString()), + Assertions: map[bool][]authSubject{ + true: {admin, orgAdmin}, + false: {member, orgMember, otherOrgAdmin, otherOrgMember}, + }, + }, + { + Name: "ReadTemplates", + Actions: []rbac.Action{rbac.ActionRead}, + Resource: rbac.ResourceTemplate.InOrg(orgID).WithID(uuid.NewString()), + Assertions: map[bool][]authSubject{ + true: {admin, orgMember, orgAdmin}, + false: {member, otherOrgAdmin, otherOrgMember}, + }, + }, + { + Name: "Files", + Actions: []rbac.Action{rbac.ActionCreate}, + Resource: rbac.ResourceFile, + Assertions: map[bool][]authSubject{ + true: {admin}, + false: {orgMember, orgAdmin, member, otherOrgAdmin, otherOrgMember}, + }, + }, + { + Name: "MyFile", + Actions: []rbac.Action{rbac.ActionRead, rbac.ActionUpdate, rbac.ActionDelete}, + Resource: rbac.ResourceFile.WithID(uuid.NewString()).WithOwner(meID.String()), + Assertions: map[bool][]authSubject{ + true: {admin, member, orgMember}, + false: {orgAdmin, otherOrgAdmin, otherOrgMember}, + }, + }, + { + Name: "CreateOrganizations", + Actions: []rbac.Action{rbac.ActionCreate}, + Resource: rbac.ResourceOrganization, + Assertions: map[bool][]authSubject{ + true: {admin}, + false: {orgAdmin, otherOrgAdmin, otherOrgMember, member, orgMember}, + }, + }, + { + Name: "Organizations", + Actions: []rbac.Action{rbac.ActionUpdate, rbac.ActionDelete}, + Resource: rbac.ResourceOrganization.InOrg(orgID).WithID(orgID.String()), + Assertions: map[bool][]authSubject{ + true: {admin, orgAdmin}, + false: {otherOrgAdmin, otherOrgMember, member, orgMember}, + }, + }, + { + Name: "ReadOrganizations", + Actions: []rbac.Action{rbac.ActionRead}, + Resource: rbac.ResourceOrganization.InOrg(orgID).WithID(orgID.String()), + Assertions: map[bool][]authSubject{ + true: {admin, orgAdmin, orgMember}, + false: {otherOrgAdmin, otherOrgMember, member}, + }, + }, + { + Name: "RoleAssignment", + Actions: []rbac.Action{rbac.ActionCreate, rbac.ActionUpdate, rbac.ActionDelete}, + Resource: rbac.ResourceRoleAssignment, + Assertions: map[bool][]authSubject{ + true: {admin}, + false: {orgAdmin, orgMember, otherOrgAdmin, otherOrgMember, member}, + }, + }, + { + Name: "ReadRoleAssignment", + Actions: []rbac.Action{rbac.ActionRead}, + Resource: rbac.ResourceRoleAssignment, + Assertions: map[bool][]authSubject{ + true: {admin, orgAdmin, orgMember, otherOrgAdmin, otherOrgMember, member}, + false: {}, + }, + }, + { + Name: "OrgRoleAssignment", + Actions: []rbac.Action{rbac.ActionCreate, rbac.ActionUpdate, rbac.ActionDelete}, + Resource: rbac.ResourceOrgRoleAssignment.InOrg(orgID), + Assertions: map[bool][]authSubject{ + true: {admin, orgAdmin}, + false: {orgMember, otherOrgAdmin, otherOrgMember, member}, + }, + }, + { + Name: "ReadOrgRoleAssignment", + Actions: []rbac.Action{rbac.ActionRead}, + Resource: rbac.ResourceOrgRoleAssignment.InOrg(orgID), + Assertions: map[bool][]authSubject{ + true: {admin, orgAdmin, orgMember}, + false: {otherOrgAdmin, otherOrgMember, member}, + }, + }, + { + Name: "APIKey", + Actions: []rbac.Action{rbac.ActionCreate, rbac.ActionRead, rbac.ActionUpdate, rbac.ActionDelete}, + Resource: rbac.ResourceAPIKey.WithOwner(meID.String()).WithID(uuid.NewString()), + Assertions: map[bool][]authSubject{ + true: {admin, orgMember, member}, + false: {orgAdmin, otherOrgAdmin, otherOrgMember}, + }, + }, + { + Name: "UserData", + Actions: []rbac.Action{rbac.ActionCreate, rbac.ActionRead, rbac.ActionUpdate, rbac.ActionDelete}, + Resource: rbac.ResourceUserData.WithOwner(meID.String()).WithID(meID.String()), + Assertions: map[bool][]authSubject{ + true: {admin, orgMember, member}, + false: {orgAdmin, otherOrgAdmin, otherOrgMember}, + }, + }, + { + Name: "ManageOrgMember", + Actions: []rbac.Action{rbac.ActionCreate, rbac.ActionUpdate, rbac.ActionDelete}, + Resource: rbac.ResourceOrganizationMember.InOrg(orgID).WithID(uuid.NewString()), + Assertions: map[bool][]authSubject{ + true: {admin, orgAdmin}, + false: {orgMember, member, otherOrgAdmin, otherOrgMember}, + }, + }, + { + Name: "ReadOrgMember", + Actions: []rbac.Action{rbac.ActionRead}, + Resource: rbac.ResourceOrganizationMember.InOrg(orgID).WithID(uuid.NewString()), + Assertions: map[bool][]authSubject{ + true: {admin, orgAdmin, orgMember}, + false: {member, otherOrgAdmin, otherOrgMember}, + }, + }, + } + + for _, c := range testCases { + c := c + t.Run(c.Name, func(t *testing.T) { + t.Parallel() + remainingSubjs := make(map[string]struct{}) + for _, subj := range allSubj { + remainingSubjs[subj.Name] = struct{}{} + } + + for _, action := range c.Actions { + for result, subjs := range c.Assertions { + for _, subj := range subjs { + delete(remainingSubjs, subj.Name) + msg := fmt.Sprintf("%s as %q doing %q on %q", c.Name, subj.Name, action, c.Resource.Type) + err := auth.ByRoleName(context.Background(), subj.UserID, subj.Roles, action, c.Resource) + if result { + assert.NoError(t, err, fmt.Sprintf("Should pass: %s", msg)) + } else { + assert.ErrorContains(t, err, "forbidden", fmt.Sprintf("Should fail: %s", msg)) + } + } + } + } + require.Empty(t, remainingSubjs, "test should cover all subjects") + }) + } +} + func TestIsOrgRole(t *testing.T) { t.Parallel() randomUUID := uuid.New() From 9129ef64c6f8fda68b83614e07e0d604df45b4bd Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 26 May 2022 10:19:45 -0500 Subject: [PATCH 2/4] Import order --- coderd/rbac/builtin_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/coderd/rbac/builtin_test.go b/coderd/rbac/builtin_test.go index 232705e41a713..e5bb013f8c9ca 100644 --- a/coderd/rbac/builtin_test.go +++ b/coderd/rbac/builtin_test.go @@ -5,10 +5,8 @@ import ( "fmt" "testing" - "github.com/stretchr/testify/assert" - "github.com/google/uuid" - + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/coder/coder/coderd/rbac" From 67a7fee6fd37f173b975fae765ace0c03c7b2673 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 26 May 2022 10:22:04 -0500 Subject: [PATCH 3/4] Add some comments --- coderd/rbac/builtin_test.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/coderd/rbac/builtin_test.go b/coderd/rbac/builtin_test.go index e5bb013f8c9ca..e610722c95906 100644 --- a/coderd/rbac/builtin_test.go +++ b/coderd/rbac/builtin_test.go @@ -39,12 +39,16 @@ func TestRolePermissions(t *testing.T) { otherOrgMember := authSubject{Name: "other_org_member", UserID: uuid.NewString(), Roles: []string{rbac.RoleMember(), rbac.RoleOrgMember(otherOrg)}} otherOrgAdmin := authSubject{Name: "other_org_admin", UserID: uuid.NewString(), Roles: []string{rbac.RoleMember(), rbac.RoleOrgMember(otherOrg), rbac.RoleOrgAdmin(otherOrg)}} - allSubj := []authSubject{member, admin, orgMember, orgAdmin, otherOrgAdmin, otherOrgMember} + // requiredSubjects are required to be asserted in each test case. This is + // to make sure one is not forgotten. + requiredSubjects := []authSubject{member, admin, orgMember, orgAdmin, otherOrgAdmin, otherOrgMember} testCases := []struct { - Name string - Resource rbac.Object - Actions []rbac.Action + // Name the test case to better locate the failing test case. + Name string + Resource rbac.Object + Actions []rbac.Action + // Assertions must cover all subjects in 'requiredSubjects' Assertions map[bool][]authSubject }{ { @@ -217,7 +221,7 @@ func TestRolePermissions(t *testing.T) { t.Run(c.Name, func(t *testing.T) { t.Parallel() remainingSubjs := make(map[string]struct{}) - for _, subj := range allSubj { + for _, subj := range requiredSubjects { remainingSubjs[subj.Name] = struct{}{} } From f60365b97725651d165652024136c9bb5ca1e7c5 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 27 May 2022 08:30:56 -0500 Subject: [PATCH 4/4] PR cleanup from comments - Add comments, rename fields --- coderd/rbac/builtin_test.go | 119 +++++++++++++++++++----------------- 1 file changed, 63 insertions(+), 56 deletions(-) diff --git a/coderd/rbac/builtin_test.go b/coderd/rbac/builtin_test.go index e610722c95906..d68f697719acd 100644 --- a/coderd/rbac/builtin_test.go +++ b/coderd/rbac/builtin_test.go @@ -25,38 +25,45 @@ func TestRolePermissions(t *testing.T) { auth, err := rbac.NewAuthorizer() require.NoError(t, err, "new rego authorizer") - meID := uuid.New() + // currentUser is anything that references "me", "mine", or "my". + currentUser := uuid.New() adminID := uuid.New() orgID := uuid.New() otherOrg := uuid.New() // Subjects to user - member := authSubject{Name: "member", UserID: meID.String(), Roles: []string{rbac.RoleMember()}} - admin := authSubject{Name: "admin", UserID: adminID.String(), Roles: []string{rbac.RoleMember(), rbac.RoleAdmin()}} + memberMe := authSubject{Name: "member_me", UserID: currentUser.String(), Roles: []string{rbac.RoleMember()}} + orgMemberMe := authSubject{Name: "org_member_me", UserID: currentUser.String(), Roles: []string{rbac.RoleMember(), rbac.RoleOrgMember(orgID)}} - orgMember := authSubject{Name: "org_member", UserID: meID.String(), Roles: []string{rbac.RoleMember(), rbac.RoleOrgMember(orgID)}} + admin := authSubject{Name: "admin", UserID: adminID.String(), Roles: []string{rbac.RoleMember(), rbac.RoleAdmin()}} orgAdmin := authSubject{Name: "org_admin", UserID: adminID.String(), Roles: []string{rbac.RoleMember(), rbac.RoleOrgMember(orgID), rbac.RoleOrgAdmin(orgID)}} - otherOrgMember := authSubject{Name: "other_org_member", UserID: uuid.NewString(), Roles: []string{rbac.RoleMember(), rbac.RoleOrgMember(otherOrg)}} - otherOrgAdmin := authSubject{Name: "other_org_admin", UserID: uuid.NewString(), Roles: []string{rbac.RoleMember(), rbac.RoleOrgMember(otherOrg), rbac.RoleOrgAdmin(otherOrg)}} + + otherOrgMember := authSubject{Name: "org_member_other", UserID: uuid.NewString(), Roles: []string{rbac.RoleMember(), rbac.RoleOrgMember(otherOrg)}} + otherOrgAdmin := authSubject{Name: "org_admin_other", UserID: uuid.NewString(), Roles: []string{rbac.RoleMember(), rbac.RoleOrgMember(otherOrg), rbac.RoleOrgAdmin(otherOrg)}} // requiredSubjects are required to be asserted in each test case. This is // to make sure one is not forgotten. - requiredSubjects := []authSubject{member, admin, orgMember, orgAdmin, otherOrgAdmin, otherOrgMember} + requiredSubjects := []authSubject{memberMe, admin, orgMemberMe, orgAdmin, otherOrgAdmin, otherOrgMember} testCases := []struct { // Name the test case to better locate the failing test case. Name string Resource rbac.Object Actions []rbac.Action - // Assertions must cover all subjects in 'requiredSubjects' - Assertions map[bool][]authSubject + // AuthorizeMap must cover all subjects in 'requiredSubjects'. + // This map will run an Authorize() check with the resource, action, + // and subjects. The subjects are split into 2 categories, "true" and + // "false". + // true: Subjects who Authorize should return no error + // false: Subjects who Authorize should return forbidden. + AuthorizeMap map[bool][]authSubject }{ { Name: "MyUser", Actions: []rbac.Action{rbac.ActionRead}, - Resource: rbac.ResourceUser.WithID(meID.String()), - Assertions: map[bool][]authSubject{ - true: {admin, member, orgMember, orgAdmin, otherOrgMember, otherOrgAdmin}, + Resource: rbac.ResourceUser.WithID(currentUser.String()), + AuthorizeMap: map[bool][]authSubject{ + true: {admin, memberMe, orgMemberMe, orgAdmin, otherOrgMember, otherOrgAdmin}, false: {}, }, }, @@ -64,54 +71,54 @@ func TestRolePermissions(t *testing.T) { Name: "AUser", Actions: []rbac.Action{rbac.ActionCreate, rbac.ActionUpdate, rbac.ActionDelete}, Resource: rbac.ResourceUser, - Assertions: map[bool][]authSubject{ + AuthorizeMap: map[bool][]authSubject{ true: {admin}, - false: {member, orgMember, orgAdmin, otherOrgMember, otherOrgAdmin}, + false: {memberMe, orgMemberMe, orgAdmin, otherOrgMember, otherOrgAdmin}, }, }, { Name: "MyWorkspaceInOrg", // When creating the WithID won't be set, but it does not change the result. Actions: []rbac.Action{rbac.ActionCreate, rbac.ActionRead, rbac.ActionUpdate, rbac.ActionDelete}, - Resource: rbac.ResourceWorkspace.InOrg(orgID).WithOwner(meID.String()).WithID(uuid.NewString()), - Assertions: map[bool][]authSubject{ - true: {admin, orgMember, orgAdmin}, - false: {member, otherOrgAdmin, otherOrgMember}, + Resource: rbac.ResourceWorkspace.InOrg(orgID).WithOwner(currentUser.String()).WithID(uuid.NewString()), + AuthorizeMap: map[bool][]authSubject{ + true: {admin, orgMemberMe, orgAdmin}, + false: {memberMe, otherOrgAdmin, otherOrgMember}, }, }, { Name: "Templates", Actions: []rbac.Action{rbac.ActionCreate, rbac.ActionUpdate, rbac.ActionDelete}, Resource: rbac.ResourceTemplate.InOrg(orgID).WithID(uuid.NewString()), - Assertions: map[bool][]authSubject{ + AuthorizeMap: map[bool][]authSubject{ true: {admin, orgAdmin}, - false: {member, orgMember, otherOrgAdmin, otherOrgMember}, + false: {memberMe, orgMemberMe, otherOrgAdmin, otherOrgMember}, }, }, { Name: "ReadTemplates", Actions: []rbac.Action{rbac.ActionRead}, Resource: rbac.ResourceTemplate.InOrg(orgID).WithID(uuid.NewString()), - Assertions: map[bool][]authSubject{ - true: {admin, orgMember, orgAdmin}, - false: {member, otherOrgAdmin, otherOrgMember}, + AuthorizeMap: map[bool][]authSubject{ + true: {admin, orgMemberMe, orgAdmin}, + false: {memberMe, otherOrgAdmin, otherOrgMember}, }, }, { Name: "Files", Actions: []rbac.Action{rbac.ActionCreate}, Resource: rbac.ResourceFile, - Assertions: map[bool][]authSubject{ + AuthorizeMap: map[bool][]authSubject{ true: {admin}, - false: {orgMember, orgAdmin, member, otherOrgAdmin, otherOrgMember}, + false: {orgMemberMe, orgAdmin, memberMe, otherOrgAdmin, otherOrgMember}, }, }, { Name: "MyFile", Actions: []rbac.Action{rbac.ActionRead, rbac.ActionUpdate, rbac.ActionDelete}, - Resource: rbac.ResourceFile.WithID(uuid.NewString()).WithOwner(meID.String()), - Assertions: map[bool][]authSubject{ - true: {admin, member, orgMember}, + Resource: rbac.ResourceFile.WithID(uuid.NewString()).WithOwner(currentUser.String()), + AuthorizeMap: map[bool][]authSubject{ + true: {admin, memberMe, orgMemberMe}, false: {orgAdmin, otherOrgAdmin, otherOrgMember}, }, }, @@ -119,44 +126,44 @@ func TestRolePermissions(t *testing.T) { Name: "CreateOrganizations", Actions: []rbac.Action{rbac.ActionCreate}, Resource: rbac.ResourceOrganization, - Assertions: map[bool][]authSubject{ + AuthorizeMap: map[bool][]authSubject{ true: {admin}, - false: {orgAdmin, otherOrgAdmin, otherOrgMember, member, orgMember}, + false: {orgAdmin, otherOrgAdmin, otherOrgMember, memberMe, orgMemberMe}, }, }, { Name: "Organizations", Actions: []rbac.Action{rbac.ActionUpdate, rbac.ActionDelete}, Resource: rbac.ResourceOrganization.InOrg(orgID).WithID(orgID.String()), - Assertions: map[bool][]authSubject{ + AuthorizeMap: map[bool][]authSubject{ true: {admin, orgAdmin}, - false: {otherOrgAdmin, otherOrgMember, member, orgMember}, + false: {otherOrgAdmin, otherOrgMember, memberMe, orgMemberMe}, }, }, { Name: "ReadOrganizations", Actions: []rbac.Action{rbac.ActionRead}, Resource: rbac.ResourceOrganization.InOrg(orgID).WithID(orgID.String()), - Assertions: map[bool][]authSubject{ - true: {admin, orgAdmin, orgMember}, - false: {otherOrgAdmin, otherOrgMember, member}, + AuthorizeMap: map[bool][]authSubject{ + true: {admin, orgAdmin, orgMemberMe}, + false: {otherOrgAdmin, otherOrgMember, memberMe}, }, }, { Name: "RoleAssignment", Actions: []rbac.Action{rbac.ActionCreate, rbac.ActionUpdate, rbac.ActionDelete}, Resource: rbac.ResourceRoleAssignment, - Assertions: map[bool][]authSubject{ + AuthorizeMap: map[bool][]authSubject{ true: {admin}, - false: {orgAdmin, orgMember, otherOrgAdmin, otherOrgMember, member}, + false: {orgAdmin, orgMemberMe, otherOrgAdmin, otherOrgMember, memberMe}, }, }, { Name: "ReadRoleAssignment", Actions: []rbac.Action{rbac.ActionRead}, Resource: rbac.ResourceRoleAssignment, - Assertions: map[bool][]authSubject{ - true: {admin, orgAdmin, orgMember, otherOrgAdmin, otherOrgMember, member}, + AuthorizeMap: map[bool][]authSubject{ + true: {admin, orgAdmin, orgMemberMe, otherOrgAdmin, otherOrgMember, memberMe}, false: {}, }, }, @@ -164,35 +171,35 @@ func TestRolePermissions(t *testing.T) { Name: "OrgRoleAssignment", Actions: []rbac.Action{rbac.ActionCreate, rbac.ActionUpdate, rbac.ActionDelete}, Resource: rbac.ResourceOrgRoleAssignment.InOrg(orgID), - Assertions: map[bool][]authSubject{ + AuthorizeMap: map[bool][]authSubject{ true: {admin, orgAdmin}, - false: {orgMember, otherOrgAdmin, otherOrgMember, member}, + false: {orgMemberMe, otherOrgAdmin, otherOrgMember, memberMe}, }, }, { Name: "ReadOrgRoleAssignment", Actions: []rbac.Action{rbac.ActionRead}, Resource: rbac.ResourceOrgRoleAssignment.InOrg(orgID), - Assertions: map[bool][]authSubject{ - true: {admin, orgAdmin, orgMember}, - false: {otherOrgAdmin, otherOrgMember, member}, + AuthorizeMap: map[bool][]authSubject{ + true: {admin, orgAdmin, orgMemberMe}, + false: {otherOrgAdmin, otherOrgMember, memberMe}, }, }, { Name: "APIKey", Actions: []rbac.Action{rbac.ActionCreate, rbac.ActionRead, rbac.ActionUpdate, rbac.ActionDelete}, - Resource: rbac.ResourceAPIKey.WithOwner(meID.String()).WithID(uuid.NewString()), - Assertions: map[bool][]authSubject{ - true: {admin, orgMember, member}, + Resource: rbac.ResourceAPIKey.WithOwner(currentUser.String()).WithID(uuid.NewString()), + AuthorizeMap: map[bool][]authSubject{ + true: {admin, orgMemberMe, memberMe}, false: {orgAdmin, otherOrgAdmin, otherOrgMember}, }, }, { Name: "UserData", Actions: []rbac.Action{rbac.ActionCreate, rbac.ActionRead, rbac.ActionUpdate, rbac.ActionDelete}, - Resource: rbac.ResourceUserData.WithOwner(meID.String()).WithID(meID.String()), - Assertions: map[bool][]authSubject{ - true: {admin, orgMember, member}, + Resource: rbac.ResourceUserData.WithOwner(currentUser.String()).WithID(currentUser.String()), + AuthorizeMap: map[bool][]authSubject{ + true: {admin, orgMemberMe, memberMe}, false: {orgAdmin, otherOrgAdmin, otherOrgMember}, }, }, @@ -200,18 +207,18 @@ func TestRolePermissions(t *testing.T) { Name: "ManageOrgMember", Actions: []rbac.Action{rbac.ActionCreate, rbac.ActionUpdate, rbac.ActionDelete}, Resource: rbac.ResourceOrganizationMember.InOrg(orgID).WithID(uuid.NewString()), - Assertions: map[bool][]authSubject{ + AuthorizeMap: map[bool][]authSubject{ true: {admin, orgAdmin}, - false: {orgMember, member, otherOrgAdmin, otherOrgMember}, + false: {orgMemberMe, memberMe, otherOrgAdmin, otherOrgMember}, }, }, { Name: "ReadOrgMember", Actions: []rbac.Action{rbac.ActionRead}, Resource: rbac.ResourceOrganizationMember.InOrg(orgID).WithID(uuid.NewString()), - Assertions: map[bool][]authSubject{ - true: {admin, orgAdmin, orgMember}, - false: {member, otherOrgAdmin, otherOrgMember}, + AuthorizeMap: map[bool][]authSubject{ + true: {admin, orgAdmin, orgMemberMe}, + false: {memberMe, otherOrgAdmin, otherOrgMember}, }, }, } @@ -226,7 +233,7 @@ func TestRolePermissions(t *testing.T) { } for _, action := range c.Actions { - for result, subjs := range c.Assertions { + for result, subjs := range c.AuthorizeMap { for _, subj := range subjs { delete(remainingSubjs, subj.Name) msg := fmt.Sprintf("%s as %q doing %q on %q", c.Name, subj.Name, action, c.Resource.Type)