mirror of https://github.com/hashicorp/boundary
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.
1539 lines
47 KiB
1539 lines
47 KiB
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package iam
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"math/rand"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/hashicorp/boundary/globals"
|
|
"github.com/hashicorp/boundary/internal/db"
|
|
"github.com/hashicorp/boundary/internal/errors"
|
|
"github.com/hashicorp/boundary/internal/oplog"
|
|
"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 TestRepository_AddRoleGrants(t *testing.T) {
|
|
t.Parallel()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
rw := db.New(conn)
|
|
wrapper := db.TestWrapper(t)
|
|
repo := TestRepo(t, conn, wrapper)
|
|
_, proj := TestScopes(t, repo)
|
|
role := TestRole(t, conn, proj.PublicId)
|
|
createGrantsFn := func() []string {
|
|
results := []string{}
|
|
for i := 0; i < 5; i++ {
|
|
g := fmt.Sprintf("ids=hc_%d;actions=*", i)
|
|
results = append(results, g)
|
|
}
|
|
return results
|
|
}
|
|
type args struct {
|
|
roleId string
|
|
roleVersion uint32
|
|
grants []string
|
|
opt []Option
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
wantErr bool
|
|
wantErrIs error
|
|
}{
|
|
{
|
|
name: "valid",
|
|
args: args{
|
|
roleId: role.PublicId,
|
|
roleVersion: 1,
|
|
grants: createGrantsFn(),
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "no-grants",
|
|
args: args{
|
|
roleId: role.PublicId,
|
|
roleVersion: 2,
|
|
grants: nil,
|
|
},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "bad-version",
|
|
args: args{
|
|
roleId: role.PublicId,
|
|
roleVersion: 1000,
|
|
grants: createGrantsFn(),
|
|
},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "zero-version",
|
|
args: args{
|
|
roleId: role.PublicId,
|
|
roleVersion: 0,
|
|
grants: createGrantsFn(),
|
|
},
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
db.TestDeleteWhere(t, conn, func() any { rg := allocRoleGrant(); return &rg }(), "1=1")
|
|
got, err := repo.AddRoleGrants(context.Background(), tt.args.roleId, tt.args.roleVersion, tt.args.grants, tt.args.opt...)
|
|
if tt.wantErr {
|
|
require.Error(err)
|
|
if tt.wantErrIs != nil {
|
|
assert.Truef(errors.Is(err, tt.wantErrIs), "unexpected error %s", err.Error())
|
|
}
|
|
return
|
|
}
|
|
require.NoError(err)
|
|
gotRoleGrant := map[string]*RoleGrant{}
|
|
for _, r := range got {
|
|
gotRoleGrant[r.CanonicalGrant] = r
|
|
}
|
|
|
|
err = db.TestVerifyOplog(t, rw, role.PublicId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second))
|
|
assert.NoError(err)
|
|
|
|
foundRoleGrants, err := repo.ListRoleGrants(context.Background(), role.PublicId)
|
|
require.NoError(err)
|
|
// Create a map of grants to check against
|
|
grantSet := make(map[string]bool, len(tt.args.grants))
|
|
for _, grant := range tt.args.grants {
|
|
grantSet[grant] = true
|
|
}
|
|
for _, r := range foundRoleGrants {
|
|
roleGrant := gotRoleGrant[r.CanonicalGrant]
|
|
assert.NotEmpty(roleGrant)
|
|
assert.Equal(roleGrant.GetRoleId(), r.GetRoleId())
|
|
assert.NotEmpty(grantSet[roleGrant.CanonicalGrant])
|
|
delete(grantSet, roleGrant.CanonicalGrant)
|
|
}
|
|
assert.Empty(grantSet)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRepository_ListRoleGrants(t *testing.T) {
|
|
t.Parallel()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
const testLimit = 10
|
|
wrapper := db.TestWrapper(t)
|
|
repo := TestRepo(t, conn, wrapper, WithLimit(testLimit))
|
|
org, proj := TestScopes(t, repo)
|
|
|
|
type args struct {
|
|
withRoleId string
|
|
opt []Option
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
createCnt int
|
|
createGrantScopeId string
|
|
args args
|
|
wantCnt int
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "no-limit",
|
|
createCnt: repo.defaultLimit + 2,
|
|
createGrantScopeId: org.PublicId,
|
|
args: args{
|
|
opt: []Option{WithLimit(-1)},
|
|
},
|
|
wantCnt: repo.defaultLimit + 2,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "no-limit-proj-group",
|
|
createCnt: repo.defaultLimit + 2,
|
|
createGrantScopeId: proj.PublicId,
|
|
args: args{
|
|
opt: []Option{WithLimit(-1)},
|
|
},
|
|
wantCnt: repo.defaultLimit + 2,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "default-limit",
|
|
createCnt: repo.defaultLimit + 2,
|
|
createGrantScopeId: org.PublicId,
|
|
wantCnt: repo.defaultLimit,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "custom-limit",
|
|
createCnt: repo.defaultLimit + 2,
|
|
createGrantScopeId: org.PublicId,
|
|
args: args{
|
|
opt: []Option{WithLimit(3)},
|
|
},
|
|
wantCnt: 3,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "bad-role-id",
|
|
createCnt: 2,
|
|
createGrantScopeId: org.PublicId,
|
|
args: args{
|
|
withRoleId: "bad-id",
|
|
},
|
|
wantCnt: 0,
|
|
wantErr: false,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
db.TestDeleteWhere(t, conn, func() any { r := allocRole(); return &r }(), "1=1")
|
|
role := TestRole(t, conn, tt.createGrantScopeId)
|
|
roleGrants := make([]string, 0, tt.createCnt)
|
|
for i := 0; i < tt.createCnt; i++ {
|
|
roleGrants = append(roleGrants, fmt.Sprintf("ids=h_%d;actions=*", i))
|
|
}
|
|
testRoles, err := repo.AddRoleGrants(context.Background(), role.PublicId, role.Version, roleGrants, tt.args.opt...)
|
|
require.NoError(err)
|
|
assert.Equal(tt.createCnt, len(testRoles))
|
|
|
|
var roleId string
|
|
switch {
|
|
case tt.args.withRoleId != "":
|
|
roleId = tt.args.withRoleId
|
|
default:
|
|
roleId = role.PublicId
|
|
}
|
|
got, err := repo.ListRoleGrants(context.Background(), roleId, tt.args.opt...)
|
|
if tt.wantErr {
|
|
require.Error(err)
|
|
return
|
|
}
|
|
require.NoError(err)
|
|
assert.Equal(tt.wantCnt, len(got))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRepository_DeleteRoleGrants(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := context.Background()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
rw := db.New(conn)
|
|
wrapper := db.TestWrapper(t)
|
|
repo := TestRepo(t, conn, wrapper)
|
|
org, _ := TestScopes(t, repo)
|
|
|
|
type args struct {
|
|
role *Role
|
|
roleIdOverride *string
|
|
roleVersionOverride *uint32
|
|
grantStringsOverride []string
|
|
createCnt int
|
|
deleteCnt int
|
|
opt []Option
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
wantRowsDeleted int
|
|
wantErr bool
|
|
wantIsErr errors.Code
|
|
}{
|
|
{
|
|
name: "valid",
|
|
args: args{
|
|
role: TestRole(t, conn, org.PublicId),
|
|
createCnt: 5,
|
|
deleteCnt: 5,
|
|
},
|
|
wantRowsDeleted: 5,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "valid-keeping-some",
|
|
args: args{
|
|
role: TestRole(t, conn, org.PublicId),
|
|
createCnt: 5,
|
|
deleteCnt: 3,
|
|
},
|
|
wantRowsDeleted: 3,
|
|
wantErr: false,
|
|
},
|
|
|
|
{
|
|
name: "no-deletes",
|
|
args: args{
|
|
role: TestRole(t, conn, org.PublicId),
|
|
createCnt: 5,
|
|
},
|
|
wantRowsDeleted: 0,
|
|
wantErr: true,
|
|
wantIsErr: errors.InvalidParameter,
|
|
},
|
|
|
|
{
|
|
name: "not-found",
|
|
args: args{
|
|
role: TestRole(t, conn, org.PublicId),
|
|
roleIdOverride: func() *string { id := testId(t); return &id }(),
|
|
createCnt: 5,
|
|
deleteCnt: 5,
|
|
},
|
|
wantRowsDeleted: 0,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "missing-role-id",
|
|
args: args{
|
|
role: TestRole(t, conn, org.PublicId),
|
|
roleIdOverride: func() *string { id := ""; return &id }(),
|
|
createCnt: 5,
|
|
deleteCnt: 5,
|
|
},
|
|
wantRowsDeleted: 0,
|
|
wantErr: true,
|
|
wantIsErr: errors.InvalidParameter,
|
|
},
|
|
{
|
|
name: "invalid-grant-strings",
|
|
args: args{
|
|
role: TestRole(t, conn, org.PublicId),
|
|
grantStringsOverride: []string{"ids=s_87;actions=*"},
|
|
createCnt: 5,
|
|
deleteCnt: 3,
|
|
},
|
|
wantRowsDeleted: 2,
|
|
},
|
|
{
|
|
name: "zero-version",
|
|
args: args{
|
|
role: TestRole(t, conn, org.PublicId),
|
|
createCnt: 5,
|
|
deleteCnt: 5,
|
|
roleVersionOverride: func() *uint32 { v := uint32(0); return &v }(),
|
|
},
|
|
wantRowsDeleted: 0,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "bad-version",
|
|
args: args{
|
|
role: TestRole(t, conn, org.PublicId),
|
|
createCnt: 5,
|
|
deleteCnt: 5,
|
|
roleVersionOverride: func() *uint32 { v := uint32(1000); return &v }(),
|
|
},
|
|
wantRowsDeleted: 0,
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
db.TestDeleteWhere(t, conn, func() any { rg := allocRoleGrant(); return &rg }(), "1=1")
|
|
grants := make([]*RoleGrant, 0, tt.args.createCnt)
|
|
grantStrings := make([]string, 0, tt.args.createCnt)
|
|
for i := 0; i < tt.args.createCnt; i++ {
|
|
g, err := NewRoleGrant(ctx, tt.args.role.PublicId, fmt.Sprintf("actions=*;ids=s_%d", i), tt.args.opt...)
|
|
require.NoError(err)
|
|
grantStrings = append(grantStrings, g.RawGrant)
|
|
grants = append(grants, g)
|
|
}
|
|
roleGrants, err := repo.AddRoleGrants(context.Background(), tt.args.role.PublicId, 1, grantStrings, tt.args.opt...)
|
|
require.NoError(err)
|
|
assert.Equal(tt.args.createCnt, len(roleGrants))
|
|
|
|
deleteCanonicalGrants := make([]string, 0, tt.args.deleteCnt)
|
|
deleteGrants := make([]string, 0, tt.args.deleteCnt)
|
|
for i := 0; i < tt.args.deleteCnt; i++ {
|
|
deleteCanonicalGrants = append(deleteCanonicalGrants, grants[i].CanonicalGrant)
|
|
deleteGrants = append(deleteGrants, fmt.Sprintf("ids=s_%d;actions=*", i))
|
|
}
|
|
for i, override := range tt.args.grantStringsOverride {
|
|
deleteCanonicalGrants = deleteCanonicalGrants[1:]
|
|
deleteGrants[i] = override
|
|
}
|
|
|
|
var roleId string
|
|
switch {
|
|
case tt.args.roleIdOverride != nil:
|
|
roleId = *tt.args.roleIdOverride
|
|
default:
|
|
roleId = tt.args.role.PublicId
|
|
}
|
|
var roleVersion uint32
|
|
switch {
|
|
case tt.args.roleVersionOverride != nil:
|
|
roleVersion = *tt.args.roleVersionOverride
|
|
default:
|
|
roleVersion = 2
|
|
}
|
|
deletedRows, err := repo.DeleteRoleGrants(context.Background(), roleId, roleVersion, deleteGrants, tt.args.opt...)
|
|
if tt.wantErr {
|
|
assert.Error(err)
|
|
assert.Equal(0, deletedRows)
|
|
assert.Truef(errors.Match(errors.T(tt.wantIsErr), err), "unexpected error %s", err.Error())
|
|
err = db.TestVerifyOplog(t, rw, tt.args.role.PublicId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second))
|
|
assert.Error(err)
|
|
assert.True(errors.IsNotFoundError(err))
|
|
return
|
|
}
|
|
require.NoError(err)
|
|
assert.Equal(tt.wantRowsDeleted, deletedRows)
|
|
|
|
roleGrants = []*RoleGrant{}
|
|
require.NoError(repo.reader.SearchWhere(context.Background(), &roleGrants, "role_id = ?", []any{roleId}))
|
|
found := map[string]bool{}
|
|
for _, rg := range roleGrants {
|
|
found[rg.CanonicalGrant] = true
|
|
}
|
|
for _, i := range deleteCanonicalGrants {
|
|
assert.False(found[i])
|
|
}
|
|
|
|
err = db.TestVerifyOplog(t, rw, tt.args.role.PublicId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second))
|
|
assert.NoError(err)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRepository_SetRoleGrants_Randomize(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := context.Background()
|
|
require := require.New(t)
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
wrapper := db.TestWrapper(t)
|
|
repo := TestRepo(t, conn, wrapper)
|
|
org, _ := TestScopes(t, repo)
|
|
role := TestRole(t, conn, org.PublicId)
|
|
db.TestDeleteWhere(t, conn, func() any { i := allocRoleGrant(); return &i }(), "1=1")
|
|
|
|
type roleGrantWrapper struct {
|
|
grantString string
|
|
enabled bool
|
|
}
|
|
|
|
totalCnt := 30
|
|
grants := make([]*roleGrantWrapper, 0, totalCnt)
|
|
for i := 0; i < totalCnt; i++ {
|
|
g, err := NewRoleGrant(ctx, role.PublicId, fmt.Sprintf("ids=s_%d;actions=*", i))
|
|
require.NoError(err)
|
|
grants = append(grants, &roleGrantWrapper{
|
|
grantString: g.RawGrant,
|
|
})
|
|
}
|
|
|
|
// Each loop will set some number of role grants to enabled or disabled
|
|
// randomly and then validate after setting that what's set matches
|
|
var grantsToSet []string
|
|
var expected map[string]bool
|
|
for i := 1; i <= totalCnt; i++ {
|
|
grantsToSet = make([]string, 0, totalCnt)
|
|
expected = make(map[string]bool, totalCnt)
|
|
prng := rand.New(rand.NewSource(time.Now().UnixNano()))
|
|
for _, rgw := range grants {
|
|
rgw.enabled = prng.Int()%2 == 0
|
|
if rgw.enabled {
|
|
grantsToSet = append(grantsToSet, rgw.grantString)
|
|
expected[rgw.grantString] = true
|
|
}
|
|
}
|
|
|
|
// First time, run a couple of error conditions
|
|
if i == 1 {
|
|
_, _, err := repo.SetRoleGrants(ctx, "", 1, []string{})
|
|
require.Error(err)
|
|
_, _, err = repo.SetRoleGrants(ctx, role.PublicId, 1, nil)
|
|
require.Error(err)
|
|
}
|
|
|
|
_, _, err := repo.SetRoleGrants(ctx, role.PublicId, uint32(i), grantsToSet)
|
|
require.NoError(err)
|
|
|
|
roleGrants, err := repo.ListRoleGrants(ctx, role.PublicId)
|
|
require.NoError(err)
|
|
require.Equal(len(grantsToSet), len(roleGrants))
|
|
for _, rg := range roleGrants {
|
|
require.Contains(expected, rg.CanonicalGrant)
|
|
delete(expected, rg.CanonicalGrant)
|
|
}
|
|
require.Empty(expected)
|
|
}
|
|
|
|
// At the end, set to explicitly empty and make sure all are cleared out
|
|
_, _, err := repo.SetRoleGrants(context.Background(), role.PublicId, uint32(totalCnt+1), []string{})
|
|
require.NoError(err)
|
|
|
|
roleGrants, err := repo.ListRoleGrants(context.Background(), role.PublicId)
|
|
require.NoError(err)
|
|
require.Empty(roleGrants)
|
|
}
|
|
|
|
func TestRepository_SetRoleGrants_Parameters(t *testing.T) {
|
|
t.Parallel()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
wrapper := db.TestWrapper(t)
|
|
repo := TestRepo(t, conn, wrapper)
|
|
org, _ := TestScopes(t, repo)
|
|
role := TestRole(t, conn, org.PublicId)
|
|
type args struct {
|
|
roleId string
|
|
roleVersion uint32
|
|
grants []string
|
|
opt []Option
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want []*RoleGrant
|
|
wantAffectedRows int
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "missing-roleid",
|
|
args: args{
|
|
roleId: "",
|
|
roleVersion: 1,
|
|
grants: []string{"ids=s_1;actions=*"},
|
|
},
|
|
want: nil,
|
|
wantAffectedRows: 0,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "bad-roleid",
|
|
args: args{
|
|
roleId: "bad-roleid",
|
|
roleVersion: 1,
|
|
grants: []string{"ids=s_1;actions=*"},
|
|
},
|
|
want: nil,
|
|
wantAffectedRows: 0,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "nil-grants",
|
|
args: args{
|
|
roleId: role.PublicId,
|
|
roleVersion: 1,
|
|
grants: nil,
|
|
},
|
|
want: nil,
|
|
wantAffectedRows: 0,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "zero-version",
|
|
args: args{
|
|
roleId: role.PublicId,
|
|
roleVersion: 0,
|
|
grants: []string{"ids=s_1;actions=*"},
|
|
},
|
|
want: nil,
|
|
wantAffectedRows: 0,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "bad-version",
|
|
args: args{
|
|
roleId: role.PublicId,
|
|
roleVersion: 1000,
|
|
grants: []string{"ids=s_1;actions=*"},
|
|
},
|
|
want: nil,
|
|
wantAffectedRows: 0,
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
rg := allocRoleGrant()
|
|
db.TestDeleteWhere(t, conn, &rg, "1=1")
|
|
got, gotAffectedRows, err := repo.SetRoleGrants(context.Background(), tt.args.roleId, tt.args.roleVersion, tt.args.grants, tt.args.opt...)
|
|
if tt.wantErr {
|
|
require.Error(err)
|
|
} else {
|
|
require.NoError(err)
|
|
}
|
|
assert.Equal(tt.wantAffectedRows, gotAffectedRows)
|
|
assert.Equal(tt.want, got)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGrantsForUser(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, 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)
|
|
|
|
// 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("db-grants", func(t *testing.T) {
|
|
// Here we should see exactly what the DB has returned, before we do some
|
|
// local exploding of grants and grant scopes
|
|
expMultiGrantTuples := []multiGrantTuple{
|
|
// No grants from noOrg/noProj
|
|
// Direct org1/2:
|
|
{
|
|
RoleId: directGrantOrg1Role.PublicId,
|
|
RoleScopeId: directGrantOrg1.PublicId,
|
|
RoleParentScopeId: scope.Global.String(),
|
|
GrantScopeIds: globals.GrantScopeThis,
|
|
Grants: strings.Join([]string{directGrantOrg1RoleGrant1, directGrantOrg1RoleGrant2}, "^"),
|
|
},
|
|
{
|
|
RoleId: directGrantOrg2Role.PublicId,
|
|
RoleScopeId: directGrantOrg2.PublicId,
|
|
RoleParentScopeId: scope.Global.String(),
|
|
GrantScopeIds: strings.Join([]string{globals.GrantScopeThis, directGrantProj2a.PublicId}, "^"),
|
|
Grants: strings.Join([]string{directGrantOrg2RoleGrant1, directGrantOrg2RoleGrant2}, "^"),
|
|
},
|
|
// Proj orgs 1/2:
|
|
{
|
|
RoleId: directGrantProj1aRole.PublicId,
|
|
RoleScopeId: directGrantProj1a.PublicId,
|
|
RoleParentScopeId: directGrantOrg1.PublicId,
|
|
GrantScopeIds: globals.GrantScopeThis,
|
|
Grants: directGrantProj1aRoleGrant,
|
|
},
|
|
{
|
|
RoleId: directGrantProj1bRole.PublicId,
|
|
RoleScopeId: directGrantProj1b.PublicId,
|
|
RoleParentScopeId: directGrantOrg1.PublicId,
|
|
GrantScopeIds: globals.GrantScopeThis,
|
|
Grants: directGrantProj1bRoleGrant,
|
|
},
|
|
{
|
|
RoleId: directGrantProj2aRole.PublicId,
|
|
RoleScopeId: directGrantProj2a.PublicId,
|
|
RoleParentScopeId: directGrantOrg2.PublicId,
|
|
GrantScopeIds: globals.GrantScopeThis,
|
|
Grants: directGrantProj2aRoleGrant,
|
|
},
|
|
{
|
|
RoleId: directGrantProj2bRole.PublicId,
|
|
RoleScopeId: directGrantProj2b.PublicId,
|
|
RoleParentScopeId: directGrantOrg2.PublicId,
|
|
GrantScopeIds: globals.GrantScopeThis,
|
|
Grants: directGrantProj2bRoleGrant,
|
|
},
|
|
// Child grants from orgs 1/2:
|
|
{
|
|
RoleId: childGrantOrg1Role.PublicId,
|
|
RoleScopeId: childGrantOrg1.PublicId,
|
|
RoleParentScopeId: scope.Global.String(),
|
|
GrantScopeIds: globals.GrantScopeChildren,
|
|
Grants: childGrantOrg1RoleGrant,
|
|
},
|
|
{
|
|
RoleId: childGrantOrg2Role.PublicId,
|
|
RoleScopeId: childGrantOrg2.PublicId,
|
|
RoleParentScopeId: scope.Global.String(),
|
|
GrantScopeIds: globals.GrantScopeChildren,
|
|
Grants: strings.Join([]string{childGrantOrg2RoleGrant1, childGrantOrg2RoleGrant2}, "^"),
|
|
},
|
|
// Children of global and descendants of global
|
|
{
|
|
RoleId: descendantGrantGlobalRole.PublicId,
|
|
RoleScopeId: scope.Global.String(),
|
|
GrantScopeIds: globals.GrantScopeDescendants,
|
|
Grants: descendantGrantGlobalRoleGrant,
|
|
},
|
|
{
|
|
RoleId: childGrantGlobalRole.PublicId,
|
|
RoleScopeId: scope.Global.String(),
|
|
GrantScopeIds: globals.GrantScopeChildren,
|
|
Grants: childGrantGlobalRoleGrant,
|
|
},
|
|
}
|
|
for i, tuple := range expMultiGrantTuples {
|
|
tuple.testStableSort()
|
|
expMultiGrantTuples[i] = tuple
|
|
}
|
|
multiGrantTuplesCache := new([]multiGrantTuple)
|
|
_, err := repo.GrantsForUser(ctx, user.PublicId, withTestCacheMultiGrantTuples(multiGrantTuplesCache))
|
|
require.NoError(t, err)
|
|
|
|
// log.Println("multiGrantTuplesCache", pretty.Sprint(*multiGrantTuplesCache))
|
|
assert.ElementsMatch(t, *multiGrantTuplesCache, expMultiGrantTuples)
|
|
})
|
|
|
|
t.Run("exploded-grants", func(t *testing.T) {
|
|
// We expect to see:
|
|
//
|
|
// * No grants from noOrg/noProj
|
|
// * Grants from direct orgs/projs:
|
|
// * directGrantOrg1/directGrantOrg2 on org and respective projects (6 grants total per org)
|
|
// * directGrantProj on respective projects (4 grants total)
|
|
expGrantTuples := []perms.GrantTuple{
|
|
// No grants from noOrg/noProj
|
|
// Grants from direct org1 to org1/proj1a/proj1b:
|
|
{
|
|
RoleId: directGrantOrg1Role.PublicId,
|
|
RoleScopeId: directGrantOrg1.PublicId,
|
|
RoleParentScopeId: scope.Global.String(),
|
|
GrantScopeId: directGrantOrg1.PublicId,
|
|
Grant: directGrantOrg1RoleGrant1,
|
|
},
|
|
{
|
|
RoleId: directGrantOrg1Role.PublicId,
|
|
RoleScopeId: directGrantOrg1.PublicId,
|
|
RoleParentScopeId: scope.Global.String(),
|
|
GrantScopeId: directGrantOrg1.PublicId,
|
|
Grant: directGrantOrg1RoleGrant2,
|
|
},
|
|
// Grants from direct org 1 proj 1a:
|
|
{
|
|
RoleId: directGrantProj1aRole.PublicId,
|
|
RoleScopeId: directGrantProj1a.PublicId,
|
|
RoleParentScopeId: directGrantOrg1.PublicId,
|
|
GrantScopeId: directGrantProj1a.PublicId,
|
|
Grant: directGrantProj1aRoleGrant,
|
|
},
|
|
// Grant from direct org 1 proj 1 b:
|
|
{
|
|
RoleId: directGrantProj1bRole.PublicId,
|
|
RoleScopeId: directGrantProj1b.PublicId,
|
|
RoleParentScopeId: directGrantOrg1.PublicId,
|
|
GrantScopeId: directGrantProj1b.PublicId,
|
|
Grant: directGrantProj1bRoleGrant,
|
|
},
|
|
|
|
// Grants from direct org2 to org2/proj2a/proj2b:
|
|
{
|
|
RoleId: directGrantOrg2Role.PublicId,
|
|
RoleScopeId: directGrantOrg2.PublicId,
|
|
RoleParentScopeId: scope.Global.String(),
|
|
GrantScopeId: directGrantOrg2.PublicId,
|
|
Grant: directGrantOrg2RoleGrant1,
|
|
},
|
|
{
|
|
RoleId: directGrantOrg2Role.PublicId,
|
|
RoleScopeId: directGrantOrg2.PublicId,
|
|
RoleParentScopeId: scope.Global.String(),
|
|
GrantScopeId: directGrantProj2a.PublicId,
|
|
Grant: directGrantOrg2RoleGrant1,
|
|
},
|
|
{
|
|
RoleId: directGrantOrg2Role.PublicId,
|
|
RoleScopeId: directGrantOrg2.PublicId,
|
|
RoleParentScopeId: scope.Global.String(),
|
|
GrantScopeId: directGrantOrg2.PublicId,
|
|
Grant: directGrantOrg2RoleGrant2,
|
|
},
|
|
{
|
|
RoleId: directGrantOrg2Role.PublicId,
|
|
RoleScopeId: directGrantOrg2.PublicId,
|
|
RoleParentScopeId: scope.Global.String(),
|
|
GrantScopeId: directGrantProj2a.PublicId,
|
|
Grant: directGrantOrg2RoleGrant2,
|
|
},
|
|
// Grants from direct org 2 proj 2a:
|
|
{
|
|
RoleId: directGrantProj2aRole.PublicId,
|
|
RoleScopeId: directGrantProj2a.PublicId,
|
|
RoleParentScopeId: directGrantOrg2.PublicId,
|
|
GrantScopeId: directGrantProj2a.PublicId,
|
|
Grant: directGrantProj2aRoleGrant,
|
|
},
|
|
// Grant from direct org 2 proj 2 b:
|
|
{
|
|
RoleId: directGrantProj2bRole.PublicId,
|
|
RoleScopeId: directGrantProj2b.PublicId,
|
|
RoleParentScopeId: directGrantOrg2.PublicId,
|
|
GrantScopeId: directGrantProj2b.PublicId,
|
|
Grant: directGrantProj2bRoleGrant,
|
|
},
|
|
// Child grants from child org1 to proj1a/proj1b:
|
|
{
|
|
RoleId: childGrantOrg1Role.PublicId,
|
|
RoleScopeId: childGrantOrg1.PublicId,
|
|
RoleParentScopeId: scope.Global.String(),
|
|
GrantScopeId: globals.GrantScopeChildren,
|
|
Grant: childGrantOrg1RoleGrant,
|
|
},
|
|
// Child grants from child org2 to proj2a/proj2b:
|
|
{
|
|
RoleId: childGrantOrg2Role.PublicId,
|
|
RoleScopeId: childGrantOrg2.PublicId,
|
|
RoleParentScopeId: scope.Global.String(),
|
|
GrantScopeId: globals.GrantScopeChildren,
|
|
Grant: childGrantOrg2RoleGrant1,
|
|
},
|
|
{
|
|
RoleId: childGrantOrg2Role.PublicId,
|
|
RoleScopeId: childGrantOrg2.PublicId,
|
|
RoleParentScopeId: scope.Global.String(),
|
|
GrantScopeId: globals.GrantScopeChildren,
|
|
Grant: childGrantOrg2RoleGrant2,
|
|
},
|
|
|
|
// Grants from global to every org:
|
|
{
|
|
RoleId: childGrantGlobalRole.PublicId,
|
|
RoleScopeId: scope.Global.String(),
|
|
GrantScopeId: globals.GrantScopeChildren,
|
|
Grant: childGrantGlobalRoleGrant,
|
|
},
|
|
|
|
// Grants from global to every org and project:
|
|
{
|
|
RoleId: descendantGrantGlobalRole.PublicId,
|
|
RoleScopeId: scope.Global.String(),
|
|
GrantScopeId: globals.GrantScopeDescendants,
|
|
Grant: descendantGrantGlobalRoleGrant,
|
|
},
|
|
}
|
|
|
|
multiGrantTuplesCache := new([]multiGrantTuple)
|
|
grantTuples, err := repo.GrantsForUser(ctx, user.PublicId, withTestCacheMultiGrantTuples(multiGrantTuplesCache))
|
|
require.NoError(t, err)
|
|
assert.ElementsMatch(t, grantTuples, expGrantTuples)
|
|
})
|
|
|
|
t.Run("acl-grants", func(t *testing.T) {
|
|
grantTuples, err := repo.GrantsForUser(ctx, user.PublicId)
|
|
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...)
|
|
|
|
t.Run("descendant-grants", func(t *testing.T) {
|
|
descendantGrants := acl.DescendantsGrants()
|
|
expDescendantGrants := []perms.AclGrant{
|
|
{
|
|
RoleScopeId: scope.Global.String(),
|
|
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) {
|
|
childrenGrants := acl.ChildrenScopeGrantMap()
|
|
expChildrenGrants := map[string][]perms.AclGrant{
|
|
childGrantOrg1.PublicId: {
|
|
{
|
|
RoleScopeId: childGrantOrg1.PublicId,
|
|
RoleParentScopeId: scope.Global.String(),
|
|
GrantScopeId: globals.GrantScopeChildren,
|
|
Id: "*",
|
|
Type: resource.HostSet,
|
|
ActionSet: perms.ActionSet{action.AddHosts: true, action.RemoveHosts: true},
|
|
},
|
|
},
|
|
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},
|
|
},
|
|
},
|
|
scope.Global.String(): {
|
|
{
|
|
RoleScopeId: scope.Global.String(),
|
|
GrantScopeId: globals.GrantScopeChildren,
|
|
Id: "*",
|
|
Type: resource.Account,
|
|
ActionSet: perms.ActionSet{action.All: 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) {
|
|
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},
|
|
},
|
|
},
|
|
directGrantProj1a.PublicId: {
|
|
{
|
|
RoleScopeId: directGrantProj1a.PublicId,
|
|
RoleParentScopeId: directGrantOrg1.PublicId,
|
|
GrantScopeId: directGrantProj1a.PublicId,
|
|
Id: "*",
|
|
Type: resource.Target,
|
|
ActionSet: perms.ActionSet{action.AuthorizeSession: true, action.Read: true},
|
|
},
|
|
},
|
|
directGrantProj1b.PublicId: {
|
|
{
|
|
RoleScopeId: directGrantProj1b.PublicId,
|
|
RoleParentScopeId: directGrantOrg1.PublicId,
|
|
GrantScopeId: directGrantProj1b.PublicId,
|
|
Id: "*",
|
|
Type: resource.Session,
|
|
ActionSet: perms.ActionSet{action.List: true, action.Read: true},
|
|
},
|
|
},
|
|
directGrantOrg2.PublicId: {
|
|
{
|
|
RoleScopeId: directGrantOrg2.PublicId,
|
|
RoleParentScopeId: scope.Global.String(),
|
|
GrantScopeId: directGrantOrg2.PublicId,
|
|
Id: "*",
|
|
Type: resource.User,
|
|
ActionSet: perms.ActionSet{action.All: true},
|
|
},
|
|
{
|
|
RoleScopeId: directGrantOrg2.PublicId,
|
|
RoleParentScopeId: scope.Global.String(),
|
|
GrantScopeId: directGrantOrg2.PublicId,
|
|
Id: "*",
|
|
Type: resource.Group,
|
|
ActionSet: perms.ActionSet{action.List: true, action.Read: true},
|
|
},
|
|
},
|
|
directGrantProj2a.PublicId: {
|
|
{
|
|
RoleScopeId: directGrantOrg2.PublicId,
|
|
RoleParentScopeId: scope.Global.String(),
|
|
GrantScopeId: directGrantProj2a.PublicId,
|
|
Id: "*",
|
|
Type: resource.User,
|
|
ActionSet: perms.ActionSet{action.All: true},
|
|
},
|
|
{
|
|
RoleScopeId: directGrantOrg2.PublicId,
|
|
RoleParentScopeId: scope.Global.String(),
|
|
GrantScopeId: directGrantProj2a.PublicId,
|
|
Id: "*",
|
|
Type: resource.Group,
|
|
ActionSet: perms.ActionSet{action.List: true, action.Read: true},
|
|
},
|
|
{
|
|
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},
|
|
},
|
|
},
|
|
}
|
|
/*
|
|
log.Println("org1", directGrantOrg1.PublicId)
|
|
log.Println("proj1a", directGrantProj1a.PublicId)
|
|
log.Println("proj1b", directGrantProj1b.PublicId)
|
|
log.Println("org2", directGrantOrg2.PublicId)
|
|
log.Println("proj2a", directGrantProj2a.PublicId)
|
|
log.Println("proj2b", directGrantProj2b.PublicId)
|
|
*/
|
|
assert.Len(t, directGrants, len(expDirectGrants))
|
|
for k, v := range directGrants {
|
|
assert.ElementsMatch(t, v, expDirectGrants[k])
|
|
}
|
|
})
|
|
})
|
|
t.Run("real-world", func(t *testing.T) {
|
|
// These tests cases crib from the initial setup of the grants, and
|
|
// include a number of cases to ensure the ones that should work do and
|
|
// various that should not do not
|
|
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: "u_abcd1234",
|
|
Type: resource.User,
|
|
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: "u_abcd1234",
|
|
Type: resource.User,
|
|
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: "g_abcd1234",
|
|
Type: resource.Group,
|
|
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: "u_abcd1234",
|
|
Type: resource.User,
|
|
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: "s_abcd1234",
|
|
Type: resource.Session,
|
|
ParentScopeId: scope.Global.String(),
|
|
},
|
|
act: action.CancelSelf,
|
|
}, 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: "hsst_abcd1234",
|
|
Type: resource.HostSet,
|
|
ParentScopeId: scope.Global.String(),
|
|
},
|
|
act: action.AddHosts,
|
|
}, 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,
|
|
},
|
|
)
|
|
}
|
|
// These test cases are global descendants grants
|
|
{
|
|
testCases = append(testCases, testCase{
|
|
name: "descendants-a",
|
|
res: perms.Resource{
|
|
ScopeId: scope.Global.String(),
|
|
Id: "cs_abcd1234",
|
|
Type: resource.Credential,
|
|
},
|
|
act: action.Update,
|
|
}, testCase{
|
|
name: "descendants-b",
|
|
res: perms.Resource{
|
|
ScopeId: noGrantProj1.PublicId,
|
|
Id: "cs_abcd1234",
|
|
Type: resource.Credential,
|
|
ParentScopeId: noGrantOrg1.PublicId,
|
|
},
|
|
act: action.Update,
|
|
shouldWork: true,
|
|
}, testCase{
|
|
name: "descendants-c",
|
|
res: perms.Resource{
|
|
ScopeId: directGrantOrg2.PublicId,
|
|
Id: "cs_abcd1234",
|
|
Type: resource.Credential,
|
|
ParentScopeId: scope.Global.String(),
|
|
},
|
|
act: action.Update,
|
|
shouldWork: true,
|
|
}, testCase{
|
|
name: "descendants-d",
|
|
res: perms.Resource{
|
|
ScopeId: directGrantProj1a.PublicId,
|
|
Id: "cs_abcd1234",
|
|
Type: resource.Credential,
|
|
ParentScopeId: directGrantOrg1.PublicId,
|
|
},
|
|
act: action.Update,
|
|
shouldWork: true,
|
|
}, testCase{
|
|
name: "descendants-e",
|
|
res: perms.Resource{
|
|
ScopeId: directGrantProj1a.PublicId,
|
|
Id: "cs_abcd1234",
|
|
Type: resource.Credential,
|
|
ParentScopeId: directGrantOrg1.PublicId,
|
|
},
|
|
act: action.Update,
|
|
shouldWork: true,
|
|
}, testCase{
|
|
name: "descendants-f",
|
|
res: perms.Resource{
|
|
ScopeId: directGrantProj2b.PublicId,
|
|
Id: "cs_abcd1234",
|
|
Type: resource.Credential,
|
|
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)
|
|
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)
|
|
})
|
|
}
|
|
})
|
|
}
|