You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
boundary/internal/iam/repository_role_grant_scope...

1930 lines
71 KiB

// Copyright IBM Corp. 2020, 2025
// SPDX-License-Identifier: MPL-2.0
package iam
import (
"context"
"fmt"
"testing"
"github.com/hashicorp/boundary/globals"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/iam/store"
"github.com/hashicorp/boundary/internal/perms"
"github.com/hashicorp/boundary/internal/types/action"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_listRoleGrantScopes(t *testing.T) {
ctx := context.Background()
conn, _ := db.TestSetup(t, "postgres")
wrap := db.TestWrapper(t)
iamRepo := TestRepo(t, conn, wrap)
rw := db.New(conn)
org1, proj1 := TestScopes(t, iamRepo)
org2, proj2 := TestScopes(t, iamRepo)
testcases := []struct {
name string
// setup function that return []*Role that will be used as test input and list of expected RoleGrantScope
setupExpect func(t *testing.T) ([]*Role, []*RoleGrantScope)
wantErr bool
wantErrMsg string
}{
{
name: "global role no individual scope grants happy path",
setupExpect: func(t *testing.T) ([]*Role, []*RoleGrantScope) {
r := TestRole(t, conn, globals.GlobalPrefix)
gRole := allocGlobalRole()
gRole.PublicId = r.PublicId
require.NoError(t, rw.LookupByPublicId(ctx, &gRole))
gRole.GrantScope = globals.GrantScopeDescendants
_, err := rw.Update(ctx, &gRole, []string{"GrantScope"}, []string{})
require.NoError(t, err)
return []*Role{r}, []*RoleGrantScope{
{
RoleId: r.PublicId,
ScopeIdOrSpecial: globals.GrantScopeDescendants,
},
{
RoleId: r.PublicId,
ScopeIdOrSpecial: globals.GrantScopeThis,
},
}
},
wantErr: false,
},
{
name: "global role without this happy path",
setupExpect: func(t *testing.T) ([]*Role, []*RoleGrantScope) {
r := TestRole(t, conn, globals.GlobalPrefix)
gRole := allocGlobalRole()
gRole.PublicId = r.PublicId
require.NoError(t, rw.LookupByPublicId(ctx, &gRole))
gRole.GrantThisRoleScope = false
gRole.GrantScope = globals.GrantScopeDescendants
_, err := rw.Update(ctx, &gRole, []string{"GrantScope", "GrantThisRoleScope"}, []string{})
require.NoError(t, err)
return []*Role{r}, []*RoleGrantScope{
{
RoleId: r.PublicId,
ScopeIdOrSpecial: globals.GrantScopeDescendants,
},
}
},
wantErr: false,
},
{
name: "global role without any grants return empty",
setupExpect: func(t *testing.T) ([]*Role, []*RoleGrantScope) {
r := TestRole(t, conn, globals.GlobalPrefix)
gRole := allocGlobalRole()
gRole.PublicId = r.PublicId
require.NoError(t, rw.LookupByPublicId(ctx, &gRole))
gRole.GrantThisRoleScope = false
_, err := rw.Update(ctx, &gRole, []string{"GrantThisRoleScope"}, []string{})
require.NoError(t, err)
return []*Role{r}, []*RoleGrantScope{}
},
wantErr: false,
},
{
name: "multiple roles with different grants union grants happy path",
setupExpect: func(t *testing.T) ([]*Role, []*RoleGrantScope) {
firstRole := TestRole(t, conn, globals.GlobalPrefix)
secondRole := TestRole(t, conn, org2.PublicId)
firstRoleOrg1 := &globalRoleIndividualOrgGrantScope{
GlobalRoleIndividualOrgGrantScope: &store.GlobalRoleIndividualOrgGrantScope{
RoleId: firstRole.PublicId,
ScopeId: org1.PublicId,
GrantScope: globals.GrantScopeIndividual,
},
}
require.NoError(t, rw.Create(ctx, firstRoleOrg1))
firstRoleProj1 := &globalRoleIndividualProjectGrantScope{
GlobalRoleIndividualProjectGrantScope: &store.GlobalRoleIndividualProjectGrantScope{
RoleId: firstRole.PublicId,
ScopeId: proj1.PublicId,
GrantScope: globals.GrantScopeIndividual,
},
}
require.NoError(t, rw.Create(ctx, firstRoleProj1))
secondRoleProj2 := &orgRoleIndividualGrantScope{
OrgRoleIndividualGrantScope: &store.OrgRoleIndividualGrantScope{
RoleId: secondRole.PublicId,
ScopeId: proj2.PublicId,
GrantScope: globals.GrantScopeIndividual,
},
}
require.NoError(t, rw.Create(ctx, secondRoleProj2))
return []*Role{firstRole, secondRole}, []*RoleGrantScope{
{
RoleId: firstRole.PublicId,
ScopeIdOrSpecial: org1.PublicId,
},
{
RoleId: firstRole.PublicId,
ScopeIdOrSpecial: globals.GrantScopeThis,
},
{
RoleId: firstRole.PublicId,
ScopeIdOrSpecial: proj1.PublicId,
},
{
RoleId: secondRole.PublicId,
ScopeIdOrSpecial: proj2.PublicId,
},
{
RoleId: secondRole.PublicId,
ScopeIdOrSpecial: globals.GrantScopeThis,
},
}
},
wantErr: false,
},
{
name: "global role with individual scope grants happy path",
setupExpect: func(t *testing.T) ([]*Role, []*RoleGrantScope) {
r := TestRole(t, conn, globals.GlobalPrefix)
gRole := allocGlobalRole()
gRole.PublicId = r.PublicId
require.NoError(t, rw.LookupByPublicId(ctx, &gRole))
o1 := &globalRoleIndividualOrgGrantScope{
GlobalRoleIndividualOrgGrantScope: &store.GlobalRoleIndividualOrgGrantScope{
RoleId: r.PublicId,
ScopeId: org1.PublicId,
GrantScope: globals.GrantScopeIndividual,
},
}
require.NoError(t, rw.Create(ctx, o1))
o2 := &globalRoleIndividualOrgGrantScope{
GlobalRoleIndividualOrgGrantScope: &store.GlobalRoleIndividualOrgGrantScope{
RoleId: r.PublicId,
ScopeId: org2.PublicId,
GrantScope: globals.GrantScopeIndividual,
},
}
require.NoError(t, rw.Create(ctx, o2))
p1 := &globalRoleIndividualProjectGrantScope{
GlobalRoleIndividualProjectGrantScope: &store.GlobalRoleIndividualProjectGrantScope{
RoleId: r.PublicId,
ScopeId: proj1.PublicId,
GrantScope: globals.GrantScopeIndividual,
},
}
require.NoError(t, rw.Create(ctx, p1))
p2 := &globalRoleIndividualProjectGrantScope{
GlobalRoleIndividualProjectGrantScope: &store.GlobalRoleIndividualProjectGrantScope{
RoleId: r.PublicId,
ScopeId: proj2.PublicId,
GrantScope: globals.GrantScopeIndividual,
},
}
require.NoError(t, rw.Create(ctx, p2))
return []*Role{r}, []*RoleGrantScope{
{
RoleId: r.PublicId,
ScopeIdOrSpecial: globals.GrantScopeThis,
},
{
RoleId: r.PublicId,
ScopeIdOrSpecial: org1.PublicId,
},
{
RoleId: r.PublicId,
ScopeIdOrSpecial: org2.PublicId,
},
{
RoleId: r.PublicId,
ScopeIdOrSpecial: proj1.PublicId,
},
{
RoleId: r.PublicId,
ScopeIdOrSpecial: proj2.PublicId,
},
}
},
wantErr: false,
},
{
name: "multiple role with children and descendants grants happy path",
setupExpect: func(t *testing.T) ([]*Role, []*RoleGrantScope) {
role1 := TestRole(t, conn, globals.GlobalPrefix)
role2 := TestRole(t, conn, org2.PublicId)
gRole := allocGlobalRole()
gRole.PublicId = role1.PublicId
require.NoError(t, rw.LookupByPublicId(ctx, &gRole))
gRole.GrantScope = globals.GrantScopeDescendants
_, err := rw.Update(ctx, &gRole, []string{"GrantScope"}, []string{})
require.NoError(t, err)
oRole := allocOrgRole()
oRole.PublicId = role2.PublicId
require.NoError(t, rw.LookupByPublicId(ctx, &oRole))
oRole.GrantScope = globals.GrantScopeChildren
_, err = rw.Update(ctx, &oRole, []string{"GrantScope"}, []string{})
require.NoError(t, err)
return []*Role{role1, role2}, []*RoleGrantScope{
{
RoleId: role1.PublicId,
ScopeIdOrSpecial: globals.GrantScopeThis,
},
{
RoleId: role1.PublicId,
ScopeIdOrSpecial: globals.GrantScopeDescendants,
},
{
RoleId: role2.PublicId,
ScopeIdOrSpecial: globals.GrantScopeThis,
},
{
RoleId: role2.PublicId,
ScopeIdOrSpecial: globals.GrantScopeChildren,
},
}
},
wantErr: false,
},
{
name: "multiple project role happy path",
setupExpect: func(t *testing.T) ([]*Role, []*RoleGrantScope) {
role1 := TestRole(t, conn, proj1.PublicId)
role2 := TestRole(t, conn, proj2.PublicId)
return []*Role{role1, role2}, []*RoleGrantScope{
{
RoleId: role1.PublicId,
ScopeIdOrSpecial: globals.GrantScopeThis,
},
{
RoleId: role2.PublicId,
ScopeIdOrSpecial: globals.GrantScopeThis,
},
}
},
wantErr: false,
},
{
name: "project role with this grant",
setupExpect: func(t *testing.T) ([]*Role, []*RoleGrantScope) {
role := TestRole(t, conn, proj1.PublicId)
return []*Role{role}, []*RoleGrantScope{
{
RoleId: role.PublicId,
ScopeIdOrSpecial: globals.GrantScopeThis,
},
}
},
wantErr: false,
},
{
name: "project role without this grant",
setupExpect: func(t *testing.T) ([]*Role, []*RoleGrantScope) {
role := TestRole(t, conn, proj1.PublicId, WithGrantScopeIds([]string{"testing-none"}))
return []*Role{role}, []*RoleGrantScope{}
},
wantErr: false,
},
{
name: "role does not exist returns empty grant scope",
setupExpect: func(t *testing.T) ([]*Role, []*RoleGrantScope) {
invalidRole := &Role{
PublicId: "r_123456",
ScopeId: globals.GlobalPrefix,
}
return []*Role{invalidRole}, []*RoleGrantScope{}
},
wantErr: false,
},
{
name: "bad role id returns error",
setupExpect: func(t *testing.T) ([]*Role, []*RoleGrantScope) {
return []*Role{}, []*RoleGrantScope{}
},
wantErr: true,
wantErrMsg: `iam.(Repository).listRoleGrantScopes: missing role ids: parameter violation: error #100`,
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
roles, expect := tc.setupExpect(t)
var roleIds []string
for _, r := range roles {
roleIds = append(roleIds, r.PublicId)
}
expectRoleScopeMap := roleScopesToMap(t, expect)
got, err := listRoleGrantScopes(ctx, rw, roleIds)
if tc.wantErr {
require.Error(t, err)
require.ErrorContains(t, err, tc.wantErrMsg)
return
}
require.NoError(t, err)
gotRoleScopeMap := roleScopesToMap(t, got)
require.Equal(t, len(expectRoleScopeMap), len(gotRoleScopeMap))
for roleId, expectRoleScopes := range expectRoleScopeMap {
gotRoleScopes, found := gotRoleScopeMap[roleId]
require.True(t, found)
require.ElementsMatch(t, expectRoleScopes, gotRoleScopes)
}
})
}
}
func Test_AddRoleGrantScope(t *testing.T) {
ctx := context.Background()
conn, _ := db.TestSetup(t, "postgres")
wrap := db.TestWrapper(t)
iamRepo := TestRepo(t, conn, wrap)
org1, proj1 := TestScopes(t, iamRepo)
org2, proj2 := TestScopes(t, iamRepo)
testcases := []struct {
name string
setupRole func(t *testing.T) *Role
inputAddScopes []string // this is both the input and expect
wantReturnedScopes []string // this is the expected scopes that are added (input scopes minus existing grant scopes)
wantRoleVersionChange uint32
wantScopes []string // this is always validated even in error case
wantErr bool
wantErrMsg string
}{
{
name: "global role add all individual grant scopes",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix)
},
inputAddScopes: []string{proj1.PublicId, proj2.PublicId, org1.PublicId, org2.PublicId},
wantReturnedScopes: []string{org1.PublicId, org2.PublicId, proj1.PublicId, proj2.PublicId},
wantRoleVersionChange: 1,
wantScopes: []string{globals.GrantScopeThis, org1.PublicId, org2.PublicId, proj1.PublicId, proj2.PublicId},
wantErr: false,
},
{
name: "global role dedupe individual scope",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix, WithGrantScopeIds([]string{org1.PublicId, proj1.PublicId}))
},
inputAddScopes: []string{org1.PublicId, proj1.PublicId},
wantReturnedScopes: []string{},
wantRoleVersionChange: 0,
wantScopes: []string{org1.PublicId, proj1.PublicId},
wantErr: false,
},
{
name: "global role add this, children. and individual project",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix, WithGrantScopeIds([]string{"testing-none"}))
},
inputAddScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren, proj1.PublicId},
wantReturnedScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren, proj1.PublicId},
wantRoleVersionChange: 1,
wantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren, proj1.PublicId},
wantErr: false,
},
{
name: "global role add dedupe special scope",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix, WithGrantScopeIds([]string{globals.GrantScopeThis, globals.GrantScopeChildren, proj1.PublicId}))
},
inputAddScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren, proj1.PublicId},
wantReturnedScopes: []string{},
wantRoleVersionChange: 0,
wantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren, proj1.PublicId},
wantErr: false,
},
{
name: "global role add individual scope when grant_scope is children",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix, WithGrantScopeIds([]string{globals.GrantScopeThis, globals.GrantScopeChildren}))
},
inputAddScopes: []string{proj1.PublicId},
wantReturnedScopes: []string{proj1.PublicId},
wantRoleVersionChange: 1,
wantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren, proj1.PublicId},
wantErr: false,
},
{
name: "global role error adding conflicting grants when individual scope exists",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix, WithGrantScopeIds([]string{proj1.PublicId}))
},
inputAddScopes: []string{globals.GrantScopeDescendants},
wantRoleVersionChange: 0,
wantScopes: []string{proj1.PublicId},
wantErr: true,
wantErrMsg: "iam.(Repository).AddRoleGrantScopes: db.DoTx: iam.(Repository).AddRoleGrantScopes: unable to update role: db.Update: only_individual_or_children_grant_scope_allowed constraint failed: check constraint violated: integrity violation: error #1000",
},
{
name: "global role error adding overlapping grants",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix, WithGrantScopeIds([]string{org1.PublicId}))
},
inputAddScopes: []string{globals.GrantScopeChildren},
wantRoleVersionChange: 0,
wantScopes: []string{org1.PublicId},
wantErr: true,
wantErrMsg: "iam.(Repository).AddRoleGrantScopes: db.DoTx: iam.(Repository).AddRoleGrantScopes: unable to update role: db.Update: immutable column: iam_role_global_individual_org_grant_scope.grant_scope: integrity violation: error #1003",
},
{
name: "global role error adding children when descendants already exists",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix, WithGrantScopeIds([]string{globals.GrantScopeChildren}))
},
inputAddScopes: []string{globals.GrantScopeDescendants},
wantRoleVersionChange: 0,
wantScopes: []string{globals.GrantScopeChildren},
wantErr: true,
wantErrMsg: "iam.(Repository).AddRoleGrantScopes: grant scope children already exists, only one of descendants or children grant scope can be specified: parameter violation: error #100",
},
{
name: "global role error adding descendants when children already exists",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix, WithGrantScopeIds([]string{globals.GrantScopeDescendants}))
},
inputAddScopes: []string{globals.GrantScopeChildren},
wantRoleVersionChange: 0,
wantScopes: []string{globals.GrantScopeDescendants},
wantErr: true,
wantErrMsg: "iam.(Repository).AddRoleGrantScopes: grant scope descendants already exists, only one of descendants or children grant scope can be specified: parameter violation: error #100",
},
{
name: "global role error adding mutually exclusive grants",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix, WithGrantScopeIds([]string{"testing-none"}))
},
inputAddScopes: []string{globals.GrantScopeChildren, globals.GrantScopeDescendants},
wantRoleVersionChange: 0,
wantScopes: []string{},
wantErr: true,
wantErrMsg: "iam.(Repository).AddRoleGrantScopes: only one of descendants or children grant scope can be specified: parameter violation: error #100",
},
{
name: "global role error adding overlapping grants",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix, WithGrantScopeIds([]string{"testing-none"}))
},
inputAddScopes: []string{globals.GrantScopeDescendants, proj1.PublicId},
wantRoleVersionChange: 0,
wantScopes: []string{},
wantErr: true,
wantErrMsg: "iam.(Repository).AddRoleGrantScopes: db.DoTx: iam.(Repository).AddRoleGrantScopes: unable to add individual project grant scopes for global role: db.CreateItems: only_individual_or_children_grant_scope_allowed constraint failed: check constraint violated: integrity violation: error #1000",
},
{
name: "org role add specials",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, org1.PublicId, WithGrantScopeIds([]string{"testing-none"}))
},
inputAddScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
wantReturnedScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
wantRoleVersionChange: 1,
wantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
wantErr: false,
},
{
name: "org role add individual",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, org1.PublicId)
},
inputAddScopes: []string{proj1.PublicId},
wantReturnedScopes: []string{proj1.PublicId},
wantRoleVersionChange: 1,
wantScopes: []string{globals.GrantScopeThis, proj1.PublicId},
wantErr: false,
},
{
name: "org role dedupe individual",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, org1.PublicId, WithGrantScopeIds([]string{proj1.PublicId}))
},
inputAddScopes: []string{proj1.PublicId},
wantReturnedScopes: []string{},
wantRoleVersionChange: 0,
wantScopes: []string{proj1.PublicId},
wantErr: false,
},
{
name: "org role dedupe special",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, org1.PublicId, WithGrantScopeIds([]string{globals.GrantScopeThis, globals.GrantScopeChildren}))
},
inputAddScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
wantReturnedScopes: []string{},
wantRoleVersionChange: 0,
wantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
wantErr: false,
},
{
name: "org role error adding invalid grants",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, org1.PublicId, WithGrantScopeIds([]string{globals.GrantScopeChildren}))
},
inputAddScopes: []string{globals.GrantScopeDescendants},
wantRoleVersionChange: 0,
wantScopes: []string{globals.GrantScopeChildren},
wantErr: true,
wantErrMsg: `iam.(Repository).AddRoleGrantScopes: grant scope children already exists, only one of descendants or children grant scope can be specified: parameter violation: error #100`,
},
{
name: "org role error adding overlapping grants",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, org1.PublicId, WithGrantScopeIds([]string{globals.GrantScopeChildren}))
},
inputAddScopes: []string{proj1.PublicId},
wantRoleVersionChange: 0,
wantScopes: []string{globals.GrantScopeChildren},
wantErr: true,
wantErrMsg: `iam.(Repository).AddRoleGrantScopes: db.DoTx: iam.(Repository).AddRoleGrantScopes: unable to add individual project grant scopes for global role: db.CreateItems: insert or update on table "iam_role_org_individual_grant_scope" violates foreign key constraint "iam_role_org_grant_scope_fkey": integrity violation: error #1003`,
},
{
name: "org role error adding project not belong to this org",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, org1.PublicId)
},
inputAddScopes: []string{proj2.PublicId},
wantRoleVersionChange: 0,
wantScopes: []string{globals.GrantScopeThis},
wantErr: true,
wantErrMsg: fmt.Sprintf(`iam.(Repository).AddRoleGrantScopes: db.DoTx: iam.(Repository).AddRoleGrantScopes: unable to add individual project grant scopes for global role: db.CreateItems: project scope_id %s not found in org: integrity violation: error #1104`, proj2.PublicId),
},
{
name: "project role add this grant_scope",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, proj1.PublicId, WithGrantScopeIds([]string{"testing-none"}))
},
inputAddScopes: []string{globals.GrantScopeThis},
wantReturnedScopes: []string{globals.GrantScopeThis},
wantRoleVersionChange: 1,
wantScopes: []string{globals.GrantScopeThis},
wantErr: false,
},
{
name: "project role add this grant scope then this is already set",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, proj1.PublicId, WithGrantScopeIds([]string{globals.GrantScopeThis}))
},
inputAddScopes: []string{globals.GrantScopeThis},
wantReturnedScopes: []string{},
wantRoleVersionChange: 0,
wantScopes: []string{globals.GrantScopeThis},
wantErr: false,
},
{
name: "project role add children grant scope returns error",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, proj1.PublicId, WithGrantScopeIds([]string{globals.GrantScopeThis}))
},
inputAddScopes: []string{globals.GrantScopeChildren},
wantRoleVersionChange: 0,
wantScopes: []string{globals.GrantScopeThis},
wantErr: true,
wantErrMsg: `iam.(Repository).AddRoleGrantScopes: iam.(projectRole).setGrantScope: hierarchical grant scope is not allowed for project role: parameter violation: error #100`,
},
{
name: "project role add individual grant scope returns error",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, proj1.PublicId, WithGrantScopeIds([]string{globals.GrantScopeThis}))
},
inputAddScopes: []string{proj2.PublicId},
wantRoleVersionChange: 0,
wantScopes: []string{globals.GrantScopeThis},
wantErr: true,
wantErrMsg: `iam.(Repository).AddRoleGrantScopes: individual role grant scope can only be set for global roles or org roles: parameter violation: error #100`,
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
r := tc.setupRole(t)
out, err := iamRepo.AddRoleGrantScopes(ctx, r.PublicId, r.Version, tc.inputAddScopes)
if tc.wantErr {
require.Error(t, err)
require.Contains(t, err.Error(), tc.wantErrMsg)
} else {
require.NoError(t, err)
var outScopes []string
for _, gs := range out {
require.Equal(t, r.PublicId, gs.RoleId)
outScopes = append(outScopes, gs.ScopeIdOrSpecial)
}
require.ElementsMatch(t, outScopes, tc.wantReturnedScopes)
}
// list the grant scopes again to verify that we're getting the expected grants scope
afterRole, _, _, readbackGrantScopes, err := iamRepo.LookupRole(ctx, r.PublicId)
require.NoError(t, err)
var readbackScopeIds []string
for _, gs := range readbackGrantScopes {
require.Equal(t, r.PublicId, gs.RoleId)
readbackScopeIds = append(readbackScopeIds, gs.ScopeIdOrSpecial)
}
require.ElementsMatch(t, readbackScopeIds, tc.wantScopes)
require.Equal(t, r.Version+tc.wantRoleVersionChange, afterRole.Version)
})
}
}
func Test_SetRoleGrantScope(t *testing.T) {
ctx := context.Background()
conn, _ := db.TestSetup(t, "postgres")
wrap := db.TestWrapper(t)
iamRepo := TestRepo(t, conn, wrap)
org1, proj1 := TestScopes(t, iamRepo)
org2, proj2 := TestScopes(t, iamRepo)
testcases := []struct {
name string
setupRole func(t *testing.T) *Role
expectRemove int
expectRoleVersionChange uint32
scopes []string // this is both the input and expect
wantErr bool
wantErrMsg string
}{
{
name: "global role sets this and children",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix, WithGrantScopeIds([]string{"testing-none"}))
},
expectRemove: 0,
expectRoleVersionChange: 1,
scopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
wantErr: false,
},
{
name: "global role sets this and children and individual project",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix, WithGrantScopeIds([]string{globals.GrantScopeThis, globals.GrantScopeChildren}))
},
expectRemove: 0,
expectRoleVersionChange: 1,
scopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren, proj2.PublicId},
wantErr: false,
},
{
name: "global role sets all individual scopes",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix, WithGrantScopeIds([]string{globals.GrantScopeThis, globals.GrantScopeDescendants}))
},
expectRemove: 2,
expectRoleVersionChange: 1,
scopes: []string{org1.PublicId, org2.PublicId, proj1.PublicId, proj2.PublicId},
wantErr: false,
},
{
name: "global role set special and individual scopes",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix, WithGrantScopeIds([]string{org1.PublicId, org2.PublicId}))
},
expectRemove: 2,
expectRoleVersionChange: 1,
scopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren, proj1.PublicId, proj2.PublicId},
wantErr: false,
},
{
name: "global role set different special and individual scopes",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix, WithGrantScopeIds([]string{globals.GrantScopeThis, globals.GrantScopeDescendants}))
},
expectRemove: 2,
expectRoleVersionChange: 1,
scopes: []string{globals.GrantScopeChildren, proj1.PublicId},
wantErr: false,
},
{
name: "global role change grants types from individual to children with individual scopes",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix, WithGrantScopeIds([]string{globals.GrantScopeThis, proj1.PublicId, proj2.PublicId}))
},
expectRemove: 0,
expectRoleVersionChange: 1,
scopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren, proj1.PublicId, proj2.PublicId},
wantErr: false,
},
{
name: "global role set grants to mix type",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix, WithGrantScopeIds([]string{org1.PublicId, org2.PublicId, proj1.PublicId, proj2.PublicId}))
},
expectRemove: 4,
expectRoleVersionChange: 1,
scopes: []string{globals.GrantScopeThis, globals.GrantScopeDescendants},
wantErr: false,
},
{
name: "global role remove and add special",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix, WithGrantScopeIds([]string{globals.GrantScopeThis}))
},
expectRemove: 1,
expectRoleVersionChange: 1,
scopes: []string{globals.GrantScopeDescendants},
wantErr: false,
},
{
name: "global role set special conflicting scopes return error",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix)
},
expectRemove: 0,
expectRoleVersionChange: 0,
scopes: []string{globals.GrantScopeChildren, globals.GrantScopeDescendants},
wantErr: true,
wantErrMsg: "iam.(Repository).SetRoleGrantScopes: only one of ['children', 'descendants'] can be specified: parameter violation: error #100",
},
{
name: "global role set individual conflicting scopes return error",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix)
},
expectRemove: 0,
expectRoleVersionChange: 0,
scopes: []string{globals.GrantScopeThis, globals.GrantScopeDescendants, proj1.PublicId, proj2.PublicId},
wantErr: true,
wantErrMsg: `iam.(Repository).SetRoleGrantScopes: db.DoTx: iam.(Repository).SetRoleGrantScopes: unable to add individual project grant scope for global role during set: db.CreateItems: insert or update on table "iam_role_global_individual_project_grant_scope" violates foreign key constraint "iam_role_global_grant_scope_fkey": integrity violation: error #1003`,
},
{
name: "global role set individual to remove individual grants",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix, WithGrantScopeIds([]string{org1.PublicId, org2.PublicId, proj1.PublicId, proj2.PublicId}))
},
expectRemove: 2,
expectRoleVersionChange: 1,
scopes: []string{org1.PublicId, proj1.PublicId},
wantErr: false,
},
{
name: "org role set no scopes to special",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, org1.PublicId, WithGrantScopeIds([]string{"testing-none"}))
},
expectRemove: 0,
expectRoleVersionChange: 1,
scopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
wantErr: false,
},
{
name: "org role switch from specials to individual",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, org1.PublicId, WithGrantScopeIds([]string{globals.GrantScopeThis, globals.GrantScopeChildren}))
},
expectRemove: 2,
expectRoleVersionChange: 1,
scopes: []string{proj1.PublicId},
wantErr: false,
},
{
name: "org role set role to remove all special scopes",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, org1.PublicId, WithGrantScopeIds([]string{globals.GrantScopeThis, globals.GrantScopeChildren}))
},
expectRemove: 2,
expectRoleVersionChange: 1,
scopes: []string{},
wantErr: false,
},
{
name: "org role set role to remove and add special",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, org1.PublicId, WithGrantScopeIds([]string{globals.GrantScopeChildren}))
},
expectRemove: 1,
expectRoleVersionChange: 1,
scopes: []string{globals.GrantScopeThis},
wantErr: false,
},
{
name: "org role set role to remove all individual scopes",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, org1.PublicId, WithGrantScopeIds([]string{proj1.PublicId}))
},
expectRemove: 1,
expectRoleVersionChange: 1,
scopes: []string{},
wantErr: false,
},
{
name: "org role add proj under another org returns error",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, org1.PublicId, WithGrantScopeIds([]string{globals.GrantScopeThis, proj1.PublicId}))
},
expectRoleVersionChange: 0,
scopes: []string{globals.GrantScopeThis, proj1.PublicId, proj2.PublicId},
wantErr: true,
wantErrMsg: fmt.Sprintf("iam.(Repository).SetRoleGrantScopes: db.DoTx: iam.(Repository).SetRoleGrantScopes: unable to add individual project grant scope for org role during set: db.CreateItems: project scope_id %s not found in org: integrity violation: error #1104", proj2.PublicId),
},
{
name: "org role conflicting grant scopes returns error",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, org1.PublicId)
},
expectRoleVersionChange: 0,
scopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren, proj1.PublicId},
wantErr: true,
wantErrMsg: `iam.(Repository).SetRoleGrantScopes: db.DoTx: iam.(Repository).SetRoleGrantScopes: unable to add individual project grant scope for org role during set: db.CreateItems: insert or update on table "iam_role_org_individual_grant_scope" violates foreign key constraint "iam_role_org_grant_scope_fkey": integrity violation: error #1003`,
},
{
name: "org role setting descendants grants returns error",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, org1.PublicId)
},
expectRoleVersionChange: 0,
scopes: []string{globals.GrantScopeThis, globals.GrantScopeDescendants},
wantErr: true,
wantErrMsg: `iam.(Repository).SetRoleGrantScopes: db.DoTx: iam.(Repository).SetRoleGrantScopes: unable to update role: db.Update: insert or update on table "iam_role_org" violates foreign key constraint "iam_role_org_grant_scope_enm_fkey": integrity violation: error #1003`,
},
{
name: "project scope with 'this' grant sets empty scopes",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, proj1.PublicId, WithGrantScopeIds([]string{globals.GrantScopeThis}))
},
scopes: []string{},
expectRoleVersionChange: 1,
expectRemove: 1,
wantErr: false,
},
{
name: "project scope with 'this' grant",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, proj1.PublicId, WithGrantScopeIds([]string{"testing-none"}))
},
scopes: []string{globals.GrantScopeThis},
expectRoleVersionChange: 1,
wantErr: false,
},
{
name: "project setting special grants return error",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, proj1.PublicId, WithGrantScopeIds([]string{"testing-none"}))
},
scopes: []string{globals.GrantScopeChildren},
expectRoleVersionChange: 0,
wantErr: true,
wantErrMsg: `iam.(Repository).SetRoleGrantScopes: iam.(projectRole).setGrantScope: hierarchical grant scope is not allowed for project role: parameter violation: error #100`,
},
{
name: "project setting individual grants return error",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, proj1.PublicId, WithGrantScopeIds([]string{"testing-none"}))
},
scopes: []string{proj2.PublicId},
expectRoleVersionChange: 0,
wantErr: true,
wantErrMsg: `iam.(Repository).SetRoleGrantScopes: roles in scope type project does not allow individual role grant scope: parameter violation: error #100`,
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
r := tc.setupRole(t)
got, removed, err := iamRepo.SetRoleGrantScopes(ctx, r.PublicId, r.Version, tc.scopes)
if tc.wantErr {
require.Error(t, err)
require.ErrorContains(t, err, tc.wantErrMsg)
afterRole, _, _, _, err := iamRepo.LookupRole(ctx, r.PublicId)
require.NoError(t, err)
require.Equal(t, r.Version, afterRole.Version)
return
}
require.NoError(t, err)
require.Equal(t, tc.expectRemove, removed)
var gotScopeIds []string
for _, grantScope := range got {
require.Equal(t, r.PublicId, grantScope.RoleId)
gotScopeIds = append(gotScopeIds, grantScope.ScopeIdOrSpecial)
}
require.ElementsMatch(t, tc.scopes, gotScopeIds)
// also validate using list
afterRole, _, _, afterGrantScopes, err := iamRepo.LookupRole(ctx, r.PublicId)
require.NoError(t, err)
var listedScopeIds []string
for _, grantScope := range afterGrantScopes {
require.Equal(t, r.PublicId, grantScope.RoleId)
listedScopeIds = append(listedScopeIds, grantScope.ScopeIdOrSpecial)
}
require.ElementsMatch(t, listedScopeIds, tc.scopes)
require.Equal(t, r.Version+tc.expectRoleVersionChange, afterRole.Version)
})
}
}
func Test_DeleteRoleGrantScope(t *testing.T) {
ctx := context.Background()
conn, _ := db.TestSetup(t, "postgres")
wrap := db.TestWrapper(t)
iamRepo := TestRepo(t, conn, wrap)
org1, proj1 := TestScopes(t, iamRepo)
org2, proj2 := TestScopes(t, iamRepo)
testcases := []struct {
name string
setupRole func(t *testing.T) *Role
expectRemove int
expectRoleVersionChange uint32
inputScopes []string
finalScopes []string
wantDeleted int
wantErr bool
wantErrMsg string
}{
{
name: "global role delete this and descendants",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix, WithGrantScopeIds([]string{globals.GrantScopeThis, globals.GrantScopeDescendants}))
},
expectRemove: 2,
expectRoleVersionChange: 1,
inputScopes: []string{globals.GrantScopeThis, globals.GrantScopeDescendants},
finalScopes: []string{},
wantErr: false,
},
{
name: "global role remove children with existing individually granted projects",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix, WithGrantScopeIds([]string{globals.GrantScopeThis, globals.GrantScopeChildren, proj1.PublicId, proj2.PublicId}))
},
expectRemove: 2,
expectRoleVersionChange: 1,
inputScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
finalScopes: []string{proj1.PublicId, proj2.PublicId},
wantErr: false,
},
{
name: "global role remove individual scopes",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix, WithGrantScopeIds([]string{globals.GrantScopeThis, org1.PublicId, org2.PublicId, proj1.PublicId, proj2.PublicId}))
},
expectRemove: 4,
expectRoleVersionChange: 1,
inputScopes: []string{org1.PublicId, org2.PublicId, proj1.PublicId, proj2.PublicId},
finalScopes: []string{globals.GrantScopeThis},
wantErr: false,
},
{
name: "global role remove scopes that dont exist",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, globals.GlobalPrefix, WithGrantScopeIds([]string{globals.GrantScopeThis, org1.PublicId, org2.PublicId}))
},
expectRemove: 0,
expectRoleVersionChange: 0,
inputScopes: []string{globals.GrantScopeChildren, proj1.PublicId, proj2.PublicId},
finalScopes: []string{globals.GrantScopeThis, org1.PublicId, org2.PublicId},
wantErr: false,
},
{
name: "org role remove special scopes",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, org1.PublicId, WithGrantScopeIds([]string{globals.GrantScopeThis, globals.GrantScopeChildren}))
},
expectRemove: 2,
expectRoleVersionChange: 1,
inputScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
finalScopes: []string{},
wantErr: false,
},
{
name: "org role remove individual scopes including scope that is not granted",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, org1.PublicId, WithGrantScopeIds([]string{globals.GrantScopeThis, proj1.PublicId}))
},
expectRemove: 1,
expectRoleVersionChange: 1,
inputScopes: []string{proj1.PublicId, proj2.PublicId},
finalScopes: []string{globals.GrantScopeThis},
wantErr: false,
},
{
name: "org role remove grants that don't exist",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, org2.PublicId, WithGrantScopeIds([]string{proj2.PublicId}))
},
expectRemove: 0,
expectRoleVersionChange: 0,
inputScopes: []string{org1.PublicId, org2.PublicId},
finalScopes: []string{proj2.PublicId},
wantErr: false,
},
{
name: "project role remove this",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, proj1.PublicId, WithGrantScopeIds([]string{globals.GrantScopeThis}))
},
inputScopes: []string{globals.GrantScopeThis},
wantErr: false,
expectRemove: 1,
expectRoleVersionChange: 1,
finalScopes: []string{},
},
{
name: "project role remove this without this grant",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, proj1.PublicId, WithGrantScopeIds([]string{"testing-none"}))
},
inputScopes: []string{globals.GrantScopeThis},
wantErr: false,
expectRemove: 0,
expectRoleVersionChange: 0,
finalScopes: []string{},
},
{
name: "project role remove this individual scope",
setupRole: func(t *testing.T) *Role {
return TestRole(t, conn, proj1.PublicId)
},
inputScopes: []string{proj2.PublicId},
wantErr: false,
expectRemove: 0,
expectRoleVersionChange: 0,
finalScopes: []string{globals.GrantScopeThis},
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
r := tc.setupRole(t)
removed, err := iamRepo.DeleteRoleGrantScopes(ctx, r.PublicId, r.Version, tc.inputScopes)
if tc.wantErr {
require.Error(t, err)
require.ErrorContains(t, err, tc.wantErrMsg)
afterRole, _, _, _, err := iamRepo.LookupRole(ctx, r.PublicId)
require.NoError(t, err)
require.Equal(t, r.Version, afterRole.Version)
return
}
require.NoError(t, err)
require.Equal(t, tc.expectRemove, removed)
afterRole, _, _, afterGrantScopes, err := iamRepo.LookupRole(ctx, r.PublicId)
require.NoError(t, err)
var afterGrantScopeIds []string
for _, grantScope := range afterGrantScopes {
require.Equal(t, r.PublicId, grantScope.RoleId)
afterGrantScopeIds = append(afterGrantScopeIds, grantScope.ScopeIdOrSpecial)
}
require.ElementsMatch(t, tc.finalScopes, afterGrantScopeIds)
require.Equal(t, r.Version+tc.expectRoleVersionChange, afterRole.Version)
})
}
}
func roleScopesToMap(t *testing.T, roleGrantScopes []*RoleGrantScope) map[string][]string {
t.Helper()
m := map[string][]string{}
for _, e := range roleGrantScopes {
scopes, ok := m[e.RoleId]
if !ok {
m[e.RoleId] = []string{e.ScopeIdOrSpecial}
continue
}
m[e.RoleId] = append(scopes, e.ScopeIdOrSpecial)
}
return m
}
// TestGrantsForUser_ACL_Allowed calls GrantsForUsers, parses the ACL, then calls `Allowed` to validate
// if the request is allowed (granted permission to take action)
func TestGrantsForUser_ACL_Allowed(t *testing.T) {
ctx := context.Background()
conn, _ := db.TestSetup(t, "postgres")
wrap := db.TestWrapper(t)
repo := TestRepo(t, conn, wrap)
user := TestUser(t, repo, "global")
// Create a series of scopes with roles in each. We'll create two of each
// kind to ensure we're not just picking up the first role in each.
// The first org/project do not have any direct grants to the user. They
// contain roles but the user is not a principal.
noGrantOrg1, noGrantProj1 := TestScopes(
t,
repo,
WithSkipAdminRoleCreation(true),
WithSkipDefaultRoleCreation(true),
)
noGrantOrg1Role := TestRole(t, conn, noGrantOrg1.PublicId)
TestRoleGrant(t, conn, noGrantOrg1Role.PublicId, "ids=*;type=scope;actions=*")
noGrantProj1Role := TestRole(t, conn, noGrantProj1.PublicId)
TestRoleGrant(t, conn, noGrantProj1Role.PublicId, "ids=*;type=*;actions=*")
noGrantOrg2, noGrantProj2 := TestScopes(
t,
repo,
WithSkipAdminRoleCreation(true),
WithSkipDefaultRoleCreation(true),
)
noGrantOrg2Role := TestRole(t, conn, noGrantOrg2.PublicId)
TestRoleGrant(t, conn, noGrantOrg2Role.PublicId, "ids=*;type=scope;actions=*")
noGrantProj2Role := TestRole(t, conn, noGrantProj2.PublicId)
TestRoleGrant(t, conn, noGrantProj2Role.PublicId, "ids=*;type=*;actions=*")
// The second org/project set contains direct grants, but without
// inheritance. We create two roles in each project.
directGrantOrg1, directGrantProj1a := TestScopes(
t,
repo,
WithSkipAdminRoleCreation(true),
WithSkipDefaultRoleCreation(true),
)
directGrantProj1b := TestProject(
t,
repo,
directGrantOrg1.PublicId,
WithSkipAdminRoleCreation(true),
WithSkipDefaultRoleCreation(true),
)
directGrantOrg1Role := TestRole(t, conn, directGrantOrg1.PublicId)
TestUserRole(t, conn, directGrantOrg1Role.PublicId, user.PublicId)
directGrantOrg1RoleGrant1 := "ids=*;type=*;actions=*"
TestRoleGrant(t, conn, directGrantOrg1Role.PublicId, directGrantOrg1RoleGrant1)
directGrantProj1aRole := TestRole(t, conn, directGrantProj1a.PublicId)
TestUserRole(t, conn, directGrantProj1aRole.PublicId, user.PublicId)
directGrantProj1aRoleGrant := "ids=*;type=target;actions=authorize-session,read"
TestRoleGrant(t, conn, directGrantProj1aRole.PublicId, directGrantProj1aRoleGrant)
directGrantProj1bRole := TestRole(t, conn, directGrantProj1b.PublicId)
TestUserRole(t, conn, directGrantProj1bRole.PublicId, user.PublicId)
directGrantProj1bRoleGrant := "ids=*;type=session;actions=list,read"
TestRoleGrant(t, conn, directGrantProj1bRole.PublicId, directGrantProj1bRoleGrant)
directGrantOrg2, directGrantProj2a := TestScopes(
t,
repo,
WithSkipAdminRoleCreation(true),
WithSkipDefaultRoleCreation(true),
)
directGrantProj2b := TestProject(
t,
repo,
directGrantOrg2.PublicId,
WithSkipAdminRoleCreation(true),
WithSkipDefaultRoleCreation(true),
)
directGrantOrg2Role := TestRole(t, conn, directGrantOrg2.PublicId,
WithGrantScopeIds([]string{
globals.GrantScopeThis,
directGrantProj2a.PublicId,
}))
TestUserRole(t, conn, directGrantOrg2Role.PublicId, user.PublicId)
directGrantOrg2RoleGrant1 := "ids=*;type=user;actions=*"
TestRoleGrant(t, conn, directGrantOrg2Role.PublicId, directGrantOrg2RoleGrant1)
directGrantOrg2RoleGrant2 := "ids=*;type=group;actions=list,read"
TestRoleGrant(t, conn, directGrantOrg2Role.PublicId, directGrantOrg2RoleGrant2)
directGrantOrg2RoleGrant3 := "ids=*;type=credential-store;actions=*"
TestRoleGrant(t, conn, directGrantOrg2Role.PublicId, directGrantOrg2RoleGrant3)
directGrantProj2aRole := TestRole(t, conn, directGrantProj2a.PublicId)
TestUserRole(t, conn, directGrantProj2aRole.PublicId, user.PublicId)
directGrantProj2aRoleGrant := "ids=hcst_abcd1234,hcst_1234abcd;actions=*"
TestRoleGrant(t, conn, directGrantProj2aRole.PublicId, directGrantProj2aRoleGrant)
directGrantProj2bRole := TestRole(t, conn, directGrantProj2b.PublicId)
TestUserRole(t, conn, directGrantProj2bRole.PublicId, user.PublicId)
directGrantProj2bRoleGrant := "ids=cs_abcd1234;actions=read,update"
TestRoleGrant(t, conn, directGrantProj2bRole.PublicId, directGrantProj2bRoleGrant)
// For the third set we create a couple of orgs/projects and then use
// globals.GrantScopeChildren.
childGrantOrg1, childGrantOrg1Proj := TestScopes(
t,
repo,
WithSkipAdminRoleCreation(true),
WithSkipDefaultRoleCreation(true),
)
childGrantOrg1Role := TestRole(t, conn, childGrantOrg1.PublicId,
WithGrantScopeIds([]string{
globals.GrantScopeChildren,
}))
TestUserRole(t, conn, childGrantOrg1Role.PublicId, user.PublicId)
childGrantOrg1RoleGrant := "ids=*;type=host-set;actions=add-hosts,remove-hosts"
TestRoleGrant(t, conn, childGrantOrg1Role.PublicId, childGrantOrg1RoleGrant)
childGrantOrg2, childGrantOrg2Proj := TestScopes(
t,
repo,
WithSkipAdminRoleCreation(true),
WithSkipDefaultRoleCreation(true),
)
childGrantOrg2Role := TestRole(t, conn, childGrantOrg2.PublicId,
WithGrantScopeIds([]string{
globals.GrantScopeChildren,
}))
TestUserRole(t, conn, childGrantOrg2Role.PublicId, user.PublicId)
childGrantOrg2RoleGrant1 := "ids=*;type=session;actions=cancel:self"
TestRoleGrant(t, conn, childGrantOrg2Role.PublicId, childGrantOrg2RoleGrant1)
childGrantOrg2RoleGrant2 := "ids=*;type=session;actions=read:self"
TestRoleGrant(t, conn, childGrantOrg2Role.PublicId, childGrantOrg2RoleGrant2)
childGrantOrg3RoleGrant3 := "ids=*;type=group;actions=delete"
TestRoleGrant(t, conn, childGrantOrg2Role.PublicId, childGrantOrg3RoleGrant3)
// Finally, let's create some roles at global scope with children and
// descendants grants
childGrantGlobalRole := TestRole(t, conn, scope.Global.String(),
WithGrantScopeIds([]string{
globals.GrantScopeChildren,
}))
TestUserRole(t, conn, childGrantGlobalRole.PublicId, globals.AnyAuthenticatedUserId)
childGrantGlobalRoleGrant := "ids=*;type=account;actions=*"
TestRoleGrant(t, conn, childGrantGlobalRole.PublicId, childGrantGlobalRoleGrant)
descendantGrantGlobalRole := TestRole(t, conn, scope.Global.String(),
WithGrantScopeIds([]string{
globals.GrantScopeDescendants,
}))
TestUserRole(t, conn, descendantGrantGlobalRole.PublicId, globals.AnyAuthenticatedUserId)
descendantGrantGlobalRoleGrant := "ids=*;type=group;actions=*"
TestRoleGrant(t, conn, descendantGrantGlobalRole.PublicId, descendantGrantGlobalRoleGrant)
type testCase struct {
name string
res perms.Resource
act action.Type
shouldWork bool
}
testCases := []testCase{}
// These test cases should fail because the grants are in roles where
// the user is not a principal
{
testCases = append(testCases, testCase{
name: "nogrant-a",
res: perms.Resource{
ScopeId: noGrantOrg1.PublicId,
Id: "u_abcd1234",
Type: resource.Scope,
ParentScopeId: scope.Global.String(),
},
act: action.Read,
}, testCase{
name: "nogrant-b",
res: perms.Resource{
ScopeId: noGrantProj1.PublicId,
Id: "hsts_abcd1234",
Type: resource.HostSet,
ParentScopeId: noGrantOrg1.String(),
},
act: action.Read,
}, testCase{
name: "nogrant-c",
res: perms.Resource{
ScopeId: noGrantOrg2.PublicId,
Id: "u_abcd1234",
Type: resource.Scope,
ParentScopeId: scope.Global.String(),
},
act: action.Read,
}, testCase{
name: "nogrant-d",
res: perms.Resource{
ScopeId: noGrantProj2.PublicId,
Id: "r_abcd1234",
Type: resource.Role,
ParentScopeId: noGrantOrg2.String(),
},
act: action.Read,
},
)
}
// These test cases are for org1 and its projects where the grants are
// direct, not via children/descendants. They test some actions that
// should work and some that shouldn't.
{
testCases = append(testCases, testCase{
name: "direct-a",
res: perms.Resource{
ScopeId: directGrantOrg1.PublicId,
Id: "u_abcd1234",
Type: resource.User,
ParentScopeId: scope.Global.String(),
},
act: action.Read,
shouldWork: true,
}, testCase{
name: "direct-b",
res: perms.Resource{
ScopeId: directGrantOrg1.PublicId,
Id: "r_abcd1234",
Type: resource.Role,
ParentScopeId: scope.Global.String(),
},
act: action.Read,
shouldWork: true,
}, testCase{
name: "direct-c",
res: perms.Resource{
ScopeId: directGrantProj1a.PublicId,
Id: "ttcp_abcd1234",
Type: resource.Target,
ParentScopeId: directGrantOrg1.PublicId,
},
act: action.AuthorizeSession,
shouldWork: true,
}, testCase{
name: "direct-d",
res: perms.Resource{
ScopeId: directGrantProj1a.PublicId,
Id: "s_abcd1234",
Type: resource.Session,
ParentScopeId: directGrantOrg1.PublicId,
},
act: action.Read,
}, testCase{
name: "direct-e",
res: perms.Resource{
ScopeId: directGrantProj1b.PublicId,
Id: "ttcp_abcd1234",
Type: resource.Target,
ParentScopeId: directGrantOrg1.PublicId,
},
act: action.AuthorizeSession,
}, testCase{
name: "direct-f",
res: perms.Resource{
ScopeId: directGrantProj1b.PublicId,
Id: "s_abcd1234",
Type: resource.Session,
ParentScopeId: directGrantOrg1.PublicId,
},
act: action.Read,
shouldWork: true,
},
)
}
// These test cases are for org2 and its projects where the grants are
// direct, not via children/descendants. They test some actions that
// should work and some that shouldn't.
{
testCases = append(testCases, testCase{
name: "direct-g",
res: perms.Resource{
ScopeId: directGrantOrg2.PublicId,
Id: "u_abcd1234",
Type: resource.User,
ParentScopeId: scope.Global.String(),
},
act: action.Update,
shouldWork: true,
}, testCase{
name: "direct-m",
res: perms.Resource{
ScopeId: directGrantOrg2.PublicId,
Id: "at_abcd1234",
Type: resource.AuthToken,
ParentScopeId: scope.Global.String(),
},
act: action.Update,
}, testCase{
name: "direct-h",
res: perms.Resource{
ScopeId: directGrantOrg2.PublicId,
Id: "acct_abcd1234",
Type: resource.Account,
ParentScopeId: scope.Global.String(),
},
act: action.Delete,
shouldWork: true,
}, testCase{
name: "direct-i",
res: perms.Resource{
ScopeId: directGrantProj2a.PublicId,
Type: resource.Group,
ParentScopeId: directGrantOrg2.PublicId,
},
act: action.List,
shouldWork: true,
}, testCase{
name: "direct-j",
res: perms.Resource{
ScopeId: directGrantProj2a.PublicId,
Id: "r_abcd1234",
Type: resource.Role,
ParentScopeId: directGrantOrg2.PublicId,
},
act: action.Read,
}, testCase{
name: "direct-n",
res: perms.Resource{
ScopeId: directGrantProj2a.PublicId,
Id: "cs_abcd1234",
Type: resource.CredentialStore,
ParentScopeId: directGrantOrg2.PublicId,
},
act: action.Read,
shouldWork: true,
}, testCase{
name: "direct-k",
res: perms.Resource{
ScopeId: directGrantProj2a.PublicId,
Id: "hcst_abcd1234",
Type: resource.HostCatalog,
ParentScopeId: directGrantOrg2.PublicId,
},
act: action.Read,
shouldWork: true,
}, testCase{
name: "direct-l",
res: perms.Resource{
ScopeId: directGrantProj2b.PublicId,
Id: "cs_abcd1234",
Type: resource.CredentialStore,
ParentScopeId: directGrantOrg2.PublicId,
},
act: action.Update,
shouldWork: true,
},
testCase{
name: "direct-m",
res: perms.Resource{
ScopeId: directGrantProj2b.PublicId,
Id: "cl_abcd1234",
Type: resource.CredentialLibrary,
ParentScopeId: directGrantOrg2.PublicId,
},
act: action.Update,
},
)
}
// These test cases are child grants
{
testCases = append(testCases, testCase{
name: "children-a",
res: perms.Resource{
ScopeId: scope.Global.String(),
Id: "a_abcd1234",
Type: resource.Account,
},
act: action.Update,
}, testCase{
name: "children-b",
res: perms.Resource{
ScopeId: noGrantOrg1.PublicId,
Id: "a_abcd1234",
Type: resource.Account,
ParentScopeId: scope.Global.String(),
},
act: action.Update,
shouldWork: true,
}, testCase{
name: "children-c",
res: perms.Resource{
ScopeId: directGrantOrg1.PublicId,
Id: "a_abcd1234",
Type: resource.Account,
ParentScopeId: scope.Global.String(),
},
act: action.Update,
shouldWork: true,
}, testCase{
name: "children-d",
res: perms.Resource{
ScopeId: directGrantOrg2.PublicId,
Id: "a_abcd1234",
Type: resource.Account,
ParentScopeId: scope.Global.String(),
},
act: action.Update,
shouldWork: true,
}, testCase{
name: "children-e",
res: perms.Resource{
ScopeId: childGrantOrg2.PublicId,
Id: "oidc_abcd1234",
Type: resource.ManagedGroup,
ParentScopeId: scope.Global.String(),
},
act: action.Delete,
}, testCase{
name: "children-f",
res: perms.Resource{
ScopeId: childGrantOrg1Proj.PublicId,
Id: "s_abcd1234",
Type: resource.Session,
ParentScopeId: childGrantOrg1.PublicId,
},
act: action.CancelSelf,
}, testCase{
name: "children-g",
res: perms.Resource{
ScopeId: childGrantOrg2Proj.PublicId,
Id: "s_abcd1234",
Type: resource.Session,
ParentScopeId: childGrantOrg2.PublicId,
},
act: action.CancelSelf,
shouldWork: true,
}, testCase{
name: "children-h",
res: perms.Resource{
ScopeId: childGrantOrg2Proj.PublicId,
Id: "s_abcd1234",
Type: resource.Session,
ParentScopeId: childGrantOrg2.PublicId,
},
act: action.CancelSelf,
shouldWork: true,
}, testCase{
name: "children-i",
res: perms.Resource{
ScopeId: childGrantOrg1.PublicId,
Id: "sb_abcd1234",
Type: resource.StorageBucket,
ParentScopeId: scope.Global.String(),
},
act: action.Update,
}, testCase{
name: "children-j",
res: perms.Resource{
ScopeId: childGrantOrg1Proj.PublicId,
Id: "hsst_abcd1234",
Type: resource.HostSet,
ParentScopeId: childGrantOrg1.PublicId,
},
act: action.AddHosts,
shouldWork: true,
}, testCase{
name: "children-k",
res: perms.Resource{
ScopeId: childGrantOrg2Proj.PublicId,
Id: "hsst_abcd1234",
Type: resource.HostSet,
ParentScopeId: childGrantOrg2.PublicId,
},
act: action.AddHosts,
}, testCase{
name: "children-l",
res: perms.Resource{
ScopeId: childGrantOrg2Proj.PublicId,
Id: "hctg_abcd1234",
Type: resource.HostCatalog,
ParentScopeId: childGrantOrg2.PublicId,
},
act: action.Update,
},
)
}
// These test cases are global descendants grants
{
testCases = append(testCases, testCase{
name: "descendants-a",
res: perms.Resource{
ScopeId: scope.Global.String(),
Id: "g_abcd1234",
Type: resource.Group,
},
act: action.Update,
}, testCase{
name: "descendants-b",
res: perms.Resource{
ScopeId: noGrantProj1.PublicId,
Id: "g_abcd1234",
Type: resource.Group,
ParentScopeId: noGrantOrg1.PublicId,
},
act: action.Update,
shouldWork: true,
}, testCase{
name: "descendants-c",
res: perms.Resource{
ScopeId: directGrantOrg2.PublicId,
Id: "g_abcd1234",
Type: resource.Group,
ParentScopeId: scope.Global.String(),
},
act: action.Update,
shouldWork: true,
}, testCase{
name: "descendants-d",
res: perms.Resource{
ScopeId: directGrantProj1a.PublicId,
Id: "g_abcd1234",
Type: resource.Group,
ParentScopeId: directGrantOrg1.PublicId,
},
act: action.Update,
shouldWork: true,
}, testCase{
name: "descendants-e",
res: perms.Resource{
ScopeId: directGrantProj1a.PublicId,
Id: "g_abcd1234",
Type: resource.Group,
ParentScopeId: directGrantOrg1.PublicId,
},
act: action.Update,
shouldWork: true,
}, testCase{
name: "descendants-f",
res: perms.Resource{
ScopeId: directGrantProj2b.PublicId,
Id: "g_abcd1234",
Type: resource.Group,
ParentScopeId: directGrantOrg2.PublicId,
},
act: action.Update,
shouldWork: true,
},
)
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
grantTuples, err := repo.GrantsForUser(ctx, user.PublicId, []resource.Type{tc.res.Type}, tc.res.ScopeId)
require.NoError(t, err)
grants := make([]perms.Grant, 0, len(grantTuples))
for _, gt := range grantTuples {
grant, err := perms.Parse(ctx, gt)
require.NoError(t, err)
grants = append(grants, grant)
}
acl := perms.NewACL(grants...)
assert.True(t, acl.Allowed(tc.res, tc.act, "u_abc123").Authorized == tc.shouldWork)
})
}
}
// TestGrantsForUser_ACL_parsing calls GrantsForUsers then parse the result's ACL to validate that the
// returned map matches the expectation
func TestGrantsForUser_ACL_parsing(t *testing.T) {
ctx := context.Background()
conn, _ := db.TestSetup(t, "postgres")
wrap := db.TestWrapper(t)
repo := TestRepo(t, conn, wrap)
user := TestUser(t, repo, "global")
// Create a series of scopes with roles in each. We'll create two of each
// kind to ensure we're not just picking up the first role in each.
// The first org/project do not have any direct grants to the user. They
// contain roles but the user is not a principal.
noGrantOrg1, noGrantProj1 := TestScopes(
t,
repo,
WithSkipAdminRoleCreation(true),
WithSkipDefaultRoleCreation(true),
)
noGrantOrg1Role := TestRole(t, conn, noGrantOrg1.PublicId)
TestRoleGrant(t, conn, noGrantOrg1Role.PublicId, "ids=*;type=scope;actions=*")
noGrantProj1Role := TestRole(t, conn, noGrantProj1.PublicId)
TestRoleGrant(t, conn, noGrantProj1Role.PublicId, "ids=*;type=*;actions=*")
noGrantOrg2, noGrantProj2 := TestScopes(
t,
repo,
WithSkipAdminRoleCreation(true),
WithSkipDefaultRoleCreation(true),
)
noGrantOrg2Role := TestRole(t, conn, noGrantOrg2.PublicId)
TestRoleGrant(t, conn, noGrantOrg2Role.PublicId, "ids=*;type=scope;actions=*")
noGrantProj2Role := TestRole(t, conn, noGrantProj2.PublicId)
TestRoleGrant(t, conn, noGrantProj2Role.PublicId, "ids=*;type=*;actions=*")
// The second org/project set contains direct grants, but without
// inheritance. We create two roles in each project.
directGrantOrg1, directGrantProj1a := TestScopes(
t,
repo,
WithSkipAdminRoleCreation(true),
WithSkipDefaultRoleCreation(true),
)
directGrantProj1b := TestProject(
t,
repo,
directGrantOrg1.PublicId,
WithSkipAdminRoleCreation(true),
WithSkipDefaultRoleCreation(true),
)
directGrantOrg1Role := TestRole(t, conn, directGrantOrg1.PublicId)
TestUserRole(t, conn, directGrantOrg1Role.PublicId, user.PublicId)
directGrantOrg1RoleGrant1 := "ids=*;type=*;actions=*"
TestRoleGrant(t, conn, directGrantOrg1Role.PublicId, directGrantOrg1RoleGrant1)
directGrantOrg1RoleGrant2 := "ids=*;type=role;actions=list,read"
TestRoleGrant(t, conn, directGrantOrg1Role.PublicId, directGrantOrg1RoleGrant2)
directGrantProj1aRole := TestRole(t, conn, directGrantProj1a.PublicId)
TestUserRole(t, conn, directGrantProj1aRole.PublicId, user.PublicId)
directGrantProj1aRoleGrant := "ids=*;type=target;actions=authorize-session,read"
TestRoleGrant(t, conn, directGrantProj1aRole.PublicId, directGrantProj1aRoleGrant)
directGrantProj1bRole := TestRole(t, conn, directGrantProj1b.PublicId)
TestUserRole(t, conn, directGrantProj1bRole.PublicId, user.PublicId)
directGrantProj1bRoleGrant := "ids=*;type=session;actions=list,read"
TestRoleGrant(t, conn, directGrantProj1bRole.PublicId, directGrantProj1bRoleGrant)
directGrantOrg2, directGrantProj2a := TestScopes(
t,
repo,
WithSkipAdminRoleCreation(true),
WithSkipDefaultRoleCreation(true),
)
directGrantProj2b := TestProject(
t,
repo,
directGrantOrg2.PublicId,
WithSkipAdminRoleCreation(true),
WithSkipDefaultRoleCreation(true),
)
directGrantOrg2Role := TestRole(t, conn, directGrantOrg2.PublicId,
WithGrantScopeIds([]string{
globals.GrantScopeThis,
directGrantProj2a.PublicId,
}))
TestUserRole(t, conn, directGrantOrg2Role.PublicId, user.PublicId)
directGrantOrg2RoleGrant1 := "ids=*;type=user;actions=*"
TestRoleGrant(t, conn, directGrantOrg2Role.PublicId, directGrantOrg2RoleGrant1)
directGrantOrg2RoleGrant2 := "ids=*;type=group;actions=list,read"
TestRoleGrant(t, conn, directGrantOrg2Role.PublicId, directGrantOrg2RoleGrant2)
directGrantProj2aRole := TestRole(t, conn, directGrantProj2a.PublicId)
TestUserRole(t, conn, directGrantProj2aRole.PublicId, user.PublicId)
directGrantProj2aRoleGrant := "ids=hcst_abcd1234,hcst_1234abcd;actions=*"
TestRoleGrant(t, conn, directGrantProj2aRole.PublicId, directGrantProj2aRoleGrant)
directGrantProj2bRole := TestRole(t, conn, directGrantProj2b.PublicId)
TestUserRole(t, conn, directGrantProj2bRole.PublicId, user.PublicId)
directGrantProj2bRoleGrant := "ids=cs_abcd1234;actions=read,update"
TestRoleGrant(t, conn, directGrantProj2bRole.PublicId, directGrantProj2bRoleGrant)
// For the third set we create a couple of orgs/projects and then use
// globals.GrantScopeChildren.
childGrantOrg1, _ := TestScopes(
t,
repo,
WithSkipAdminRoleCreation(true),
WithSkipDefaultRoleCreation(true),
)
childGrantOrg1Role := TestRole(t, conn, childGrantOrg1.PublicId,
WithGrantScopeIds([]string{
globals.GrantScopeChildren,
}))
TestUserRole(t, conn, childGrantOrg1Role.PublicId, user.PublicId)
childGrantOrg1RoleGrant := "ids=*;type=host-set;actions=add-hosts,remove-hosts"
TestRoleGrant(t, conn, childGrantOrg1Role.PublicId, childGrantOrg1RoleGrant)
childGrantOrg2, _ := TestScopes(
t,
repo,
WithSkipAdminRoleCreation(true),
WithSkipDefaultRoleCreation(true),
)
childGrantOrg2Role := TestRole(t, conn, childGrantOrg2.PublicId,
WithGrantScopeIds([]string{
globals.GrantScopeChildren,
}))
TestUserRole(t, conn, childGrantOrg2Role.PublicId, user.PublicId)
childGrantOrg2RoleGrant1 := "ids=*;type=session;actions=cancel:self"
TestRoleGrant(t, conn, childGrantOrg2Role.PublicId, childGrantOrg2RoleGrant1)
childGrantOrg2RoleGrant2 := "ids=*;type=session;actions=read:self"
TestRoleGrant(t, conn, childGrantOrg2Role.PublicId, childGrantOrg2RoleGrant2)
// Finally, let's create some roles at global scope with children and
// descendants grants
childGrantGlobalRole := TestRole(t, conn, scope.Global.String(),
WithGrantScopeIds([]string{
globals.GrantScopeChildren,
}))
TestUserRole(t, conn, childGrantGlobalRole.PublicId, globals.AnyAuthenticatedUserId)
childGrantGlobalRoleGrant := "ids=*;type=account;actions=*"
TestRoleGrant(t, conn, childGrantGlobalRole.PublicId, childGrantGlobalRoleGrant)
descendantGrantGlobalRole := TestRole(t, conn, scope.Global.String(),
WithGrantScopeIds([]string{
globals.GrantScopeDescendants,
}))
TestUserRole(t, conn, descendantGrantGlobalRole.PublicId, globals.AnyAuthenticatedUserId)
descendantGrantGlobalRoleGrant := "ids=*;type=credential;actions=*"
TestRoleGrant(t, conn, descendantGrantGlobalRole.PublicId, descendantGrantGlobalRoleGrant)
t.Run("acl-grants", func(t *testing.T) {
// ACLs have to be calculated for each test because they care about different resources
t.Run("descendant-grants", func(t *testing.T) {
grantTuples, err := repo.GrantsForUser(ctx, user.PublicId, []resource.Type{resource.Credential}, globals.GlobalPrefix, WithRecursive(true))
require.NoError(t, err)
grants := make([]perms.Grant, 0, len(grantTuples))
for _, gt := range grantTuples {
grant, err := perms.Parse(ctx, gt)
require.NoError(t, err)
grants = append(grants, grant)
}
acl := perms.NewACL(grants...)
descendantGrants := acl.DescendantsGrants()
expDescendantGrants := []perms.AclGrant{
{
RoleScopeId: scope.Global.String(),
RoleParentScopeId: "",
GrantScopeId: globals.GrantScopeDescendants,
Id: "*",
Type: resource.Credential,
ActionSet: perms.ActionSet{action.All: true},
},
}
assert.ElementsMatch(t, descendantGrants, expDescendantGrants)
})
t.Run("child-grants", func(t *testing.T) {
grantTuples, err := repo.GrantsForUser(ctx, user.PublicId, []resource.Type{resource.Session}, globals.GlobalPrefix, WithRecursive(true))
require.NoError(t, err)
grants := make([]perms.Grant, 0, len(grantTuples))
for _, gt := range grantTuples {
grant, err := perms.Parse(ctx, gt)
require.NoError(t, err)
grants = append(grants, grant)
}
acl := perms.NewACL(grants...)
childrenGrants := acl.ChildrenScopeGrantMap()
expChildrenGrants := map[string][]perms.AclGrant{
childGrantOrg2.PublicId: {
{
RoleScopeId: childGrantOrg2.PublicId,
RoleParentScopeId: scope.Global.String(),
GrantScopeId: globals.GrantScopeChildren,
Id: "*",
Type: resource.Session,
ActionSet: perms.ActionSet{action.CancelSelf: true},
},
{
RoleScopeId: childGrantOrg2.PublicId,
RoleParentScopeId: scope.Global.String(),
GrantScopeId: globals.GrantScopeChildren,
Id: "*",
Type: resource.Session,
ActionSet: perms.ActionSet{action.ReadSelf: true},
},
},
}
assert.Len(t, childrenGrants, len(expChildrenGrants))
for k, v := range childrenGrants {
assert.ElementsMatch(t, v, expChildrenGrants[k])
}
})
t.Run("direct-grants", func(t *testing.T) {
grantTuples, err := repo.GrantsForUser(ctx, user.PublicId, []resource.Type{resource.Role}, globals.GlobalPrefix, WithRecursive(true))
require.NoError(t, err)
grants := make([]perms.Grant, 0, len(grantTuples))
for _, gt := range grantTuples {
grant, err := perms.Parse(ctx, gt)
require.NoError(t, err)
grants = append(grants, grant)
}
acl := perms.NewACL(grants...)
directGrants := acl.DirectScopeGrantMap()
expDirectGrants := map[string][]perms.AclGrant{
directGrantOrg1.PublicId: {
{
RoleScopeId: directGrantOrg1.PublicId,
RoleParentScopeId: scope.Global.String(),
GrantScopeId: directGrantOrg1.PublicId,
Id: "*",
Type: resource.All,
ActionSet: perms.ActionSet{action.All: true},
},
{
RoleScopeId: directGrantOrg1.PublicId,
RoleParentScopeId: scope.Global.String(),
GrantScopeId: directGrantOrg1.PublicId,
Id: "*",
Type: resource.Role,
ActionSet: perms.ActionSet{action.List: true, action.Read: true},
},
},
directGrantProj2a.PublicId: {
{
RoleScopeId: directGrantProj2a.PublicId,
RoleParentScopeId: directGrantOrg2.PublicId,
GrantScopeId: directGrantProj2a.PublicId,
Id: "hcst_abcd1234",
Type: resource.Unknown,
ActionSet: perms.ActionSet{action.All: true},
},
{
RoleScopeId: directGrantProj2a.PublicId,
RoleParentScopeId: directGrantOrg2.PublicId,
GrantScopeId: directGrantProj2a.PublicId,
Id: "hcst_1234abcd",
Type: resource.Unknown,
ActionSet: perms.ActionSet{action.All: true},
},
},
directGrantProj2b.PublicId: {
{
RoleScopeId: directGrantProj2b.PublicId,
RoleParentScopeId: directGrantOrg2.PublicId,
GrantScopeId: directGrantProj2b.PublicId,
Id: "cs_abcd1234",
Type: resource.Unknown,
ActionSet: perms.ActionSet{action.Update: true, action.Read: true},
},
},
}
assert.Len(t, directGrants, len(expDirectGrants))
for k, v := range directGrants {
assert.ElementsMatch(t, v, expDirectGrants[k])
}
})
})
}