Bug: fix groups in children scopes being filtered out by grants (#5418)
* add utility functions for grants tests * use passed in scopeID to create user * add test for groups list * groups: set ParentScopeId before FetchActionSetForId * add comment to TestRoleGrantsForToken * lint and ran make gen * fix import groups * add an additional test case * remove print * changelog * fix(alias): set parent scope id for alias resource (#5434) set the `ParentScopeId` before fetching authorized actions for alias * fix(worker): set parent scope id for worker resource (#5435) set the `ParentScopeId` before fetching authorized actions for worker * fix(user): children scopes being filtered out by grants for user (#5436) * fix(user): children scopes being filtered out by grants for user Resources are being filtered out due to missing ParentScopeId when constructing Resource to pass into authResults.FetchActionSetForId. * fix(scope): set parent scope id for worker resource (#5439) set the `ParentScopeId` before fetching authorized actions for worker * fix(target): set parent scope id for target resource (#5447) set the `ParentScopeId` before fetching authorized actions for target * fix(roles): set parent scope id for roles resource (#5452) * fix(roles): set parent scope id for roles resource set the `ParentScopeId` before fetching authorized actions for role resource * test(managed-group): add grants test coverage (#5453) * fix(managed-group): set parent scope id for managed-group resource set the ParentScopeId before fetching authorized actions for managed resource * fix(host): set parent scope id for host resource (#5455) set the `ParentScopeId` before fetching authorized actions for host resource * fix(host-set): set parent scope id for host-set resource (#5456) set the ParentScopeId before fetching authorized actions for host-set resource * fix(host-catalog): set parent scope id for host-catalog resource (#5457) set the ParentScopeId before fetching authorized actions for host-catalog resource * fix(credential-store): set parent scope id for credential-store resource (#5458) set the ParentScopeId before fetching authorized actions for credential-store resource * fix(authmethods): set parent scope ID for auth methods resource (#5448) * handlers/authmethods: fix children permission * documentation * formatting * fix(credential): set parent scope id for credential resource (#5459) set the `ParentScopeId` before fetching authorized actions for credential resource * fix(accounts): bug grants filter children accounts (#5431) * handlers/accounts: fix children grants filtering out results unexpectedly * make gen * fix(authtokens): set parent scope ID for auth token resource (#5451) * fix authtokens not passing children scope ID * make gen * fix(credential-libraries): set parent scope ID (#5463) * fix(common) set parent ID before fetching action setsparent ID before fetching action sets (#5467) * fix(common) set parent ID before fetching action sets * make gen * additional test * rename test * more tests * remove duplicate test * make gen * Update CHANGELOG.md Co-authored-by: Johan Brandhorst-Satzkorn <johan.brandhorst@gmail.com> --------- Co-authored-by: Elim Tsiagbey <elim.tsiagbey@hashicorp.com> Co-authored-by: Johan Brandhorst-Satzkorn <johan.brandhorst@gmail.com>
This commit is contained in:
39 files changed
+2676
-30
No files matched your search
@@ -46,6 +46,9 @@ maintainability of worker queries, and improve DB performance. ([PR](https://git
|
||||
([PR](https://github.com/hashicorp/boundary/pull/5221)).
|
||||
* Fix an issue where, when starting a session, the connection limit always displays 0.
|
||||
([PR](https://github.com/hashicorp/boundary/pull/5396)).
|
||||
* Fix bug which caused the `children` keyword not to apply the appropriate
|
||||
permissions for a number of resources.
|
||||
([PR](https://github.com/hashicorp/boundary/pull/5418)).
|
||||
|
||||
## 0.18.2 (2024/12/12)
|
||||
### Bug fixes
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/go-uuid"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -46,3 +47,38 @@ func TestAuthToken(t testing.TB, conn *db.DB, kms *kms.Kms, scopeId string, opt
|
||||
require.NoError(t, err)
|
||||
return at
|
||||
}
|
||||
|
||||
// TestRoleGrantsForToken contains information used by TestAuthTokenWithRoles to create
|
||||
// roles and their associated grants (with grant scopes)
|
||||
type TestRoleGrantsForToken struct {
|
||||
RoleScopeID string
|
||||
GrantStrings []string
|
||||
GrantScopes []string
|
||||
}
|
||||
|
||||
// TestAuthTokenWithRoles creates auth token associated with roles as requested by the caller along
|
||||
// with any required resources to achieve said token
|
||||
func TestAuthTokenWithRoles(t testing.TB, conn *db.DB, kms *kms.Kms, scopeId string, roles []TestRoleGrantsForToken) *AuthToken {
|
||||
t.Helper()
|
||||
ctx := context.Background()
|
||||
rw := db.New(conn)
|
||||
atRepo, err := NewRepository(ctx, rw, rw, kms)
|
||||
require.NoError(t, err)
|
||||
|
||||
iamRepo, err := iam.NewRepository(ctx, rw, rw, kms)
|
||||
require.NoError(t, err)
|
||||
|
||||
authMethod := password.TestAuthMethods(t, conn, scopeId, 1)[0]
|
||||
|
||||
loginName, err := uuid.GenerateUUID()
|
||||
require.NoError(t, err)
|
||||
acct := password.TestAccount(t, conn, authMethod.GetPublicId(), loginName)
|
||||
user := iam.TestUser(t, iamRepo, scopeId, iam.WithAccountIds(acct.GetPublicId()))
|
||||
for _, r := range roles {
|
||||
role := iam.TestRoleWithGrants(t, conn, r.RoleScopeID, r.GrantScopes, r.GrantStrings)
|
||||
_ = iam.TestUserRole(t, conn, role.PublicId, user.PublicId)
|
||||
}
|
||||
fullGrantToken, err := atRepo.CreateAuthToken(ctx, user, acct.GetPublicId())
|
||||
require.NoError(t, err)
|
||||
return fullGrantToken
|
||||
}
|
||||
@@ -5,11 +5,19 @@ package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/authtoken"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/common"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
authpb "github.com/hashicorp/boundary/internal/gen/controller/auth"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/requests"
|
||||
"github.com/hashicorp/boundary/internal/server"
|
||||
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// DisabledAuthTestContext is meant for testing, and uses a context that has
|
||||
@@ -30,3 +38,30 @@ func DisabledAuthTestContext(iamRepoFn common.IamRepoFactory, scopeId string, op
|
||||
requestContext := context.WithValue(context.Background(), requests.ContextRequestInformationKey, &requests.RequestContext{})
|
||||
return NewVerifierContext(requestContext, iamRepoFn, nil, nil, opts.withKms, &reqInfo)
|
||||
}
|
||||
|
||||
// TestAuthContextFromToken creates an auth context with provided token
|
||||
// This is used in conjunction with TestAuthTokenWithRoles which creates a test token
|
||||
func TestAuthContextFromToken(t *testing.T, conn *db.DB, wrap wrapping.Wrapper, token *authtoken.AuthToken, iamRepo *iam.Repository) context.Context {
|
||||
t.Helper()
|
||||
ctx := context.Background()
|
||||
rw := db.New(conn)
|
||||
kmsCache := kms.TestKms(t, conn, wrap)
|
||||
atRepo, err := authtoken.NewRepository(ctx, rw, rw, kmsCache)
|
||||
require.NoError(t, err)
|
||||
serversRepoFn := func() (*server.Repository, error) {
|
||||
return server.NewRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
iamRepoFn := func() (*iam.Repository, error) {
|
||||
return iamRepo, nil
|
||||
}
|
||||
atRepoFn := func() (*authtoken.Repository, error) {
|
||||
return atRepo, nil
|
||||
}
|
||||
fullGrantAuthCtx := NewVerifierContext(requests.NewRequestContext(ctx, requests.WithUserId(token.GetIamUserId())),
|
||||
iamRepoFn, atRepoFn, serversRepoFn, kmsCache, &authpb.RequestInfo{
|
||||
PublicId: token.PublicId,
|
||||
Token: token.GetToken(),
|
||||
TokenFormat: uint32(AuthTokenTypeBearer),
|
||||
})
|
||||
return fullGrantAuthCtx
|
||||
}
|
||||
@@ -150,6 +150,7 @@ func GetListingResourceInformation(
|
||||
for _, scp := range scps {
|
||||
scpId := scp.GetPublicId()
|
||||
res.ScopeId = scpId
|
||||
res.ParentScopeId = scp.GetParentId()
|
||||
aSet := input.AuthResults.FetchActionSetForType(ctx,
|
||||
// This is overridden by WithResource
|
||||
resource.Unknown,
|
||||
|
||||
@@ -1488,9 +1488,10 @@ func validateSetPasswordRequest(ctx context.Context, req *pbs.SetPasswordRequest
|
||||
|
||||
func newOutputOpts(ctx context.Context, item auth.Account, authMethodId string, authResults requestauth.VerifyResults) ([]handlers.Option, bool) {
|
||||
res := perms.Resource{
|
||||
ScopeId: authResults.Scope.Id,
|
||||
Type: resource.Account,
|
||||
Pin: authMethodId,
|
||||
ScopeId: authResults.Scope.Id,
|
||||
ParentScopeId: authResults.Scope.ParentScopeId,
|
||||
Type: resource.Account,
|
||||
Pin: authMethodId,
|
||||
}
|
||||
res.Id = item.GetPublicId()
|
||||
authorizedActions := authResults.FetchActionSetForId(ctx, item.GetPublicId(), IdActions[globals.ResourceInfoFromPrefix(item.GetPublicId()).Subtype], requestauth.WithResource(&res)).Strings()
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package accounts_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/auth/ldap"
|
||||
"github.com/hashicorp/boundary/internal/auth/oidc"
|
||||
"github.com/hashicorp/boundary/internal/auth/password"
|
||||
"github.com/hashicorp/boundary/internal/authtoken"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/accounts"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestListPassword_Grants(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
rw := db.New(conn)
|
||||
wrap := db.TestWrapper(t)
|
||||
kms := kms.TestKms(t, conn, wrap)
|
||||
iamRepo, err := iam.NewRepository(ctx, rw, rw, kms)
|
||||
require.NoError(t, err)
|
||||
pwRepoFn := func() (*password.Repository, error) {
|
||||
return password.NewRepository(ctx, rw, rw, kms)
|
||||
}
|
||||
oidcRepoFn := func() (*oidc.Repository, error) {
|
||||
return oidc.NewRepository(ctx, rw, rw, kms)
|
||||
}
|
||||
|
||||
ldapRepoFn := func() (*ldap.Repository, error) {
|
||||
return ldap.NewRepository(ctx, rw, rw, kms)
|
||||
}
|
||||
|
||||
org, proj := iam.TestScopes(t, iam.TestRepo(t, conn, wrap))
|
||||
orgAM := password.TestAuthMethod(t, conn, org.GetPublicId())
|
||||
projAM := password.TestAuthMethod(t, conn, proj.GetPublicId())
|
||||
orgPWAccounts := password.TestMultipleAccounts(t, conn, orgAM.GetPublicId(), 3)
|
||||
projPWAccounts := password.TestMultipleAccounts(t, conn, projAM.GetPublicId(), 3)
|
||||
|
||||
testcases := []struct {
|
||||
name string
|
||||
roleRequest []authtoken.TestRoleGrantsForToken
|
||||
input *pbs.ListAccountsRequest
|
||||
wantAccountIDs []string
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "children grants global scope list org accounts return org accounts",
|
||||
input: &pbs.ListAccountsRequest{
|
||||
AuthMethodId: orgAM.PublicId,
|
||||
PageSize: 100,
|
||||
},
|
||||
roleRequest: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=*;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
wantAccountIDs: []string{orgPWAccounts[0].PublicId, orgPWAccounts[1].PublicId, orgPWAccounts[2].PublicId},
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
name: "children grants org scope list project accounts return project accounts",
|
||||
input: &pbs.ListAccountsRequest{
|
||||
AuthMethodId: projAM.PublicId,
|
||||
PageSize: 100,
|
||||
},
|
||||
roleRequest: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: org.GetPublicId(),
|
||||
GrantStrings: []string{"ids=*;type=*;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
wantAccountIDs: []string{projPWAccounts[0].PublicId, projPWAccounts[1].PublicId, projPWAccounts[2].PublicId},
|
||||
wantErr: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
s, err := accounts.NewService(ctx, pwRepoFn, oidcRepoFn, ldapRepoFn, 1000)
|
||||
require.NoError(t, err, "Couldn't create new user service.")
|
||||
tok := authtoken.TestAuthTokenWithRoles(t, conn, kms, globals.GlobalPrefix, tc.roleRequest)
|
||||
fullGrantAuthCtx := auth.TestAuthContextFromToken(t, conn, wrap, tok, iamRepo)
|
||||
got, gErr := s.ListAccounts(fullGrantAuthCtx, tc.input)
|
||||
if tc.wantErr != nil {
|
||||
require.Error(t, err)
|
||||
require.ErrorIs(t, err, tc.wantErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, gErr)
|
||||
require.Len(t, got.Items, len(orgPWAccounts))
|
||||
var gotIDs []string
|
||||
for _, item := range got.Items {
|
||||
gotIDs = append(gotIDs, item.Id)
|
||||
}
|
||||
require.ElementsMatch(t, tc.wantAccountIDs, gotIDs)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -648,6 +648,7 @@ func newOutputOpts(ctx context.Context, item *target.Alias, scopeInfoMap map[str
|
||||
}
|
||||
res.Id = item.GetPublicId()
|
||||
res.ScopeId = item.GetScopeId()
|
||||
res.ParentScopeId = scopeInfoMap[item.GetScopeId()].GetParentScopeId()
|
||||
authorizedActions := authResults.FetchActionSetForId(ctx, item.GetPublicId(), IdActions, auth.WithResource(&res))
|
||||
if len(authorizedActions) == 0 {
|
||||
return nil, false
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package aliases_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/alias/target"
|
||||
"github.com/hashicorp/boundary/internal/authtoken"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/aliases"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc/codes"
|
||||
)
|
||||
|
||||
// TestGrants_ReadActions tests read actions to assert that grants are being applied properly
|
||||
//
|
||||
// Role - which scope the role is created in
|
||||
// - global level
|
||||
// Scopes [resource]:
|
||||
// - globalAlias1 [globalAlias]
|
||||
// - globalAlias2 [globalAlias]
|
||||
func TestGrants_ReadActions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
rw := db.New(conn)
|
||||
wrap := db.TestWrapper(t)
|
||||
kmsCache := kms.TestKms(t, conn, wrap)
|
||||
iamRepo := iam.TestRepo(t, conn, wrap)
|
||||
iamRepoFn := func() (*iam.Repository, error) {
|
||||
return iamRepo, nil
|
||||
}
|
||||
repoFn := func() (*target.Repository, error) {
|
||||
return target.NewRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
s, err := aliases.NewService(ctx, repoFn, iamRepoFn, 1000)
|
||||
require.NoError(t, err)
|
||||
globalAlias1 := target.TestAlias(t, rw, "test.alias.one", target.WithDescription("alias_1"), target.WithName("alias_one"))
|
||||
globalAlias2 := target.TestAlias(t, rw, "test.alias.two", target.WithDescription("alias_2"), target.WithName("alias_two"))
|
||||
t.Run("List", func(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input *pbs.ListAliasesRequest
|
||||
rolesToCreate []authtoken.TestRoleGrantsForToken
|
||||
wantErr error
|
||||
wantIDs []string
|
||||
}{
|
||||
{
|
||||
name: "global role grant this returns all created aliases",
|
||||
input: &pbs.ListAliasesRequest{
|
||||
ScopeId: globals.GlobalPrefix,
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=alias;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: []string{globalAlias1.PublicId, globalAlias2.PublicId},
|
||||
},
|
||||
{
|
||||
name: "global role grant this with a non-applicable type throws an error",
|
||||
input: &pbs.ListAliasesRequest{
|
||||
ScopeId: globals.GlobalPrefix,
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=group;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis},
|
||||
},
|
||||
},
|
||||
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tok := authtoken.TestAuthTokenWithRoles(t, conn, kmsCache, globals.GlobalPrefix, tc.rolesToCreate)
|
||||
fullGrantAuthCtx := auth.TestAuthContextFromToken(t, conn, wrap, tok, iamRepo)
|
||||
got, finalErr := s.ListAliases(fullGrantAuthCtx, tc.input)
|
||||
if tc.wantErr != nil {
|
||||
require.ErrorIs(t, finalErr, tc.wantErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, finalErr)
|
||||
var gotIDs []string
|
||||
for _, g := range got.Items {
|
||||
gotIDs = append(gotIDs, g.GetId())
|
||||
}
|
||||
require.ElementsMatch(t, tc.wantIDs, gotIDs)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1577,6 +1577,7 @@ func newOutputOpts(ctx context.Context, item auth.AuthMethod, scopeInfoMap map[s
|
||||
}
|
||||
res.Id = item.GetPublicId()
|
||||
res.ScopeId = item.GetScopeId()
|
||||
res.ParentScopeId = scopeInfoMap[item.GetScopeId()].GetParentScopeId()
|
||||
authorizedActions := authResults.FetchActionSetForId(ctx, item.GetPublicId(), IdActions[globals.ResourceInfoFromPrefix(item.GetPublicId()).Subtype], requestauth.WithResource(&res)).Strings()
|
||||
if len(authorizedActions) == 0 {
|
||||
return nil, false, nil
|
||||
|
||||
@@ -0,0 +1,266 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package authmethods_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"slices"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/auth"
|
||||
"github.com/hashicorp/boundary/internal/auth/ldap"
|
||||
"github.com/hashicorp/boundary/internal/auth/oidc"
|
||||
"github.com/hashicorp/boundary/internal/auth/password"
|
||||
"github.com/hashicorp/boundary/internal/authtoken"
|
||||
controllerauth "github.com/hashicorp/boundary/internal/daemon/controller/auth"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/authmethods"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestGrants_ReadActions tests read actions to assert that grants are being applied properly
|
||||
func TestGrants_ReadActions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrap := db.TestWrapper(t)
|
||||
iamRepo := iam.TestRepo(t, conn, wrap)
|
||||
rw := db.New(conn)
|
||||
kmsCache := kms.TestKms(t, conn, wrap)
|
||||
iamRepoFn := func() (*iam.Repository, error) {
|
||||
return iamRepo, nil
|
||||
}
|
||||
oidcRepoFn := func() (*oidc.Repository, error) {
|
||||
return oidc.NewRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
ldapRepoFn := func() (*ldap.Repository, error) {
|
||||
return ldap.NewRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
pwRepoFn := func() (*password.Repository, error) {
|
||||
return password.NewRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
atRepoFn := func() (*authtoken.Repository, error) {
|
||||
return authtoken.NewRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
authMethodRepoFn := func() (*auth.AuthMethodRepository, error) {
|
||||
return auth.NewAuthMethodRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
|
||||
s, err := authmethods.NewService(ctx,
|
||||
kmsCache,
|
||||
pwRepoFn,
|
||||
oidcRepoFn,
|
||||
iamRepoFn,
|
||||
atRepoFn,
|
||||
ldapRepoFn,
|
||||
authMethodRepoFn,
|
||||
1000)
|
||||
require.NoError(t, err)
|
||||
org1, _ := iam.TestScopes(t, iamRepo)
|
||||
org2, _ := iam.TestScopes(t, iamRepo)
|
||||
databaseWrapper, err := kmsCache.GetWrapper(context.Background(), globals.GlobalPrefix, kms.KeyPurposeDatabase)
|
||||
require.NoError(t, err)
|
||||
oidcGlobal := oidc.TestAuthMethod(t, conn, databaseWrapper, globals.GlobalPrefix, oidc.InactiveState, "client-id", "secret")
|
||||
oidcOrg1 := oidc.TestAuthMethod(t, conn, databaseWrapper, org1.GetPublicId(), oidc.InactiveState, "client-id", "secret")
|
||||
oidcOrg2 := oidc.TestAuthMethod(t, conn, databaseWrapper, org2.GetPublicId(), oidc.InactiveState, "client-id", "secret")
|
||||
|
||||
ldapGlobal := ldap.TestAuthMethod(t, conn, wrap, globals.GlobalPrefix, []string{"ldaps://alice.com"})
|
||||
ldapOrg1 := ldap.TestAuthMethod(t, conn, wrap, org1.GetPublicId(), []string{"ldaps://alice.com"})
|
||||
ldapOrg2 := ldap.TestAuthMethod(t, conn, wrap, org2.GetPublicId(), []string{"ldaps://alice.com"})
|
||||
|
||||
pwGlobal := password.TestAuthMethod(t, conn, globals.GlobalPrefix)
|
||||
pwOrg1 := password.TestAuthMethod(t, conn, org1.GetPublicId())
|
||||
pwOrg2 := password.TestAuthMethod(t, conn, org2.GetPublicId())
|
||||
|
||||
// ignoreList consists of auth method IDs to omit from the result set
|
||||
// this is to handle auth methods that are created during the auth token
|
||||
// creation
|
||||
ignoreList := []string{}
|
||||
|
||||
t.Run("List", func(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input *pbs.ListAuthMethodsRequest
|
||||
includeGlobalAuthMethods bool
|
||||
rolesToCreate []authtoken.TestRoleGrantsForToken
|
||||
wantErr error
|
||||
wantIDs []string
|
||||
}{
|
||||
{
|
||||
name: "global role grant this and children returns all auth methods",
|
||||
input: &pbs.ListAuthMethodsRequest{
|
||||
ScopeId: globals.GlobalPrefix,
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=auth-method;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: []string{
|
||||
oidcGlobal.PublicId,
|
||||
oidcOrg1.PublicId,
|
||||
oidcOrg2.PublicId,
|
||||
ldapGlobal.PublicId,
|
||||
ldapOrg1.PublicId,
|
||||
ldapOrg2.PublicId,
|
||||
pwGlobal.PublicId,
|
||||
pwOrg1.PublicId,
|
||||
pwOrg2.PublicId,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no grants return children org",
|
||||
input: &pbs.ListAuthMethodsRequest{
|
||||
ScopeId: globals.GlobalPrefix,
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{},
|
||||
wantErr: nil,
|
||||
// auth methods in `global` are filtered out because the user does not have grants to read
|
||||
// them in the global scope. Auth methods in org 1 and org 2 show up - my guess is because
|
||||
// the u_anon grants allow auth methods to be read on any org.
|
||||
wantIDs: []string{
|
||||
// oidcGlobal.PublicId,
|
||||
oidcOrg1.PublicId,
|
||||
oidcOrg2.PublicId,
|
||||
// ldapGlobal.PublicId,
|
||||
ldapOrg1.PublicId,
|
||||
ldapOrg2.PublicId,
|
||||
// pwGlobal.PublicId,
|
||||
pwOrg1.PublicId,
|
||||
pwOrg2.PublicId,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "org role grant this and children returns auth methods in org1",
|
||||
input: &pbs.ListAuthMethodsRequest{
|
||||
ScopeId: org1.PublicId,
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: org1.PublicId,
|
||||
GrantStrings: []string{"ids=*;type=auth-method;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: []string{oidcOrg1.PublicId, ldapOrg1.PublicId, pwOrg1.PublicId},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tok := authtoken.TestAuthTokenWithRoles(t, conn, kmsCache, globals.GlobalPrefix, tc.rolesToCreate)
|
||||
// auth method created during token generation will not be taken into considerations during this test
|
||||
// adding to the ignoreList so it can be ignored later
|
||||
ignoreList = append(ignoreList, tok.GetAuthMethodId())
|
||||
fullGrantAuthCtx := controllerauth.TestAuthContextFromToken(t, conn, wrap, tok, iamRepo)
|
||||
got, finalErr := s.ListAuthMethods(fullGrantAuthCtx, tc.input)
|
||||
if tc.wantErr != nil {
|
||||
require.ErrorIs(t, finalErr, tc.wantErr)
|
||||
return
|
||||
}
|
||||
// authtoken.TestAuthTokenWithRoles creates an auth method at `global` scope so
|
||||
// include AuthMethodID of the user used to generate AuthToken in the "wantIDs" set
|
||||
// when listing auth methods at global scope
|
||||
require.NoError(t, finalErr)
|
||||
var gotIDs []string
|
||||
for _, g := range got.Items {
|
||||
// do not include IDs in the ignore list in the
|
||||
// result sets
|
||||
if slices.Contains(ignoreList, g.Id) {
|
||||
continue
|
||||
}
|
||||
gotIDs = append(gotIDs, g.GetId())
|
||||
}
|
||||
require.ElementsMatch(t, tc.wantIDs, gotIDs)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Get", func(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input *pbs.ListAuthMethodsRequest
|
||||
amIDExpectErrMap map[string]error
|
||||
rolesToCreate []authtoken.TestRoleGrantsForToken
|
||||
}{
|
||||
{
|
||||
name: "global role grant this and children returns all auth methods",
|
||||
amIDExpectErrMap: map[string]error{
|
||||
pwGlobal.GetPublicId(): nil,
|
||||
pwOrg1.GetPublicId(): nil,
|
||||
pwOrg2.GetPublicId(): nil,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=auth-method;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "org role grant this and children returns auth methods in org1",
|
||||
input: &pbs.ListAuthMethodsRequest{
|
||||
ScopeId: org1.PublicId,
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=auth-method;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
amIDExpectErrMap: map[string]error{
|
||||
pwGlobal.GetPublicId(): handlers.ForbiddenError(),
|
||||
pwOrg1.GetPublicId(): nil,
|
||||
pwOrg2.GetPublicId(): nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no grants return all auth methods",
|
||||
input: &pbs.ListAuthMethodsRequest{
|
||||
ScopeId: globals.GlobalPrefix,
|
||||
Recursive: true,
|
||||
PageSize: 500,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{},
|
||||
amIDExpectErrMap: map[string]error{
|
||||
pwGlobal.GetPublicId(): handlers.ForbiddenError(),
|
||||
pwOrg1.GetPublicId(): handlers.ForbiddenError(),
|
||||
pwOrg2.GetPublicId(): handlers.ForbiddenError(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tok := authtoken.TestAuthTokenWithRoles(t, conn, kmsCache, globals.GlobalPrefix, tc.rolesToCreate)
|
||||
fullGrantAuthCtx := controllerauth.TestAuthContextFromToken(t, conn, wrap, tok, iamRepo)
|
||||
for amId, wantErr := range tc.amIDExpectErrMap {
|
||||
_, err := s.GetAuthMethod(fullGrantAuthCtx, &pbs.GetAuthMethodRequest{
|
||||
Id: amId,
|
||||
})
|
||||
if wantErr != nil {
|
||||
require.ErrorIs(t, err, wantErr)
|
||||
continue
|
||||
}
|
||||
require.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -457,6 +457,8 @@ func newOutputOpts(ctx context.Context, item *authtoken.AuthToken, scopeInfoMap
|
||||
}
|
||||
res.Id = item.GetPublicId()
|
||||
res.ScopeId = item.GetScopeId()
|
||||
res.ParentScopeId = scopeInfoMap[item.GetScopeId()].GetParentScopeId()
|
||||
|
||||
authorizedActions := authResults.FetchActionSetForId(ctx, item.GetPublicId(), IdActions, auth.WithResource(&res))
|
||||
if len(authorizedActions) == 0 {
|
||||
return nil, false
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package authtokens_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/authtoken"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
|
||||
at "github.com/hashicorp/boundary/internal/daemon/controller/handlers/authtokens"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestGrants_ReadActions tests read actions to assert that grants are being applied properly
|
||||
//
|
||||
// Role - which scope the role is created in
|
||||
// - global level
|
||||
// - org level
|
||||
// - project level
|
||||
// Grant - what IAM grant scope is set for the permission
|
||||
// - global: descendant
|
||||
// - org: children
|
||||
// - project
|
||||
// Scopes [resource]:
|
||||
// - global [globalGroup]
|
||||
// - org1 [org1Group]
|
||||
// - proj1 [proj1Group]
|
||||
// - org2 [org2Group]
|
||||
// - proj2 [proj2Group]
|
||||
// - proj3 [proj3Group]
|
||||
func TestGrants_ReadActions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
rw := db.New(conn)
|
||||
wrap := db.TestWrapper(t)
|
||||
iamRepo := iam.TestRepo(t, conn, wrap)
|
||||
|
||||
iamRepoFn := func() (*iam.Repository, error) {
|
||||
return iamRepo, nil
|
||||
}
|
||||
kmsCache := kms.TestKms(t, conn, wrap)
|
||||
|
||||
atRepo, err := authtoken.NewRepository(ctx, rw, rw, kmsCache)
|
||||
require.NoError(t, err)
|
||||
atRepoFn := func() (*authtoken.Repository, error) { return atRepo, nil }
|
||||
|
||||
s, err := at.NewService(ctx, atRepoFn, iamRepoFn, 1000)
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
org1, _ := iam.TestScopes(t, iamRepo)
|
||||
org2, _ := iam.TestScopes(t, iamRepo)
|
||||
|
||||
globalAT := authtoken.TestAuthToken(t, conn, kmsCache, globals.GlobalPrefix)
|
||||
org1AT := authtoken.TestAuthToken(t, conn, kmsCache, org1.GetPublicId())
|
||||
org2AT := authtoken.TestAuthToken(t, conn, kmsCache, org2.GetPublicId())
|
||||
|
||||
t.Run("List", func(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input *pbs.ListAuthTokensRequest
|
||||
rolesToCreate []authtoken.TestRoleGrantsForToken
|
||||
wantErr error
|
||||
wantIDs []string
|
||||
}{
|
||||
{
|
||||
name: "global role grant this and children returns global and org groups",
|
||||
input: &pbs.ListAuthTokensRequest{
|
||||
ScopeId: globals.GlobalPrefix,
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=auth-token;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: []string{globalAT.PublicId, org1AT.PublicId, org2AT.PublicId},
|
||||
},
|
||||
{
|
||||
name: "org role grant this and children returns org groups",
|
||||
input: &pbs.ListAuthTokensRequest{
|
||||
ScopeId: org1.PublicId,
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: org1.PublicId,
|
||||
GrantStrings: []string{"ids=*;type=auth-token;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: []string{org1AT.PublicId},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tok := authtoken.TestAuthTokenWithRoles(t, conn, kmsCache, globals.GlobalPrefix, tc.rolesToCreate)
|
||||
fullGrantAuthCtx := auth.TestAuthContextFromToken(t, conn, wrap, tok, iamRepo)
|
||||
got, finalErr := s.ListAuthTokens(fullGrantAuthCtx, tc.input)
|
||||
if tc.wantErr != nil {
|
||||
require.ErrorIs(t, finalErr, tc.wantErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, finalErr)
|
||||
var gotIDs []string
|
||||
for _, g := range got.Items {
|
||||
fmt.Println("ID:", g.GetId(), "Scope:", g.GetScopeId())
|
||||
gotIDs = append(gotIDs, g.GetId())
|
||||
}
|
||||
|
||||
for _, id := range tc.wantIDs {
|
||||
require.Contains(t, gotIDs, id)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
+5
-4
@@ -678,10 +678,11 @@ func newOutputOpts(
|
||||
authResults auth.VerifyResults,
|
||||
) ([]handlers.Option, bool) {
|
||||
res := perms.Resource{
|
||||
ScopeId: authResults.Scope.Id,
|
||||
Type: resource.CredentialLibrary,
|
||||
Pin: credentialStoreId,
|
||||
Id: item.GetPublicId(),
|
||||
ScopeId: authResults.Scope.Id,
|
||||
ParentScopeId: authResults.Scope.GetParentScopeId(),
|
||||
Type: resource.CredentialLibrary,
|
||||
Pin: credentialStoreId,
|
||||
Id: item.GetPublicId(),
|
||||
}
|
||||
authorizedActions := authResults.FetchActionSetForId(ctx, item.GetPublicId(), IdActions, auth.WithResource(&res)).Strings()
|
||||
if len(authorizedActions) == 0 {
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package credentiallibraries_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/authtoken"
|
||||
"github.com/hashicorp/boundary/internal/credential/vault"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/credentiallibraries"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/scheduler"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGrants_ReadActions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
rw := db.New(conn)
|
||||
wrap := db.TestWrapper(t)
|
||||
iamRepo := iam.TestRepo(t, conn, wrap)
|
||||
iamRepoFn := func() (*iam.Repository, error) {
|
||||
return iamRepo, nil
|
||||
}
|
||||
kmsCache := kms.TestKms(t, conn, wrap)
|
||||
sche := scheduler.TestScheduler(t, conn, wrap)
|
||||
|
||||
vaultRepoFn := func() (*vault.Repository, error) {
|
||||
return vault.NewRepository(ctx, rw, rw, kmsCache, sche)
|
||||
}
|
||||
|
||||
s, err := credentiallibraries.NewService(ctx, iamRepoFn, vaultRepoFn, 1000)
|
||||
require.NoError(t, err)
|
||||
org, proj := iam.TestScopes(t, iamRepo)
|
||||
|
||||
proj1CredStore := vault.TestCredentialStores(t, conn, wrap, proj.PublicId, 1)
|
||||
proj1Libs := vault.TestCredentialLibraries(t, conn, wrap, proj1CredStore[0].GetPublicId(), 3)
|
||||
|
||||
t.Run("List", func(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input *pbs.ListCredentialLibrariesRequest
|
||||
rolesToCreate []authtoken.TestRoleGrantsForToken
|
||||
wantErr error
|
||||
wantIDs []string
|
||||
}{
|
||||
{
|
||||
name: "global role grant descendant returns all credentials library",
|
||||
input: &pbs.ListCredentialLibrariesRequest{
|
||||
CredentialStoreId: proj1CredStore[0].GetPublicId(),
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=credential-library;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeDescendants},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: []string{proj1Libs[0].GetPublicId(), proj1Libs[1].GetPublicId(), proj1Libs[2].GetPublicId()},
|
||||
},
|
||||
{
|
||||
name: "org role grant this and children returns all credentials library",
|
||||
input: &pbs.ListCredentialLibrariesRequest{
|
||||
CredentialStoreId: proj1CredStore[0].GetPublicId(),
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: org.GetPublicId(),
|
||||
GrantStrings: []string{"ids=*;type=credential-library;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: []string{proj1Libs[0].GetPublicId(), proj1Libs[1].GetPublicId(), proj1Libs[2].GetPublicId()},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tok := authtoken.TestAuthTokenWithRoles(t, conn, kmsCache, globals.GlobalPrefix, tc.rolesToCreate)
|
||||
fullGrantAuthCtx := auth.TestAuthContextFromToken(t, conn, wrap, tok, iamRepo)
|
||||
got, finalErr := s.ListCredentialLibraries(fullGrantAuthCtx, tc.input)
|
||||
if tc.wantErr != nil {
|
||||
require.ErrorIs(t, finalErr, tc.wantErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, finalErr)
|
||||
var gotIDs []string
|
||||
for _, g := range got.Items {
|
||||
gotIDs = append(gotIDs, g.GetId())
|
||||
}
|
||||
require.ElementsMatch(t, tc.wantIDs, gotIDs)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -640,9 +640,10 @@ func newOutputOpts(
|
||||
authResults auth.VerifyResults,
|
||||
) ([]handlers.Option, bool) {
|
||||
res := perms.Resource{
|
||||
ScopeId: authResults.Scope.Id,
|
||||
Type: resource.Credential,
|
||||
Pin: credentialStoreId,
|
||||
ScopeId: authResults.Scope.Id,
|
||||
ParentScopeId: authResults.Scope.ParentScopeId,
|
||||
Type: resource.Credential,
|
||||
Pin: credentialStoreId,
|
||||
}
|
||||
res.Id = item.GetPublicId()
|
||||
authorizedActions := authResults.FetchActionSetForId(ctx, item.GetPublicId(), IdActions, auth.WithResource(&res)).Strings()
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package credentials_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/authtoken"
|
||||
"github.com/hashicorp/boundary/internal/credential/static"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/credentials"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestGrants_ReadActions tests read actions to assert that grants are being applied properly
|
||||
//
|
||||
// Role - which scope the role is created in
|
||||
// - global level
|
||||
// - org level
|
||||
// - proj level
|
||||
// Grant - what IAM grant scope is set for the permission
|
||||
// - global: descendant
|
||||
// - org: children
|
||||
// - project: this
|
||||
// Scopes [resource]:
|
||||
// - global
|
||||
// - org1
|
||||
// - proj1
|
||||
func TestGrants_ReadActions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrap := db.TestWrapper(t)
|
||||
rw := db.New(conn)
|
||||
iamRepo := iam.TestRepo(t, conn, wrap)
|
||||
kmsCache := kms.TestKms(t, conn, wrap)
|
||||
|
||||
iamRepoFn := func() (*iam.Repository, error) {
|
||||
return iamRepo, nil
|
||||
}
|
||||
staticRepoFn := func() (*static.Repository, error) {
|
||||
return static.NewRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
s, err := credentials.NewService(ctx, iamRepoFn, staticRepoFn, 1000)
|
||||
require.NoError(t, err)
|
||||
|
||||
org, proj := iam.TestScopes(t, iamRepo)
|
||||
|
||||
credStore := static.TestCredentialStore(t, conn, wrap, proj.GetPublicId())
|
||||
var wantCreds []string
|
||||
for i := 0; i < 10; i++ {
|
||||
user := fmt.Sprintf("user-%d", i)
|
||||
pass := fmt.Sprintf("pass-%d", i)
|
||||
c := static.TestUsernamePasswordCredential(t, conn, wrap, user, pass, credStore.GetPublicId(), proj.GetPublicId())
|
||||
require.NoError(t, err)
|
||||
wantCreds = append(wantCreds, c.GetPublicId())
|
||||
}
|
||||
|
||||
t.Run("List", func(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input *pbs.ListCredentialsRequest
|
||||
rolesToCreate []authtoken.TestRoleGrantsForToken
|
||||
wantErr error
|
||||
wantIDs []string
|
||||
}{
|
||||
{
|
||||
name: "global role grant this returns all created credentials",
|
||||
input: &pbs.ListCredentialsRequest{
|
||||
CredentialStoreId: credStore.GetPublicId(),
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=credential;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeDescendants},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: wantCreds,
|
||||
},
|
||||
{
|
||||
name: "org role grant this returns all created credentials",
|
||||
input: &pbs.ListCredentialsRequest{
|
||||
CredentialStoreId: credStore.GetPublicId(),
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: org.PublicId,
|
||||
GrantStrings: []string{"ids=*;type=credential;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: wantCreds,
|
||||
},
|
||||
{
|
||||
name: "project role grant this returns all created credentials",
|
||||
input: &pbs.ListCredentialsRequest{
|
||||
CredentialStoreId: credStore.GetPublicId(),
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: proj.PublicId,
|
||||
GrantStrings: []string{"ids=*;type=credential;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: wantCreds,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tok := authtoken.TestAuthTokenWithRoles(t, conn, kmsCache, globals.GlobalPrefix, tc.rolesToCreate)
|
||||
fullGrantAuthCtx := auth.TestAuthContextFromToken(t, conn, wrap, tok, iamRepo)
|
||||
got, finalErr := s.ListCredentials(fullGrantAuthCtx, tc.input)
|
||||
if tc.wantErr != nil {
|
||||
require.ErrorIs(t, finalErr, tc.wantErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, finalErr)
|
||||
var gotIDs []string
|
||||
for _, g := range got.Items {
|
||||
gotIDs = append(gotIDs, g.GetId())
|
||||
}
|
||||
require.ElementsMatch(t, tc.wantIDs, gotIDs)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -676,9 +676,10 @@ func newOutputOpts(
|
||||
authzScopes map[string]*scopes.ScopeInfo,
|
||||
) ([]handlers.Option, bool, error) {
|
||||
res := perms.Resource{
|
||||
Type: resource.CredentialStore,
|
||||
Id: item.GetPublicId(),
|
||||
ScopeId: item.GetProjectId(),
|
||||
Type: resource.CredentialStore,
|
||||
Id: item.GetPublicId(),
|
||||
ScopeId: item.GetProjectId(),
|
||||
ParentScopeId: authzScopes[item.GetProjectId()].GetParentScopeId(),
|
||||
}
|
||||
authorizedActions := authResults.FetchActionSetForId(ctx, item.GetPublicId(), IdActions, auth.WithResource(&res)).Strings()
|
||||
if len(authorizedActions) == 0 {
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package credentialstores_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/authtoken"
|
||||
"github.com/hashicorp/boundary/internal/credential"
|
||||
"github.com/hashicorp/boundary/internal/credential/static"
|
||||
"github.com/hashicorp/boundary/internal/credential/vault"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/credentialstores"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/scheduler"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestGrants_ReadActions tests read actions to assert that grants are being applied properly
|
||||
//
|
||||
// Role - which scope the role is created in
|
||||
// - global level
|
||||
// - org level
|
||||
// - proj level
|
||||
// Grant - what IAM grant scope is set for the permission
|
||||
// - global: descendant
|
||||
// - org: children
|
||||
// - project: this
|
||||
// Scopes [resource]:
|
||||
// - global
|
||||
// - org1
|
||||
// - proj1
|
||||
func TestGrants_ReadActions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrap := db.TestWrapper(t)
|
||||
rw := db.New(conn)
|
||||
iamRepo := iam.TestRepo(t, conn, wrap)
|
||||
kmsCache := kms.TestKms(t, conn, wrap)
|
||||
|
||||
sche := scheduler.TestScheduler(t, conn, wrap)
|
||||
iamRepoFn := func() (*iam.Repository, error) {
|
||||
return iamRepo, nil
|
||||
}
|
||||
vaultRepoFn := func() (*vault.Repository, error) {
|
||||
return vault.NewRepository(ctx, rw, rw, kmsCache, sche)
|
||||
}
|
||||
staticRepoFn := func() (*static.Repository, error) {
|
||||
return static.NewRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
credStoreRepoFn := func() (*credential.StoreRepository, error) {
|
||||
return credential.NewStoreRepository(context.Background(), rw, rw)
|
||||
}
|
||||
s, err := credentialstores.NewService(ctx, iamRepoFn, vaultRepoFn, staticRepoFn, credStoreRepoFn, 1000)
|
||||
require.NoError(t, err)
|
||||
|
||||
org, proj := iam.TestScopes(t, iamRepo)
|
||||
|
||||
var wantStores []string
|
||||
for _, s := range vault.TestCredentialStores(t, conn, wrap, proj.GetPublicId(), 5) {
|
||||
wantStores = append(wantStores, s.GetPublicId())
|
||||
}
|
||||
|
||||
for _, s := range static.TestCredentialStores(t, conn, wrap, proj.GetPublicId(), 5) {
|
||||
wantStores = append(wantStores, s.GetPublicId())
|
||||
}
|
||||
|
||||
t.Run("List", func(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input *pbs.ListCredentialStoresRequest
|
||||
rolesToCreate []authtoken.TestRoleGrantsForToken
|
||||
wantErr error
|
||||
wantIDs []string
|
||||
}{
|
||||
{
|
||||
name: "global role grant this returns all created credential stores",
|
||||
input: &pbs.ListCredentialStoresRequest{
|
||||
ScopeId: globals.GlobalPrefix,
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=credential-store;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeDescendants},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: wantStores,
|
||||
},
|
||||
{
|
||||
name: "org role grant this returns all created credential stores",
|
||||
input: &pbs.ListCredentialStoresRequest{
|
||||
ScopeId: org.GetPublicId(),
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: org.PublicId,
|
||||
GrantStrings: []string{"ids=*;type=credential-store;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: wantStores,
|
||||
},
|
||||
{
|
||||
name: "project role grant this returns all created credential stores",
|
||||
input: &pbs.ListCredentialStoresRequest{
|
||||
ScopeId: proj.GetPublicId(),
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: proj.PublicId,
|
||||
GrantStrings: []string{"ids=*;type=credential-store;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: wantStores,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tok := authtoken.TestAuthTokenWithRoles(t, conn, kmsCache, globals.GlobalPrefix, tc.rolesToCreate)
|
||||
fullGrantAuthCtx := auth.TestAuthContextFromToken(t, conn, wrap, tok, iamRepo)
|
||||
got, finalErr := s.ListCredentialStores(fullGrantAuthCtx, tc.input)
|
||||
if tc.wantErr != nil {
|
||||
require.ErrorIs(t, finalErr, tc.wantErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, finalErr)
|
||||
var gotIDs []string
|
||||
for _, g := range got.Items {
|
||||
gotIDs = append(gotIDs, g.GetId())
|
||||
}
|
||||
require.ElementsMatch(t, tc.wantIDs, gotIDs)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package groups_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/authtoken"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/groups"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestGrants_ReadActions tests read actions to assert that grants are being applied properly
|
||||
//
|
||||
// Role - which scope the role is created in
|
||||
// - global level
|
||||
// - org level
|
||||
// - project level
|
||||
// Grant - what IAM grant scope is set for the permission
|
||||
// - global: descendant
|
||||
// - org: children
|
||||
// - project
|
||||
// Scopes [resource]:
|
||||
// - global [globalGroup]
|
||||
// - org1 [org1Group]
|
||||
// - proj1 [proj1Group]
|
||||
// - org2 [org2Group]
|
||||
// - proj2 [proj2Group]
|
||||
// - proj3 [proj3Group]
|
||||
func TestGrants_ReadActions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrap := db.TestWrapper(t)
|
||||
iamRepo := iam.TestRepo(t, conn, wrap)
|
||||
repoFn := func() (*iam.Repository, error) {
|
||||
return iamRepo, nil
|
||||
}
|
||||
kmsCache := kms.TestKms(t, conn, wrap)
|
||||
s, err := groups.NewService(ctx, repoFn, 1000)
|
||||
require.NoError(t, err)
|
||||
org1, _ := iam.TestScopes(t, iamRepo)
|
||||
org2, proj2 := iam.TestScopes(t, iamRepo)
|
||||
proj3 := iam.TestProject(t, iamRepo, org2.PublicId)
|
||||
globalGroup := iam.TestGroup(t, conn, globals.GlobalPrefix, iam.WithDescription("global"), iam.WithName("global"))
|
||||
org1Group := iam.TestGroup(t, conn, org1.GetPublicId(), iam.WithDescription("org1"), iam.WithName("org1"))
|
||||
org2Group := iam.TestGroup(t, conn, org2.GetPublicId(), iam.WithDescription("org2"), iam.WithName("org2"))
|
||||
|
||||
proj2Group := iam.TestGroup(t, conn, proj2.GetPublicId(), iam.WithDescription("proj2"), iam.WithName("proj2"))
|
||||
proj3Group := iam.TestGroup(t, conn, proj3.GetPublicId(), iam.WithDescription("proj3"), iam.WithName("proj3"))
|
||||
|
||||
t.Run("List", func(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input *pbs.ListGroupsRequest
|
||||
rolesToCreate []authtoken.TestRoleGrantsForToken
|
||||
wantErr error
|
||||
wantIDs []string
|
||||
}{
|
||||
{
|
||||
name: "global role grant this and children returns global and org groups",
|
||||
input: &pbs.ListGroupsRequest{
|
||||
ScopeId: globals.GlobalPrefix,
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=group;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: []string{globalGroup.PublicId, org1Group.PublicId, org2Group.PublicId},
|
||||
},
|
||||
{
|
||||
name: "org role grant this and children returns org and project groups",
|
||||
input: &pbs.ListGroupsRequest{
|
||||
ScopeId: org2.PublicId,
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: org2.PublicId,
|
||||
GrantStrings: []string{"ids=*;type=group;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: []string{org2Group.PublicId, proj2Group.PublicId, proj3Group.PublicId},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tok := authtoken.TestAuthTokenWithRoles(t, conn, kmsCache, globals.GlobalPrefix, tc.rolesToCreate)
|
||||
fullGrantAuthCtx := auth.TestAuthContextFromToken(t, conn, wrap, tok, iamRepo)
|
||||
got, finalErr := s.ListGroups(fullGrantAuthCtx, tc.input)
|
||||
if tc.wantErr != nil {
|
||||
require.ErrorIs(t, finalErr, tc.wantErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, finalErr)
|
||||
var gotIDs []string
|
||||
for _, g := range got.Items {
|
||||
gotIDs = append(gotIDs, g.GetId())
|
||||
}
|
||||
require.ElementsMatch(t, tc.wantIDs, gotIDs)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -840,6 +840,7 @@ func newOutputOpts(ctx context.Context, item *iam.Group, scopeInfoMap map[string
|
||||
}
|
||||
res.Id = item.GetPublicId()
|
||||
res.ScopeId = item.GetScopeId()
|
||||
res.ParentScopeId = scopeInfoMap[item.GetScopeId()].GetParentScopeId()
|
||||
authorizedActions := authResults.FetchActionSetForId(ctx, item.GetPublicId(), IdActions, auth.WithResource(&res))
|
||||
if len(authorizedActions) == 0 {
|
||||
return nil, false
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package host_catalogs_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/authtoken"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/host_catalogs"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/internal/host"
|
||||
hostplugin "github.com/hashicorp/boundary/internal/host/plugin"
|
||||
"github.com/hashicorp/boundary/internal/host/static"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/plugin"
|
||||
"github.com/hashicorp/boundary/internal/scheduler"
|
||||
plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestGrants_ReadActions tests read actions to assert that grants are being applied properly
|
||||
//
|
||||
// Role - which scope the role is created in
|
||||
// - global level
|
||||
// - org level
|
||||
// - proj level
|
||||
// Grant - what IAM grant scope is set for the permission
|
||||
// - global: descendant
|
||||
// - org: children
|
||||
// - project: this
|
||||
// Scopes [resource]:
|
||||
// - global
|
||||
// - org1
|
||||
// - proj1
|
||||
func TestGrants_ReadActions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrap := db.TestWrapper(t)
|
||||
rw := db.New(conn)
|
||||
iamRepo := iam.TestRepo(t, conn, wrap)
|
||||
kmsCache := kms.TestKms(t, conn, wrap)
|
||||
sche := scheduler.TestScheduler(t, conn, wrap)
|
||||
staticRepoFn := func() (*static.Repository, error) {
|
||||
return static.NewRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
pluginHostRepoFn := func() (*hostplugin.Repository, error) {
|
||||
return hostplugin.NewRepository(ctx, rw, rw, kmsCache, sche, map[string]plgpb.HostPluginServiceClient{})
|
||||
}
|
||||
pluginRepoFn := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
iamRepoFn := func() (*iam.Repository, error) {
|
||||
return iam.TestRepo(t, conn, wrap), nil
|
||||
}
|
||||
catalogServiceFn := func() (*host.CatalogRepository, error) {
|
||||
return host.NewCatalogRepository(ctx, rw, rw)
|
||||
}
|
||||
s, err := host_catalogs.NewService(ctx, staticRepoFn, pluginHostRepoFn, pluginRepoFn, iamRepoFn, catalogServiceFn, 1000)
|
||||
require.NoError(t, err)
|
||||
|
||||
org, proj := iam.TestScopes(t, iamRepo)
|
||||
|
||||
hcs := static.TestCatalogs(t, conn, proj.GetPublicId(), 5)
|
||||
var wantHcs []string
|
||||
for _, h := range hcs {
|
||||
wantHcs = append(wantHcs, h.GetPublicId())
|
||||
}
|
||||
|
||||
t.Run("List", func(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input *pbs.ListHostCatalogsRequest
|
||||
rolesToCreate []authtoken.TestRoleGrantsForToken
|
||||
wantErr error
|
||||
wantIDs []string
|
||||
}{
|
||||
{
|
||||
name: "global role grant this returns all created host catalogs",
|
||||
input: &pbs.ListHostCatalogsRequest{
|
||||
ScopeId: proj.GetPublicId(),
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=host-catalog;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeDescendants},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: wantHcs,
|
||||
},
|
||||
{
|
||||
name: "org role grant this returns all created host catalogs",
|
||||
input: &pbs.ListHostCatalogsRequest{
|
||||
ScopeId: proj.GetPublicId(),
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: org.PublicId,
|
||||
GrantStrings: []string{"ids=*;type=host-catalog;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: wantHcs,
|
||||
},
|
||||
{
|
||||
name: "project role grant this returns all created host catalogs",
|
||||
input: &pbs.ListHostCatalogsRequest{
|
||||
ScopeId: proj.GetPublicId(),
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: proj.PublicId,
|
||||
GrantStrings: []string{"ids=*;type=host-catalog;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: wantHcs,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tok := authtoken.TestAuthTokenWithRoles(t, conn, kmsCache, globals.GlobalPrefix, tc.rolesToCreate)
|
||||
fullGrantAuthCtx := auth.TestAuthContextFromToken(t, conn, wrap, tok, iamRepo)
|
||||
got, finalErr := s.ListHostCatalogs(fullGrantAuthCtx, tc.input)
|
||||
if tc.wantErr != nil {
|
||||
require.ErrorIs(t, finalErr, tc.wantErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, finalErr)
|
||||
var gotIDs []string
|
||||
for _, g := range got.Items {
|
||||
gotIDs = append(gotIDs, g.GetId())
|
||||
}
|
||||
require.ElementsMatch(t, tc.wantIDs, gotIDs)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -775,9 +775,10 @@ func newOutputOpts(
|
||||
pluginMap map[string]*plugin.Plugin,
|
||||
) ([]handlers.Option, bool, error) {
|
||||
res := perms.Resource{
|
||||
Type: resource.HostCatalog,
|
||||
Id: item.GetPublicId(),
|
||||
ScopeId: item.GetProjectId(),
|
||||
Type: resource.HostCatalog,
|
||||
Id: item.GetPublicId(),
|
||||
ScopeId: item.GetProjectId(),
|
||||
ParentScopeId: scopeInfoMap[item.GetProjectId()].GetParentScopeId(),
|
||||
}
|
||||
authorizedActions := authResults.FetchActionSetForId(ctx, item.GetPublicId(), IdActions, auth.WithResource(&res)).Strings()
|
||||
if len(authorizedActions) == 0 {
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package host_sets_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/authtoken"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/host_sets"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
hostplugin "github.com/hashicorp/boundary/internal/host/plugin"
|
||||
"github.com/hashicorp/boundary/internal/host/static"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/scheduler"
|
||||
plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestGrants_ReadActions tests read actions to assert that grants are being applied properly
|
||||
//
|
||||
// Role - which scope the role is created in
|
||||
// - global level
|
||||
// - org level
|
||||
// - proj level
|
||||
// Grant - what IAM grant scope is set for the permission
|
||||
// - global: descendant
|
||||
// - org: children
|
||||
// - project: this
|
||||
// Scopes [resource]:
|
||||
// - global
|
||||
// - org1
|
||||
// - proj1
|
||||
func TestGrants_ReadActions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrap := db.TestWrapper(t)
|
||||
rw := db.New(conn)
|
||||
iamRepo := iam.TestRepo(t, conn, wrap)
|
||||
kmsCache := kms.TestKms(t, conn, wrap)
|
||||
sche := scheduler.TestScheduler(t, conn, wrap)
|
||||
pluginRepoFn := func() (*hostplugin.Repository, error) {
|
||||
return hostplugin.NewRepository(ctx, rw, rw, kmsCache, sche, map[string]plgpb.HostPluginServiceClient{})
|
||||
}
|
||||
repoFn := func() (*static.Repository, error) {
|
||||
return static.NewRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
s, err := host_sets.NewService(ctx, repoFn, pluginRepoFn, 1000)
|
||||
require.NoError(t, err)
|
||||
|
||||
org, proj := iam.TestScopes(t, iamRepo)
|
||||
|
||||
hcs := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)
|
||||
hc := hcs[0]
|
||||
|
||||
hsets := static.TestSets(t, conn, hc.GetPublicId(), 5)
|
||||
var wantHostSets []string
|
||||
for _, h := range hsets {
|
||||
wantHostSets = append(wantHostSets, h.GetPublicId())
|
||||
}
|
||||
|
||||
t.Run("List", func(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input *pbs.ListHostSetsRequest
|
||||
rolesToCreate []authtoken.TestRoleGrantsForToken
|
||||
wantErr error
|
||||
wantIDs []string
|
||||
}{
|
||||
{
|
||||
name: "global role grant this returns all created host-set",
|
||||
input: &pbs.ListHostSetsRequest{
|
||||
HostCatalogId: hc.GetPublicId(),
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=host-set;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeDescendants},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: wantHostSets,
|
||||
},
|
||||
{
|
||||
name: "org role grant this returns all created host-set",
|
||||
input: &pbs.ListHostSetsRequest{
|
||||
HostCatalogId: hc.GetPublicId(),
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: org.PublicId,
|
||||
GrantStrings: []string{"ids=*;type=host-set;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: wantHostSets,
|
||||
},
|
||||
{
|
||||
name: "project role grant this returns all created host-set",
|
||||
input: &pbs.ListHostSetsRequest{
|
||||
HostCatalogId: hc.GetPublicId(),
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: proj.PublicId,
|
||||
GrantStrings: []string{"ids=*;type=host-set;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: wantHostSets,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tok := authtoken.TestAuthTokenWithRoles(t, conn, kmsCache, globals.GlobalPrefix, tc.rolesToCreate)
|
||||
fullGrantAuthCtx := auth.TestAuthContextFromToken(t, conn, wrap, tok, iamRepo)
|
||||
got, finalErr := s.ListHostSets(fullGrantAuthCtx, tc.input)
|
||||
if tc.wantErr != nil {
|
||||
require.ErrorIs(t, finalErr, tc.wantErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, finalErr)
|
||||
var gotIDs []string
|
||||
for _, g := range got.Items {
|
||||
gotIDs = append(gotIDs, g.GetId())
|
||||
}
|
||||
require.ElementsMatch(t, tc.wantIDs, gotIDs)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -755,10 +755,11 @@ func (s Service) deleteFromRepo(ctx context.Context, projectId, id string) (bool
|
||||
|
||||
func newOutputOpts(ctx context.Context, item host.Set, plg *plugins.PluginInfo, authResults auth.VerifyResults) ([]handlers.Option, bool) {
|
||||
res := perms.Resource{
|
||||
ScopeId: authResults.Scope.Id,
|
||||
Id: item.GetPublicId(),
|
||||
Type: resource.HostSet,
|
||||
Pin: item.GetCatalogId(),
|
||||
ScopeId: authResults.Scope.Id,
|
||||
ParentScopeId: authResults.Scope.ParentScopeId,
|
||||
Id: item.GetPublicId(),
|
||||
Type: resource.HostSet,
|
||||
Pin: item.GetCatalogId(),
|
||||
}
|
||||
res.Id = item.GetPublicId()
|
||||
idActions := idActionsTypeMap[globals.ResourceInfoFromPrefix(item.GetPublicId()).Subtype]
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package hosts_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/authtoken"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/hosts"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
hostplugin "github.com/hashicorp/boundary/internal/host/plugin"
|
||||
"github.com/hashicorp/boundary/internal/host/static"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/scheduler"
|
||||
plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestGrants_ReadActions tests read actions to assert that grants are being applied properly
|
||||
//
|
||||
// Role - which scope the role is created in
|
||||
// - global level
|
||||
// - org level
|
||||
// - proj level
|
||||
// Grant - what IAM grant scope is set for the permission
|
||||
// - global: descendant
|
||||
// - org: children
|
||||
// - project: this
|
||||
// Scopes [resource]:
|
||||
// - global
|
||||
// - org1
|
||||
// - proj1
|
||||
func TestGrants_ReadActions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrap := db.TestWrapper(t)
|
||||
rw := db.New(conn)
|
||||
iamRepo := iam.TestRepo(t, conn, wrap)
|
||||
kmsCache := kms.TestKms(t, conn, wrap)
|
||||
sche := scheduler.TestScheduler(t, conn, wrap)
|
||||
pluginRepoFn := func() (*hostplugin.Repository, error) {
|
||||
return hostplugin.NewRepository(ctx, rw, rw, kmsCache, sche, map[string]plgpb.HostPluginServiceClient{})
|
||||
}
|
||||
repoFn := func() (*static.Repository, error) {
|
||||
return static.NewRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
s, err := hosts.NewService(ctx, repoFn, pluginRepoFn, 1000)
|
||||
require.NoError(t, err)
|
||||
|
||||
org, proj := iam.TestScopes(t, iamRepo)
|
||||
|
||||
hcs := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)
|
||||
hc := hcs[0]
|
||||
|
||||
hset := static.TestSets(t, conn, hc.GetPublicId(), 1)[0]
|
||||
var wantHs []string
|
||||
testHosts := static.TestHosts(t, conn, hc.GetPublicId(), 10)
|
||||
static.TestSetMembers(t, conn, hset.GetPublicId(), testHosts)
|
||||
for _, h := range testHosts {
|
||||
wantHs = append(wantHs, h.GetPublicId())
|
||||
}
|
||||
|
||||
t.Run("List", func(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input *pbs.ListHostsRequest
|
||||
rolesToCreate []authtoken.TestRoleGrantsForToken
|
||||
wantErr error
|
||||
wantIDs []string
|
||||
}{
|
||||
{
|
||||
name: "global role grant this returns all created hosts",
|
||||
input: &pbs.ListHostsRequest{
|
||||
HostCatalogId: hc.GetPublicId(),
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=host;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeDescendants},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: wantHs,
|
||||
},
|
||||
{
|
||||
name: "org role grant this returns all created hosts",
|
||||
input: &pbs.ListHostsRequest{
|
||||
HostCatalogId: hc.GetPublicId(),
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: org.PublicId,
|
||||
GrantStrings: []string{"ids=*;type=host;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: wantHs,
|
||||
},
|
||||
{
|
||||
name: "project role grant this returns all created hosts",
|
||||
input: &pbs.ListHostsRequest{
|
||||
HostCatalogId: hc.GetPublicId(),
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: proj.PublicId,
|
||||
GrantStrings: []string{"ids=*;type=host;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: wantHs,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tok := authtoken.TestAuthTokenWithRoles(t, conn, kmsCache, globals.GlobalPrefix, tc.rolesToCreate)
|
||||
fullGrantAuthCtx := auth.TestAuthContextFromToken(t, conn, wrap, tok, iamRepo)
|
||||
got, finalErr := s.ListHosts(fullGrantAuthCtx, tc.input)
|
||||
if tc.wantErr != nil {
|
||||
require.ErrorIs(t, finalErr, tc.wantErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, finalErr)
|
||||
var gotIDs []string
|
||||
for _, g := range got.Items {
|
||||
gotIDs = append(gotIDs, g.GetId())
|
||||
}
|
||||
require.ElementsMatch(t, tc.wantIDs, gotIDs)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -622,10 +622,11 @@ func toPluginInfo(plg *plugin.Plugin) *plugins.PluginInfo {
|
||||
|
||||
func newOutputOpts(ctx context.Context, item host.Host, plg *plugin.Plugin, authResults auth.VerifyResults) ([]handlers.Option, bool) {
|
||||
res := perms.Resource{
|
||||
ScopeId: authResults.Scope.Id,
|
||||
Type: resource.Host,
|
||||
Pin: item.GetCatalogId(),
|
||||
Id: item.GetPublicId(),
|
||||
ScopeId: authResults.Scope.Id,
|
||||
ParentScopeId: authResults.Scope.ParentScopeId,
|
||||
Type: resource.Host,
|
||||
Pin: item.GetCatalogId(),
|
||||
Id: item.GetPublicId(),
|
||||
}
|
||||
res.Id = item.GetPublicId()
|
||||
idActions := idActionsTypeMap[globals.ResourceInfoFromPrefix(res.Id).Subtype]
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package managed_groups_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/auth/ldap"
|
||||
"github.com/hashicorp/boundary/internal/auth/oidc"
|
||||
"github.com/hashicorp/boundary/internal/authtoken"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/managed_groups"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestGrants_ReadActions tests read actions to assert that grants are being applied properly
|
||||
func TestGrants_ReadActions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrap := db.TestWrapper(t)
|
||||
rw := db.New(conn)
|
||||
iamRepo := iam.TestRepo(t, conn, wrap)
|
||||
kmsCache := kms.TestKms(t, conn, wrap)
|
||||
oidcRepoFn := func() (*oidc.Repository, error) {
|
||||
// Use a small limit to test that membership lookup is explicitly unlimited
|
||||
return oidc.NewRepository(ctx, rw, rw, kmsCache, oidc.WithLimit(1))
|
||||
}
|
||||
ldapRepoFn := func() (*ldap.Repository, error) {
|
||||
// Use a small limit to test that membership lookup is explicitly unlimited
|
||||
return ldap.NewRepository(ctx, rw, rw, kmsCache, ldap.WithLimit(ctx, 1))
|
||||
}
|
||||
|
||||
s, err := managed_groups.NewService(ctx, oidcRepoFn, ldapRepoFn, 1000)
|
||||
require.NoError(t, err)
|
||||
|
||||
org, _ := iam.TestScopes(t, iamRepo)
|
||||
|
||||
globalDBWrapper, err := kmsCache.GetWrapper(ctx, globals.GlobalPrefix, kms.KeyPurposeDatabase)
|
||||
require.NoError(t, err)
|
||||
globalOidcAm := oidc.TestAuthMethod(
|
||||
t, conn, globalDBWrapper, globals.GlobalPrefix, oidc.ActivePrivateState,
|
||||
"alice-rp", "fido",
|
||||
oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://www.alice.com")[0]),
|
||||
oidc.WithSigningAlgs(oidc.RS256),
|
||||
oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://www.alice.com/callback")[0]),
|
||||
)
|
||||
_ = oidc.TestAccount(t, conn, globalOidcAm, "test-subject-1", oidc.WithName("global-1"), oidc.WithDescription("global-1"))
|
||||
_ = oidc.TestAccount(t, conn, globalOidcAm, "test-subject-2", oidc.WithName("global-2"), oidc.WithDescription("global-2"))
|
||||
globalMg1 := oidc.TestManagedGroup(t, conn, globalOidcAm, oidc.TestFakeManagedGroupFilter)
|
||||
globalMg2 := oidc.TestManagedGroup(t, conn, globalOidcAm, oidc.TestFakeManagedGroupFilter)
|
||||
|
||||
orgDBWrapper, err := kmsCache.GetWrapper(ctx, org.PublicId, kms.KeyPurposeDatabase)
|
||||
require.NoError(t, err)
|
||||
orgLdapAm := ldap.TestAuthMethod(t, conn, orgDBWrapper, org.PublicId, []string{"ldaps://ldap1"}, ldap.WithName(ctx, "global"), ldap.WithDescription(ctx, "global"))
|
||||
_ = ldap.TestAccount(t, conn, orgLdapAm, "test-login-name-1", ldap.WithMemberOfGroups(ctx, "admin"), ldap.WithName(ctx, "org-1"), ldap.WithDescription(ctx, "org-1"))
|
||||
_ = ldap.TestAccount(t, conn, orgLdapAm, "test-login-name-2", ldap.WithMemberOfGroups(ctx, "admin"), ldap.WithName(ctx, "org-2"), ldap.WithDescription(ctx, "org-2"))
|
||||
orgMg := ldap.TestManagedGroup(t, conn, orgLdapAm, []string{"admin", "users"})
|
||||
|
||||
t.Run("List", func(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input *pbs.ListManagedGroupsRequest
|
||||
rolesToCreate []authtoken.TestRoleGrantsForToken
|
||||
wantErr error
|
||||
wantIDs []string
|
||||
}{
|
||||
{
|
||||
name: "global role grant this returns all created oidc managed groups",
|
||||
input: &pbs.ListManagedGroupsRequest{
|
||||
AuthMethodId: globalOidcAm.PublicId,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=managed-group;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeDescendants},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: []string{globalMg1.PublicId, globalMg2.PublicId},
|
||||
},
|
||||
{
|
||||
name: "org role grant this returns all created ldap managed groups",
|
||||
input: &pbs.ListManagedGroupsRequest{
|
||||
AuthMethodId: orgLdapAm.PublicId,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: org.PublicId,
|
||||
GrantStrings: []string{"ids=*;type=managed-group;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: []string{
|
||||
orgMg.PublicId,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tok := authtoken.TestAuthTokenWithRoles(t, conn, kmsCache, globals.GlobalPrefix, tc.rolesToCreate)
|
||||
fullGrantAuthCtx := auth.TestAuthContextFromToken(t, conn, wrap, tok, iamRepo)
|
||||
got, finalErr := s.ListManagedGroups(fullGrantAuthCtx, tc.input)
|
||||
if tc.wantErr != nil {
|
||||
require.ErrorIs(t, finalErr, tc.wantErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, finalErr)
|
||||
var gotIDs []string
|
||||
for _, g := range got.Items {
|
||||
gotIDs = append(gotIDs, g.GetId())
|
||||
}
|
||||
require.ElementsMatch(t, tc.wantIDs, gotIDs)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -998,9 +998,10 @@ func validateListRequest(ctx context.Context, req *pbs.ListManagedGroupsRequest)
|
||||
|
||||
func newOutputOpts(ctx context.Context, item auth.ManagedGroup, authMethodId string, authResults requestauth.VerifyResults) ([]handlers.Option, bool) {
|
||||
res := perms.Resource{
|
||||
ScopeId: authResults.Scope.Id,
|
||||
Type: resource.ManagedGroup,
|
||||
Pin: authMethodId,
|
||||
ScopeId: authResults.Scope.Id,
|
||||
ParentScopeId: authResults.Scope.ParentScopeId,
|
||||
Type: resource.ManagedGroup,
|
||||
Pin: authMethodId,
|
||||
}
|
||||
res.Id = item.GetPublicId()
|
||||
authorizedActions := authResults.FetchActionSetForId(ctx, item.GetPublicId(), IdActions[globals.ResourceInfoFromPrefix(item.GetPublicId()).Subtype], requestauth.WithResource(&res)).Strings()
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package roles_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/authtoken"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/roles"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestGrants_ReadActions tests read actions to assert that grants are being applied properly
|
||||
//
|
||||
// Role - which scope the role is created in
|
||||
// - global level
|
||||
// - org level
|
||||
// - project level
|
||||
// Grant - what IAM grant scope is set for the permission
|
||||
// - global: descendant
|
||||
// - org: children
|
||||
// - project
|
||||
// Scopes [resource]:
|
||||
// - global [globalRole]
|
||||
// - org1 [org1Role]
|
||||
// - proj1 [proj1Role]
|
||||
// - org2 [org2Role]
|
||||
// - proj2 [proj2Role]
|
||||
// - proj3 [proj3Role]
|
||||
func TestGrants_ReadActions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrap := db.TestWrapper(t)
|
||||
iamRepo := iam.TestRepo(t, conn, wrap)
|
||||
repoFn := func() (*iam.Repository, error) {
|
||||
return iamRepo, nil
|
||||
}
|
||||
kmsCache := kms.TestKms(t, conn, wrap)
|
||||
s, err := roles.NewService(ctx, repoFn, 1000)
|
||||
require.NoError(t, err)
|
||||
|
||||
org1, _ := iam.TestScopes(t, iamRepo)
|
||||
org2, proj2 := iam.TestScopes(t, iamRepo)
|
||||
proj3 := iam.TestProject(t, iamRepo, org2.PublicId)
|
||||
|
||||
var defaultOrg1Roles []string
|
||||
org1Roles, err := s.ListRoles(auth.DisabledAuthTestContext(repoFn, org1.GetPublicId()), &pbs.ListRolesRequest{
|
||||
ScopeId: org1.GetPublicId(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
for _, r := range org1Roles.Items {
|
||||
defaultOrg1Roles = append(defaultOrg1Roles, r.GetId())
|
||||
}
|
||||
|
||||
org2Roles, err := s.ListRoles(auth.DisabledAuthTestContext(repoFn, org2.GetPublicId()), &pbs.ListRolesRequest{
|
||||
ScopeId: org2.GetPublicId(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
var defaultOrg2Roles []string
|
||||
for _, r := range org2Roles.Items {
|
||||
defaultOrg2Roles = append(defaultOrg2Roles, r.GetId())
|
||||
}
|
||||
|
||||
proj2Roles, err := s.ListRoles(auth.DisabledAuthTestContext(repoFn, proj2.GetPublicId()), &pbs.ListRolesRequest{
|
||||
ScopeId: proj2.GetPublicId(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
var defaultProj2Roles []string
|
||||
for _, r := range proj2Roles.Items {
|
||||
defaultProj2Roles = append(defaultProj2Roles, r.GetId())
|
||||
}
|
||||
|
||||
proj3Roles, err := s.ListRoles(auth.DisabledAuthTestContext(repoFn, proj3.GetPublicId()), &pbs.ListRolesRequest{
|
||||
ScopeId: proj3.GetPublicId(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
var defaultProj3Roles []string
|
||||
for _, r := range proj3Roles.Items {
|
||||
defaultProj3Roles = append(defaultProj3Roles, r.GetId())
|
||||
}
|
||||
|
||||
org1Role := iam.TestRole(t, conn, org1.GetPublicId(), iam.WithDescription("org1"), iam.WithName("org1"))
|
||||
org2Role := iam.TestRole(t, conn, org2.GetPublicId(), iam.WithDescription("org2"), iam.WithName("org2"))
|
||||
|
||||
proj2Role := iam.TestRole(t, conn, proj2.GetPublicId(), iam.WithDescription("proj2"), iam.WithName("proj2"))
|
||||
proj3Role := iam.TestRole(t, conn, proj3.GetPublicId(), iam.WithDescription("proj3"), iam.WithName("proj3"))
|
||||
|
||||
t.Run("List", func(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input *pbs.ListRolesRequest
|
||||
rolesToCreate []authtoken.TestRoleGrantsForToken
|
||||
wantErr error
|
||||
addRolesAtThisScope bool
|
||||
wantIDs []string
|
||||
}{
|
||||
{
|
||||
name: "global role grant this and children returns global and org roles",
|
||||
input: &pbs.ListRolesRequest{
|
||||
ScopeId: globals.GlobalPrefix,
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=role;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
addRolesAtThisScope: true,
|
||||
wantErr: nil,
|
||||
wantIDs: append(append([]string{
|
||||
org1Role.PublicId,
|
||||
org2Role.PublicId,
|
||||
}, defaultOrg1Roles...), defaultOrg2Roles...),
|
||||
},
|
||||
{
|
||||
name: "org role grant this and children returns org and project roles",
|
||||
input: &pbs.ListRolesRequest{
|
||||
ScopeId: org2.PublicId,
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: org2.PublicId,
|
||||
GrantStrings: []string{"ids=*;type=role;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
addRolesAtThisScope: true,
|
||||
wantErr: nil,
|
||||
wantIDs: append(append([]string{
|
||||
proj2Role.PublicId,
|
||||
proj3Role.PublicId,
|
||||
}, defaultProj2Roles...), defaultProj3Roles...),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tok := authtoken.TestAuthTokenWithRoles(t, conn, kmsCache, globals.GlobalPrefix, tc.rolesToCreate)
|
||||
fullGrantAuthCtx := auth.TestAuthContextFromToken(t, conn, wrap, tok, iamRepo)
|
||||
|
||||
// TestAuthTokenWithRoles creates a default role, so we need to add it to the expected list
|
||||
// if the grant scope contains 'this'
|
||||
// This will add the default roles to the expected list of roles
|
||||
if tc.addRolesAtThisScope {
|
||||
var rolesAtThisScope []string
|
||||
rolesAtThisScopeList, err := s.ListRoles(auth.DisabledAuthTestContext(repoFn, tc.input.ScopeId), &pbs.ListRolesRequest{
|
||||
ScopeId: tc.input.ScopeId,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
for _, r := range rolesAtThisScopeList.Items {
|
||||
rolesAtThisScope = append(rolesAtThisScope, r.GetId())
|
||||
}
|
||||
tc.wantIDs = append(tc.wantIDs, rolesAtThisScope...)
|
||||
}
|
||||
|
||||
got, finalErr := s.ListRoles(fullGrantAuthCtx, tc.input)
|
||||
if tc.wantErr != nil {
|
||||
require.ErrorIs(t, finalErr, tc.wantErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, finalErr)
|
||||
var gotIDs []string
|
||||
for _, g := range got.Items {
|
||||
gotIDs = append(gotIDs, g.GetId())
|
||||
}
|
||||
require.ElementsMatch(t, tc.wantIDs, gotIDs)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1521,6 +1521,7 @@ func newOutputOpts(ctx context.Context, item *iam.Role, scopeInfoMap map[string]
|
||||
}
|
||||
res.Id = item.GetPublicId()
|
||||
res.ScopeId = item.GetScopeId()
|
||||
res.ParentScopeId = scopeInfoMap[item.GetScopeId()].GetParentScopeId()
|
||||
authorizedActions := authResults.FetchActionSetForId(ctx, item.GetPublicId(), IdActions, auth.WithResource(&res))
|
||||
if len(authorizedActions) == 0 {
|
||||
return nil, false
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package scopes_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/authtoken"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/scopes"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestGrants_ReadActions tests read actions to assert that grants are being applied properly
|
||||
//
|
||||
// Role - which scope the role is created in
|
||||
// - global level
|
||||
// - org level
|
||||
// Grant - what IAM grant scope is set for the permission
|
||||
// - global: descendant
|
||||
// - org: children
|
||||
// Scopes [resource]:
|
||||
// - global [globalScope]
|
||||
// - org1
|
||||
// - proj1
|
||||
func TestGrants_ReadActions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrap := db.TestWrapper(t)
|
||||
iamRepo := iam.TestRepo(t, conn, wrap)
|
||||
kmsCache := kms.TestKms(t, conn, wrap)
|
||||
repoFn := func() (*iam.Repository, error) {
|
||||
return iamRepo, nil
|
||||
}
|
||||
s, err := scopes.NewServiceFn(ctx, repoFn, kmsCache, 1000)
|
||||
require.NoError(t, err)
|
||||
|
||||
org1, proj1 := iam.TestScopes(t, iamRepo)
|
||||
|
||||
t.Run("List", func(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input *pbs.ListScopesRequest
|
||||
rolesToCreate []authtoken.TestRoleGrantsForToken
|
||||
wantErr error
|
||||
wantIDs []string
|
||||
}{
|
||||
{
|
||||
name: "global role grant this returns all created scopes",
|
||||
input: &pbs.ListScopesRequest{
|
||||
ScopeId: globals.GlobalPrefix,
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=scope;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: []string{
|
||||
org1.PublicId,
|
||||
proj1.PublicId,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "org role grant this returns all created scopes",
|
||||
input: &pbs.ListScopesRequest{
|
||||
ScopeId: globals.GlobalPrefix,
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: org1.PublicId,
|
||||
GrantStrings: []string{"ids=*;type=scope;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: []string{
|
||||
proj1.PublicId,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tok := authtoken.TestAuthTokenWithRoles(t, conn, kmsCache, globals.GlobalPrefix, tc.rolesToCreate)
|
||||
fullGrantAuthCtx := auth.TestAuthContextFromToken(t, conn, wrap, tok, iamRepo)
|
||||
got, finalErr := s.ListScopes(fullGrantAuthCtx, tc.input)
|
||||
if tc.wantErr != nil {
|
||||
require.ErrorIs(t, finalErr, tc.wantErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, finalErr)
|
||||
var gotIDs []string
|
||||
for _, g := range got.Items {
|
||||
gotIDs = append(gotIDs, g.GetId())
|
||||
}
|
||||
require.ElementsMatch(t, tc.wantIDs, gotIDs)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1138,9 +1138,10 @@ func validateDestroyKeyVersionRequest(req *pbs.DestroyKeyVersionRequest) error {
|
||||
|
||||
func newOutputOpts(ctx context.Context, item *iam.Scope, authResults auth.VerifyResults, scopeInfoMap map[string]*pb.ScopeInfo) ([]handlers.Option, bool, error) {
|
||||
res := perms.Resource{
|
||||
Type: resource.Scope,
|
||||
Id: item.GetPublicId(),
|
||||
ScopeId: item.GetParentId(),
|
||||
Type: resource.Scope,
|
||||
Id: item.GetPublicId(),
|
||||
ScopeId: item.GetParentId(),
|
||||
ParentScopeId: scopeInfoMap[item.GetParentId()].GetParentScopeId(),
|
||||
}
|
||||
|
||||
authorizedActions := authResults.FetchActionSetForId(ctx, item.GetPublicId(), idActionsById(item.GetPublicId()), auth.WithResource(&res)).Strings()
|
||||
|
||||
@@ -1983,6 +1983,7 @@ func newOutputOpts(ctx context.Context, item target.Target, authResults auth.Ver
|
||||
if outputFields.Has(globals.ScopeField) {
|
||||
outputOpts = append(outputOpts, handlers.WithScope(authzScopes[item.GetProjectId()]))
|
||||
}
|
||||
pr.ParentScopeId = authzScopes[item.GetProjectId()].GetParentScopeId()
|
||||
if outputFields.Has(globals.AuthorizedActionsField) {
|
||||
authorizedActions := authResults.FetchActionSetForId(ctx, item.GetPublicId(), IdActions, auth.WithResource(&pr)).Strings()
|
||||
outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authorizedActions))
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package tcp_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/authtoken"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/target"
|
||||
"github.com/hashicorp/boundary/internal/target/tcp"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestGrants_ReadActions tests read actions to assert that grants are being applied properly
|
||||
//
|
||||
// Role - which scope the role is created in
|
||||
// - global level
|
||||
// Scopes [resource]:
|
||||
// - org1
|
||||
// - proj1
|
||||
// - proj2
|
||||
func TestGrants_ReadActions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrapper := db.TestWrapper(t)
|
||||
kms := kms.TestKms(t, conn, wrapper)
|
||||
iamRepo := iam.TestRepo(t, conn, wrapper)
|
||||
s, err := testService(t, ctx, conn, kms, wrapper)
|
||||
require.NoError(t, err)
|
||||
|
||||
org1, proj1 := iam.TestScopes(t, iamRepo)
|
||||
_, proj2 := iam.TestScopes(t, iamRepo)
|
||||
|
||||
target1 := tcp.TestTarget(ctx, t, conn, proj1.GetPublicId(), "test address-1", target.WithAddress("8.8.8.8"))
|
||||
target2 := tcp.TestTarget(ctx, t, conn, proj1.GetPublicId(), "test address-2", target.WithAddress("8.8.8.8"))
|
||||
target3 := tcp.TestTarget(ctx, t, conn, proj2.GetPublicId(), "test address-2", target.WithAddress("8.8.8.8"))
|
||||
|
||||
t.Run("List", func(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input *pbs.ListTargetsRequest
|
||||
rolesToCreate []authtoken.TestRoleGrantsForToken
|
||||
wantErr error
|
||||
wantIDs []string
|
||||
}{
|
||||
{
|
||||
name: "org role grant this returns all created targets",
|
||||
input: &pbs.ListTargetsRequest{
|
||||
ScopeId: globals.GlobalPrefix,
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: org1.GetPublicId(),
|
||||
GrantStrings: []string{"ids=*;type=target;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: []string{target1.GetPublicId(), target2.GetPublicId()},
|
||||
},
|
||||
{
|
||||
name: "project role grant this returns all created targets",
|
||||
input: &pbs.ListTargetsRequest{
|
||||
ScopeId: proj2.GetPublicId(),
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: proj2.GetPublicId(),
|
||||
GrantStrings: []string{"ids=*;type=target;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: []string{target3.GetPublicId()},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tok := authtoken.TestAuthTokenWithRoles(t, conn, kms, globals.GlobalPrefix, tc.rolesToCreate)
|
||||
fullGrantAuthCtx := auth.TestAuthContextFromToken(t, conn, wrapper, tok, iamRepo)
|
||||
got, finalErr := s.ListTargets(fullGrantAuthCtx, tc.input)
|
||||
if tc.wantErr != nil {
|
||||
require.ErrorIs(t, finalErr, tc.wantErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, finalErr)
|
||||
var gotIDs []string
|
||||
for _, g := range got.Items {
|
||||
gotIDs = append(gotIDs, g.GetId())
|
||||
}
|
||||
require.ElementsMatch(t, tc.wantIDs, gotIDs)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,312 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package users_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
talias "github.com/hashicorp/boundary/internal/alias/target"
|
||||
"github.com/hashicorp/boundary/internal/authtoken"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/users"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestGrants_ReadActions tests read actions to assert that grants are being applied properly
|
||||
//
|
||||
// Role - which scope the role is created in
|
||||
// - global level
|
||||
// - org level
|
||||
// Grant - what IAM grant scope is set for the permission
|
||||
// - global: descendant
|
||||
// - org: children
|
||||
// Scopes [resource]:
|
||||
// - global [globalUser]
|
||||
// - org1 [org1User]
|
||||
// - org1User1
|
||||
// - org2 [org2User]
|
||||
// - org2User1
|
||||
// - org2User2
|
||||
func TestGrants_ReadActions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
rw := db.New(conn)
|
||||
wrap := db.TestWrapper(t)
|
||||
iamRepo := iam.TestRepo(t, conn, wrap)
|
||||
kmsCache := kms.TestKms(t, conn, wrap)
|
||||
repoFn := func() (*iam.Repository, error) {
|
||||
return iamRepo, nil
|
||||
}
|
||||
aliasRepoFn := func() (*talias.Repository, error) {
|
||||
return talias.NewRepository(context.Background(), rw, rw, kmsCache)
|
||||
}
|
||||
s, err := users.NewService(ctx, repoFn, aliasRepoFn, 1000)
|
||||
require.NoError(t, err)
|
||||
org1, _ := iam.TestScopes(t, iamRepo)
|
||||
org2, _ := iam.TestScopes(t, iamRepo)
|
||||
|
||||
globalUser := iam.TestUser(t, iamRepo, globals.GlobalPrefix, iam.WithDescription("global"), iam.WithName("global"))
|
||||
org1User1 := iam.TestUser(t, iamRepo, org1.GetPublicId(), iam.WithDescription("org1"), iam.WithName("org1"))
|
||||
org2User1 := iam.TestUser(t, iamRepo, org2.GetPublicId(), iam.WithDescription("org2-1"), iam.WithName("org2-1"))
|
||||
org2User2 := iam.TestUser(t, iamRepo, org2.GetPublicId(), iam.WithDescription("org2-2"), iam.WithName("org2-2"))
|
||||
|
||||
t.Run("List", func(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input *pbs.ListUsersRequest
|
||||
// set this flag when the listing user has permission to list global
|
||||
// AND the test attempts to list users at global scope
|
||||
// users which gets created as a part of token generation
|
||||
includeTestUsers bool
|
||||
rolesToCreate []authtoken.TestRoleGrantsForToken
|
||||
wantErr error
|
||||
wantIDs []string
|
||||
}{
|
||||
{
|
||||
name: "global role grant this and children recursive list at global returns global and org users",
|
||||
input: &pbs.ListUsersRequest{
|
||||
ScopeId: globals.GlobalPrefix,
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=user;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
includeTestUsers: true,
|
||||
wantErr: nil,
|
||||
wantIDs: []string{
|
||||
globals.AnyAuthenticatedUserId,
|
||||
globals.AnonymousUserId,
|
||||
globals.RecoveryUserId,
|
||||
globalUser.PublicId,
|
||||
org1User1.PublicId,
|
||||
org2User1.PublicId,
|
||||
org2User2.PublicId,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "org role grant this and children recursive list at org returns org user",
|
||||
input: &pbs.ListUsersRequest{
|
||||
ScopeId: org2.PublicId,
|
||||
Recursive: true,
|
||||
},
|
||||
includeTestUsers: false,
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: org2.PublicId,
|
||||
GrantStrings: []string{"ids=*;type=user;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: []string{
|
||||
org2User1.PublicId,
|
||||
org2User2.PublicId,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "global role grant children recursive list at org returns org user",
|
||||
input: &pbs.ListUsersRequest{
|
||||
ScopeId: org2.PublicId,
|
||||
Recursive: true,
|
||||
},
|
||||
includeTestUsers: false,
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=user;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: []string{
|
||||
org2User1.PublicId,
|
||||
org2User2.PublicId,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "global role grant children recursive list at global returns all org users",
|
||||
input: &pbs.ListUsersRequest{
|
||||
ScopeId: globals.GlobalPrefix,
|
||||
Recursive: true,
|
||||
},
|
||||
includeTestUsers: false,
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=user;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: []string{
|
||||
org1User1.PublicId,
|
||||
org2User1.PublicId,
|
||||
org2User2.PublicId,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "org1 role grant this recursive list at global returns org1 users",
|
||||
input: &pbs.ListUsersRequest{
|
||||
ScopeId: globals.GlobalPrefix,
|
||||
Recursive: true,
|
||||
},
|
||||
includeTestUsers: false,
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: org1.PublicId,
|
||||
GrantStrings: []string{"ids=*;type=user;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: []string{
|
||||
org1User1.PublicId,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "individual org grant this recursive list at global returns org user",
|
||||
input: &pbs.ListUsersRequest{
|
||||
ScopeId: globals.GlobalPrefix,
|
||||
Recursive: true,
|
||||
},
|
||||
includeTestUsers: false,
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: org1.PublicId,
|
||||
GrantStrings: []string{"ids=*;type=user;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis},
|
||||
},
|
||||
{
|
||||
RoleScopeID: org2.PublicId,
|
||||
GrantStrings: []string{"ids=*;type=user;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: []string{
|
||||
org1User1.PublicId,
|
||||
org2User1.PublicId,
|
||||
org2User2.PublicId,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "global role grant this recursive list at org returns no user",
|
||||
input: &pbs.ListUsersRequest{
|
||||
ScopeId: org2.PublicId,
|
||||
Recursive: true,
|
||||
},
|
||||
includeTestUsers: false,
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=user;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: []string{},
|
||||
},
|
||||
{
|
||||
name: "global role grant this recursive list at global returns only global user",
|
||||
input: &pbs.ListUsersRequest{
|
||||
ScopeId: globals.GlobalPrefix,
|
||||
Recursive: true,
|
||||
},
|
||||
includeTestUsers: true,
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=user;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: []string{
|
||||
globals.AnyAuthenticatedUserId,
|
||||
globals.AnonymousUserId,
|
||||
globals.RecoveryUserId,
|
||||
globalUser.PublicId,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "global role grant children non-recursive list at global returns forbidden error",
|
||||
input: &pbs.ListUsersRequest{
|
||||
ScopeId: globals.GlobalPrefix,
|
||||
Recursive: false,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=user;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
wantErr: handlers.ForbiddenError(),
|
||||
wantIDs: nil,
|
||||
},
|
||||
{
|
||||
name: "org role grant children non-recursive list at global returns forbidden error",
|
||||
input: &pbs.ListUsersRequest{
|
||||
ScopeId: globals.GlobalPrefix,
|
||||
Recursive: false,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: org2.PublicId,
|
||||
GrantStrings: []string{"ids=*;type=user;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeChildren},
|
||||
},
|
||||
},
|
||||
wantErr: handlers.ForbiddenError(),
|
||||
wantIDs: nil,
|
||||
},
|
||||
{
|
||||
name: "no grant recursive list returns forbidden error",
|
||||
input: &pbs.ListUsersRequest{
|
||||
ScopeId: globals.GlobalPrefix,
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{},
|
||||
wantErr: handlers.ForbiddenError(),
|
||||
wantIDs: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tok := authtoken.TestAuthTokenWithRoles(t, conn, kmsCache, globals.GlobalPrefix, tc.rolesToCreate)
|
||||
t.Cleanup(func() {
|
||||
// deleting user to keep assertions clean since we're listing users over and over
|
||||
_, _ = iamRepo.DeleteUser(ctx, tok.IamUserId)
|
||||
})
|
||||
fullGrantAuthCtx := auth.TestAuthContextFromToken(t, conn, wrap, tok, iamRepo)
|
||||
got, finalErr := s.ListUsers(fullGrantAuthCtx, tc.input)
|
||||
if tc.wantErr != nil {
|
||||
require.ErrorIs(t, finalErr, tc.wantErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, finalErr)
|
||||
var gotIDs []string
|
||||
if tc.includeTestUsers {
|
||||
tc.wantIDs = append(tc.wantIDs, tok.IamUserId)
|
||||
}
|
||||
for _, g := range got.Items {
|
||||
gotIDs = append(gotIDs, g.GetId())
|
||||
}
|
||||
require.ElementsMatch(t, tc.wantIDs, gotIDs)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1067,6 +1067,7 @@ func newOutputOpts(ctx context.Context, item *iam.User, scopeInfoMap map[string]
|
||||
}
|
||||
res.Id = item.GetPublicId()
|
||||
res.ScopeId = item.GetScopeId()
|
||||
res.ParentScopeId = scopeInfoMap[item.GetScopeId()].GetParentScopeId()
|
||||
authorizedActions := authResults.FetchActionSetForId(ctx, item.GetPublicId(), IdActions, auth.WithResource(&res))
|
||||
if len(authorizedActions) == 0 {
|
||||
return nil, false
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package workers_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/authtoken"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/workers"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/server"
|
||||
"github.com/hashicorp/boundary/internal/types/scope"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc/codes"
|
||||
)
|
||||
|
||||
// TestGrants_ReadActions tests read actions to assert that grants are being applied properly
|
||||
//
|
||||
// Role - which scope the role is created in
|
||||
// - global level
|
||||
// Scopes [resource]:
|
||||
// - globalWorker1
|
||||
// - globalWorker2
|
||||
func TestGrants_ReadActions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrapper := db.TestWrapper(t)
|
||||
rw := db.New(conn)
|
||||
kms := kms.TestKms(t, conn, wrapper)
|
||||
iamRepo := iam.TestRepo(t, conn, wrapper)
|
||||
iamRepoFn := func() (*iam.Repository, error) {
|
||||
return iamRepo, nil
|
||||
}
|
||||
repoFn := func() (*server.Repository, error) {
|
||||
return server.NewRepository(ctx, rw, rw, kms)
|
||||
}
|
||||
|
||||
workerAuthRepo, err := server.NewRepositoryStorage(ctx, rw, rw, kms)
|
||||
require.NoError(t, err)
|
||||
workerAuthRepoFn := func() (*server.WorkerAuthRepositoryStorage, error) {
|
||||
return workerAuthRepo, nil
|
||||
}
|
||||
|
||||
s, err := workers.NewService(context.Background(), repoFn, iamRepoFn, workerAuthRepoFn, nil)
|
||||
require.NoError(t, err)
|
||||
globalWorker1 := server.TestPkiWorker(t, conn, wrapper,
|
||||
server.WithName("worker-1"),
|
||||
server.WithDescription("worker-1"),
|
||||
server.WithNewIdFunc(func(ctx context.Context) (string, error) {
|
||||
return server.NewWorkerIdFromScopeAndName(ctx, scope.Global.String(), "worker-1")
|
||||
}),
|
||||
)
|
||||
globalWorker2 := server.TestPkiWorker(t, conn, wrapper,
|
||||
server.WithName("worker-2"),
|
||||
server.WithDescription("worker-2"),
|
||||
server.WithNewIdFunc(func(ctx context.Context) (string, error) {
|
||||
return server.NewWorkerIdFromScopeAndName(ctx, scope.Global.String(), "worker-2")
|
||||
}),
|
||||
)
|
||||
t.Run("List", func(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input *pbs.ListWorkersRequest
|
||||
rolesToCreate []authtoken.TestRoleGrantsForToken
|
||||
wantErr error
|
||||
wantIDs []string
|
||||
}{
|
||||
{
|
||||
name: "global role grant this returns all created workers",
|
||||
input: &pbs.ListWorkersRequest{
|
||||
ScopeId: globals.GlobalPrefix,
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=worker;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis},
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
wantIDs: []string{globalWorker1.PublicId, globalWorker2.PublicId},
|
||||
},
|
||||
{
|
||||
name: "global role grant this with a non-applicable type throws an error",
|
||||
input: &pbs.ListWorkersRequest{
|
||||
ScopeId: globals.GlobalPrefix,
|
||||
Recursive: true,
|
||||
},
|
||||
rolesToCreate: []authtoken.TestRoleGrantsForToken{
|
||||
{
|
||||
RoleScopeID: globals.GlobalPrefix,
|
||||
GrantStrings: []string{"ids=*;type=group;actions=list,read"},
|
||||
GrantScopes: []string{globals.GrantScopeThis},
|
||||
},
|
||||
},
|
||||
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tok := authtoken.TestAuthTokenWithRoles(t, conn, kms, globals.GlobalPrefix, tc.rolesToCreate)
|
||||
fullGrantAuthCtx := auth.TestAuthContextFromToken(t, conn, wrapper, tok, iamRepo)
|
||||
got, finalErr := s.ListWorkers(fullGrantAuthCtx, tc.input)
|
||||
if tc.wantErr != nil {
|
||||
require.ErrorIs(t, finalErr, tc.wantErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, finalErr)
|
||||
var gotIDs []string
|
||||
for _, g := range got.Items {
|
||||
gotIDs = append(gotIDs, g.GetId())
|
||||
}
|
||||
require.ElementsMatch(t, tc.wantIDs, gotIDs)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -167,6 +167,7 @@ func (s Service) ListWorkers(ctx context.Context, req *pbs.ListWorkersRequest) (
|
||||
for _, item := range ul {
|
||||
res.Id = item.GetPublicId()
|
||||
res.ScopeId = item.GetScopeId()
|
||||
res.ParentScopeId = scopeInfoMap[item.GetScopeId()].GetParentScopeId()
|
||||
authorizedActions := authResults.FetchActionSetForId(ctx, item.GetPublicId(), IdActions, auth.WithResource(&res)).Strings()
|
||||
if len(authorizedActions) == 0 {
|
||||
continue
|
||||
|
||||
@@ -223,6 +223,36 @@ func TestRole(t testing.TB, conn *db.DB, scopeId string, opt ...Option) *Role {
|
||||
return role
|
||||
}
|
||||
|
||||
// TestRoleWithGrants creates a role suitable for testing along with grants
|
||||
// Functional options for GrantScopeIDs aren't used to express that
|
||||
// this function does not provide any default grant scope unlike TestRole
|
||||
func TestRoleWithGrants(t testing.TB, conn *db.DB, scopeId string, grantScopeIDs []string, grants []string) *Role {
|
||||
t.Helper()
|
||||
|
||||
ctx := context.Background()
|
||||
require := require.New(t)
|
||||
rw := db.New(conn)
|
||||
|
||||
role, err := NewRole(ctx, scopeId)
|
||||
require.NoError(err)
|
||||
id, err := newRoleId(ctx)
|
||||
require.NoError(err)
|
||||
role.PublicId = id
|
||||
require.NoError(rw.Create(ctx, role))
|
||||
require.NotEmpty(role.PublicId)
|
||||
|
||||
for _, gsi := range grantScopeIDs {
|
||||
gs, err := NewRoleGrantScope(ctx, id, gsi)
|
||||
require.NoError(err)
|
||||
require.NoError(rw.Create(ctx, gs))
|
||||
role.GrantScopes = append(role.GrantScopes, gs)
|
||||
}
|
||||
for _, g := range grants {
|
||||
_ = TestRoleGrant(t, conn, role.PublicId, g)
|
||||
}
|
||||
return role
|
||||
}
|
||||
|
||||
func TestRoleGrant(t testing.TB, conn *db.DB, roleId, grant string, opt ...Option) *RoleGrant {
|
||||
t.Helper()
|
||||
require := require.New(t)
|
||||
|
||||
Reference in new issue
Block a user