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

1886 lines
69 KiB

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package workers_test
import (
"context"
"fmt"
"testing"
"github.com/hashicorp/boundary/globals"
"github.com/hashicorp/boundary/internal/auth"
"github.com/hashicorp/boundary/internal/auth/ldap"
"github.com/hashicorp/boundary/internal/authtoken"
cauth "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"
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/workers"
"github.com/hashicorp/go-uuid"
"github.com/hashicorp/nodeenrollment/rotation"
"github.com/hashicorp/nodeenrollment/storage/file"
"github.com/hashicorp/nodeenrollment/types"
"github.com/mr-tron/base58"
"github.com/stretchr/testify/require"
"google.golang.org/genproto/protobuf/field_mask"
"google.golang.org/grpc/codes"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/structpb"
"google.golang.org/protobuf/types/known/wrapperspb"
)
func TestGrants_ListWorkers(t *testing.T) {
t.Parallel()
ctx := context.Background()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
rw := db.New(conn)
kmsCache := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
atRepo, err := authtoken.NewRepository(ctx, rw, rw, kmsCache)
require.NoError(t, err)
org, _ := iam.TestScopes(t, iamRepo)
iamRepoFn := func() (*iam.Repository, error) {
return iamRepo, nil
}
repoFn := func() (*server.Repository, error) {
return server.NewRepository(ctx, rw, rw, kmsCache)
}
workerAuthRepo, err := server.NewRepositoryStorage(ctx, rw, rw, kmsCache)
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.WithWorkerTags(&server.Tag{
Key: "worker",
Value: "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.WithWorkerTags(&server.Tag{
Key: "worker",
Value: "2",
}),
server.WithNewIdFunc(func(ctx context.Context) (string, error) {
return server.NewWorkerIdFromScopeAndName(ctx, scope.Global.String(), "worker-2")
}),
)
globalWorker3 := server.TestPkiWorker(t, conn, wrapper,
server.WithName("worker-3"),
server.WithDescription("worker-3"),
server.WithWorkerTags(&server.Tag{
Key: "worker",
Value: "3",
}),
server.WithNewIdFunc(func(ctx context.Context) (string, error) {
return server.NewWorkerIdFromScopeAndName(ctx, scope.Global.String(), "worker-3")
}),
)
testcases := []struct {
name string
input *pbs.ListWorkersRequest
userFunc func() (*iam.User, auth.Account)
wantErr error
wantIds []string
wantOutputFields []string
}{
{
name: "global role grant this returns all created workers",
input: &pbs.ListWorkersRequest{
ScopeId: globals.GlobalPrefix,
Recursive: true,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=worker;actions=list,read;output_fields=id,name,description,created_time,updated_time"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantErr: nil,
wantIds: []string{globalWorker1.PublicId, globalWorker2.PublicId, globalWorker3.PublicId},
wantOutputFields: []string{globals.IdField, globals.NameField, globals.DescriptionField, globals.CreatedTimeField, globals.UpdatedTimeField},
},
{
name: "global role grant this returns all created workers different output fields",
input: &pbs.ListWorkersRequest{
ScopeId: globals.GlobalPrefix,
Recursive: false,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=worker;actions=list,read;output_fields=id,version,canonical_tags,config_tags,authorized_actions,local_storage_state"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantErr: nil,
wantIds: []string{globalWorker1.PublicId, globalWorker2.PublicId, globalWorker3.PublicId},
wantOutputFields: []string{globals.IdField, globals.VersionField, globals.CanonicalTagsField, globals.ConfigTagsField, globals.AuthorizedActionsField, globals.LocalStorageStateField},
},
{
name: "global role grant this with a non-applicable type returns an error",
input: &pbs.ListWorkersRequest{
ScopeId: globals.GlobalPrefix,
Recursive: true,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=group;actions=list,read"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "global role grant descendants recursive list returns empty list",
input: &pbs.ListWorkersRequest{
ScopeId: globals.GlobalPrefix,
Recursive: true,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeDescendants},
},
}),
},
{
name: "global role grant descendants non-recursive list returns error",
input: &pbs.ListWorkersRequest{
ScopeId: globals.GlobalPrefix,
Recursive: false,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeDescendants},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "org role grant this and children recursive list returns empty list",
input: &pbs.ListWorkersRequest{
ScopeId: globals.GlobalPrefix,
Recursive: true,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: org.PublicId,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
},
}),
},
{
name: "org role grant this and children non-recursive list returns error",
input: &pbs.ListWorkersRequest{
ScopeId: globals.GlobalPrefix,
Recursive: false,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: org.PublicId,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
user, accountID := tc.userFunc()
tok, err := atRepo.CreateAuthToken(ctx, user, accountID.GetPublicId())
require.NoError(t, err)
fullGrantAuthCtx := cauth.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 _, item := range got.Items {
gotIds = append(gotIds, item.GetId())
handlers.TestAssertOutputFields(t, item, tc.wantOutputFields)
}
require.ElementsMatch(t, gotIds, tc.wantIds)
})
}
}
func TestGrants_GetWorker(t *testing.T) {
t.Parallel()
ctx := context.Background()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
rw := db.New(conn)
kmsCache := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
atRepo, err := authtoken.NewRepository(ctx, rw, rw, kmsCache)
require.NoError(t, err)
org, _ := iam.TestScopes(t, iamRepo)
iamRepoFn := func() (*iam.Repository, error) {
return iamRepo, nil
}
repoFn := func() (*server.Repository, error) {
return server.NewRepository(ctx, rw, rw, kmsCache)
}
workerAuthRepo, err := server.NewRepositoryStorage(ctx, rw, rw, kmsCache)
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.WithWorkerTags(&server.Tag{
Key: "key",
Value: "val",
}),
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.WithWorkerTags(&server.Tag{
Key: "key",
Value: "val",
}, &server.Tag{
Key: "another tag",
Value: "for output fields",
}),
server.WithNewIdFunc(func(ctx context.Context) (string, error) {
return server.NewWorkerIdFromScopeAndName(ctx, scope.Global.String(), "worker-2")
}),
)
testcases := []struct {
name string
input *pbs.GetWorkerRequest
userFunc func() (*iam.User, auth.Account)
wantErr error
wantOutputFields []string
}{
{
name: "global role grant read on all workers return success",
input: &pbs.GetWorkerRequest{
Id: globalWorker1.PublicId,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=worker;actions=read;output_fields=id,name,description,created_time,updated_time,authorized_actions"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantErr: nil,
wantOutputFields: []string{globals.IdField, globals.NameField, globals.DescriptionField, globals.AuthorizedActionsField, globals.CreatedTimeField, globals.UpdatedTimeField},
},
{
name: "global role grant this with specific ID success",
input: &pbs.GetWorkerRequest{
Id: globalWorker2.PublicId,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, org.PublicId, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{fmt.Sprintf("ids=%s;actions=read;output_fields=id,version,config_tags,type", globalWorker2.PublicId)},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantOutputFields: []string{globals.IdField, globals.VersionField, globals.ConfigTagsField, globals.TypeField},
wantErr: nil,
},
{
name: "global role grant allow different ID returns error",
input: &pbs.GetWorkerRequest{
Id: globalWorker1.PublicId,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, org.PublicId, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{fmt.Sprintf("ids=%s;actions=read", globalWorker2.PublicId)},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "global role grant different action returns error",
input: &pbs.GetWorkerRequest{
Id: globalWorker1.PublicId,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, org.PublicId, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=set-worker-tags"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "global role grant different resource returns error",
input: &pbs.GetWorkerRequest{
Id: globalWorker1.PublicId,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=group;actions=*"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "global role grant descendants resource returns error",
input: &pbs.GetWorkerRequest{
Id: globalWorker1.PublicId,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeDescendants},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
user, accountID := tc.userFunc()
tok, err := atRepo.CreateAuthToken(ctx, user, accountID.GetPublicId())
require.NoError(t, err)
fullGrantAuthCtx := cauth.TestAuthContextFromToken(t, conn, wrapper, tok, iamRepo)
got, finalErr := s.GetWorker(fullGrantAuthCtx, tc.input)
if tc.wantErr != nil {
require.ErrorIs(t, finalErr, tc.wantErr)
return
}
require.NoError(t, finalErr)
// validate that we're getting the right ID back
require.Equal(t, tc.input.Id, got.GetItem().GetId())
handlers.TestAssertOutputFields(t, got.GetItem(), tc.wantOutputFields)
})
}
}
func TestGrants_Delete(t *testing.T) {
t.Parallel()
ctx := context.Background()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
rw := db.New(conn)
kmsCache := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
atRepo, err := authtoken.NewRepository(ctx, rw, rw, kmsCache)
require.NoError(t, err)
iamRepoFn := func() (*iam.Repository, error) {
return iamRepo, nil
}
repoFn := func() (*server.Repository, error) {
return server.NewRepository(ctx, rw, rw, kmsCache)
}
workerAuthRepo, err := server.NewRepositoryStorage(ctx, rw, rw, kmsCache)
require.NoError(t, err)
workerAuthRepoFn := func() (*server.WorkerAuthRepositoryStorage, error) {
return workerAuthRepo, nil
}
// Store CA and check that initial version updates
_, err = rotation.RotateRootCertificates(ctx, workerAuthRepo)
require.NoError(t, err)
s, err := workers.NewService(context.Background(), repoFn, iamRepoFn, workerAuthRepoFn, nil)
require.NoError(t, err)
testcases := []struct {
name string
input func(w *server.Worker) *pbs.DeleteWorkerRequest
userFunc func(w *server.Worker) func() (*iam.User, auth.Account)
wantErr error
}{
{
name: "valid specific grants success",
input: func(w *server.Worker) *pbs.DeleteWorkerRequest {
return &pbs.DeleteWorkerRequest{
Id: w.PublicId,
}
},
userFunc: func(w *server.Worker) func() (*iam.User, auth.Account) {
return iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=worker;actions=delete"},
GrantScopes: []string{globals.GrantScopeThis},
},
})
},
},
{
name: "valid grants success",
input: func(w *server.Worker) *pbs.DeleteWorkerRequest {
return &pbs.DeleteWorkerRequest{
Id: w.PublicId,
}
},
userFunc: func(w *server.Worker) func() (*iam.User, auth.Account) {
return iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeThis},
},
})
},
},
{
name: "no actions grant returns error",
input: func(w *server.Worker) *pbs.DeleteWorkerRequest {
return &pbs.DeleteWorkerRequest{
Id: w.PublicId,
}
},
userFunc: func(w *server.Worker) func() (*iam.User, auth.Account) {
return iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=create,list,read-certificate-authority"},
GrantScopes: []string{globals.GrantScopeThis},
},
})
},
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "wrong scope grants returns error",
input: func(w *server.Worker) *pbs.DeleteWorkerRequest {
return &pbs.DeleteWorkerRequest{
Id: w.PublicId,
}
},
userFunc: func(w *server.Worker) func() (*iam.User, auth.Account) {
return iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeDescendants},
},
})
},
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "specific worker id succeed",
input: func(w *server.Worker) *pbs.DeleteWorkerRequest {
return &pbs.DeleteWorkerRequest{
Id: w.PublicId,
}
},
userFunc: func(w *server.Worker) func() (*iam.User, auth.Account) {
return iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{fmt.Sprintf("ids=%s;actions=*", w.PublicId)},
GrantScopes: []string{globals.GrantScopeThis},
},
})
},
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
workerId, err := uuid.GenerateUUID()
require.NoError(t, err)
worker := server.TestPkiWorker(t, conn, wrapper,
server.WithName(workerId),
server.WithDescription(workerId),
server.WithTestUseInputTagsAsApiTags(true),
server.WithNewIdFunc(func(ctx context.Context) (string, error) {
return server.NewWorkerIdFromScopeAndName(ctx, scope.Global.String(), workerId)
}),
)
user, accountID := tc.userFunc(worker)()
tok, err := atRepo.CreateAuthToken(ctx, user, accountID.GetPublicId())
require.NoError(t, err)
fullGrantAuthCtx := cauth.TestAuthContextFromToken(t, conn, wrapper, tok, iamRepo)
_, finalErr := s.DeleteWorker(fullGrantAuthCtx, tc.input(worker))
if tc.wantErr != nil {
require.ErrorIs(t, finalErr, tc.wantErr)
return
}
require.NoError(t, finalErr)
})
}
}
func TestGrants_Update(t *testing.T) {
t.Parallel()
ctx := context.Background()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
rw := db.New(conn)
kmsCache := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
atRepo, err := authtoken.NewRepository(ctx, rw, rw, kmsCache)
require.NoError(t, err)
iamRepoFn := func() (*iam.Repository, error) {
return iamRepo, nil
}
repoFn := func() (*server.Repository, error) {
return server.NewRepository(ctx, rw, rw, kmsCache)
}
org, proj := iam.TestScopes(t, iamRepo)
workerAuthRepo, err := server.NewRepositoryStorage(ctx, rw, rw, kmsCache)
require.NoError(t, err)
workerAuthRepoFn := func() (*server.WorkerAuthRepositoryStorage, error) {
return workerAuthRepo, nil
}
// Store CA and check that initial version updates
_, err = rotation.RotateRootCertificates(ctx, workerAuthRepo)
require.NoError(t, err)
s, err := workers.NewService(context.Background(), repoFn, iamRepoFn, workerAuthRepoFn, nil)
require.NoError(t, err)
testcases := []struct {
name string
input func(w *server.Worker) *pbs.UpdateWorkerRequest
userFunc func(w *server.Worker) func() (*iam.User, auth.Account)
wantErr error
wantOutputFields []string
}{
{
name: "valid specific grants success",
input: func(w *server.Worker) *pbs.UpdateWorkerRequest {
description, err := uuid.GenerateUUID()
require.NoError(t, err)
return &pbs.UpdateWorkerRequest{
Id: w.PublicId,
Item: &pb.Worker{
Version: w.Version,
Description: wrapperspb.String(description),
},
UpdateMask: &field_mask.FieldMask{Paths: []string{"description"}},
}
},
userFunc: func(w *server.Worker) func() (*iam.User, auth.Account) {
return iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=worker;actions=update;output_fields=id,version,scope_id,name,description,config_tags"},
GrantScopes: []string{globals.GrantScopeThis},
},
})
},
wantOutputFields: []string{globals.IdField, globals.VersionField, globals.ScopeIdField, globals.NameField, globals.DescriptionField, globals.ConfigTagsField},
},
{
name: "valid grants success",
input: func(w *server.Worker) *pbs.UpdateWorkerRequest {
description, err := uuid.GenerateUUID()
require.NoError(t, err)
return &pbs.UpdateWorkerRequest{
Id: w.PublicId,
Item: &pb.Worker{
Version: w.Version,
Description: wrapperspb.String(description),
},
UpdateMask: &field_mask.FieldMask{Paths: []string{"description"}},
}
},
userFunc: func(w *server.Worker) func() (*iam.User, auth.Account) {
return iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=*;output_fields=id,version,type,authorized_actions"},
GrantScopes: []string{globals.GrantScopeThis},
},
})
},
wantOutputFields: []string{globals.IdField, globals.VersionField, globals.TypeField, globals.AuthorizedActionsField},
},
{
name: "no actions grant returns error",
input: func(w *server.Worker) *pbs.UpdateWorkerRequest {
description, err := uuid.GenerateUUID()
require.NoError(t, err)
return &pbs.UpdateWorkerRequest{
Id: w.PublicId,
Item: &pb.Worker{
Version: w.Version,
Description: wrapperspb.String(description),
},
UpdateMask: &field_mask.FieldMask{Paths: []string{"description"}},
}
},
userFunc: func(w *server.Worker) func() (*iam.User, auth.Account) {
return iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=create,list,delete,read"},
GrantScopes: []string{globals.GrantScopeThis},
},
})
},
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "wrong scope grants returns error",
input: func(w *server.Worker) *pbs.UpdateWorkerRequest {
description, err := uuid.GenerateUUID()
require.NoError(t, err)
return &pbs.UpdateWorkerRequest{
Id: w.PublicId,
Item: &pb.Worker{
Version: w.Version,
Description: wrapperspb.String(description),
},
UpdateMask: &field_mask.FieldMask{Paths: []string{"description"}},
}
},
userFunc: func(w *server.Worker) func() (*iam.User, auth.Account) {
return iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeDescendants},
},
})
},
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "org role scope grants this returns error",
input: func(w *server.Worker) *pbs.UpdateWorkerRequest {
description, err := uuid.GenerateUUID()
require.NoError(t, err)
return &pbs.UpdateWorkerRequest{
Id: w.PublicId,
Item: &pb.Worker{
Version: w.Version,
Description: wrapperspb.String(description),
},
UpdateMask: &field_mask.FieldMask{Paths: []string{"description"}},
}
},
userFunc: func(w *server.Worker) func() (*iam.User, auth.Account) {
return iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: org.PublicId,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeThis},
},
})
},
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "proj role scope grants this returns error",
input: func(w *server.Worker) *pbs.UpdateWorkerRequest {
description, err := uuid.GenerateUUID()
require.NoError(t, err)
return &pbs.UpdateWorkerRequest{
Id: w.PublicId,
Item: &pb.Worker{
Version: w.Version,
Description: wrapperspb.String(description),
},
UpdateMask: &field_mask.FieldMask{Paths: []string{"description"}},
}
},
userFunc: func(w *server.Worker) func() (*iam.User, auth.Account) {
return iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: proj.PublicId,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeThis},
},
})
},
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "specific worker id succeed",
input: func(w *server.Worker) *pbs.UpdateWorkerRequest {
description, err := uuid.GenerateUUID()
require.NoError(t, err)
return &pbs.UpdateWorkerRequest{
Id: w.PublicId,
Item: &pb.Worker{
Version: w.Version,
Description: wrapperspb.String(description),
},
UpdateMask: &field_mask.FieldMask{Paths: []string{"description"}},
}
},
userFunc: func(w *server.Worker) func() (*iam.User, auth.Account) {
return iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{fmt.Sprintf("ids=%s;actions=*;output_fields=id,version,description,scope_id,config_tags,authorized_actions", w.PublicId)},
GrantScopes: []string{globals.GrantScopeThis},
},
})
},
wantOutputFields: []string{globals.IdField, globals.VersionField, globals.ScopeIdField, globals.DescriptionField, globals.ConfigTagsField, globals.AuthorizedActionsField},
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
workerId, err := uuid.GenerateUUID()
require.NoError(t, err)
worker := server.TestPkiWorker(t, conn, wrapper,
server.WithName(workerId),
server.WithDescription(workerId),
server.WithWorkerTags(&server.Tag{
Key: workerId,
Value: workerId,
}, &server.Tag{
Key: "another tag",
Value: "for output fields",
}))
user, accountID := tc.userFunc(worker)()
tok, err := atRepo.CreateAuthToken(ctx, user, accountID.GetPublicId())
require.NoError(t, err)
fullGrantAuthCtx := cauth.TestAuthContextFromToken(t, conn, wrapper, tok, iamRepo)
got, finalErr := s.UpdateWorker(fullGrantAuthCtx, tc.input(worker))
if tc.wantErr != nil {
require.ErrorIs(t, finalErr, tc.wantErr)
return
}
require.NoError(t, finalErr)
handlers.TestAssertOutputFields(t, got.Item, tc.wantOutputFields)
})
}
}
func TestGrants_CreateWorkerLed(t *testing.T) {
t.Parallel()
ctx := context.Background()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
rw := db.New(conn)
kmsCache := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
atRepo, err := authtoken.NewRepository(ctx, rw, rw, kmsCache)
require.NoError(t, err)
iamRepoFn := func() (*iam.Repository, error) {
return iamRepo, nil
}
repoFn := func() (*server.Repository, error) {
return server.NewRepository(ctx, rw, rw, kmsCache)
}
workerAuthRepo, err := server.NewRepositoryStorage(ctx, rw, rw, kmsCache)
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)
org, proj := iam.TestScopes(t, iamRepo)
// Get an initial set of authorized node credentials
rootStorage, err := server.NewRepositoryStorage(ctx, rw, rw, kmsCache)
require.NoError(t, err)
_, err = rotation.RotateRootCertificates(ctx, rootStorage)
require.NoError(t, err)
fetchReqFn := func() string {
// This happens on the worker
fileStorage, err := file.New(ctx)
require.NoError(t, err)
defer func() { _ = fileStorage.Cleanup(ctx) }()
nodeCreds, err := types.NewNodeCredentials(ctx, fileStorage)
require.NoError(t, err)
// Create request using worker id
fetchReq, err := nodeCreds.CreateFetchNodeCredentialsRequest(ctx)
require.NoError(t, err)
fetchEncoded, err := proto.Marshal(fetchReq)
require.NoError(t, err)
return base58.Encode(fetchEncoded)
}
testcases := []struct {
name string
input *pbs.CreateWorkerLedRequest
userFunc func() (*iam.User, auth.Account)
wantErr error
}{
{
name: "valid grants success",
input: &pbs.CreateWorkerLedRequest{Item: &pb.Worker{
ScopeId: scope.Global.String(),
WorkerGeneratedAuthToken: &wrapperspb.StringValue{Value: fetchReqFn()},
}},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
},
{
name: "specific valid grants success",
input: &pbs.CreateWorkerLedRequest{Item: &pb.Worker{
ScopeId: scope.Global.String(),
WorkerGeneratedAuthToken: &wrapperspb.StringValue{Value: fetchReqFn()},
}},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=worker;actions=create"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
},
{
name: "no create actions grant returns error",
input: &pbs.CreateWorkerLedRequest{Item: &pb.Worker{
ScopeId: scope.Global.String(),
WorkerGeneratedAuthToken: &wrapperspb.StringValue{Value: fetchReqFn()},
}},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=list,read,no-op,set-worker-tags"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "no worker type grant returns error",
input: &pbs.CreateWorkerLedRequest{Item: &pb.Worker{
ScopeId: scope.Global.String(),
WorkerGeneratedAuthToken: &wrapperspb.StringValue{Value: fetchReqFn()},
}},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{
"ids=*;type=scope;actions=create",
"ids=*;type=session;actions=create",
"ids=*;type=user;actions=create",
"ids=*;type=group;actions=create",
"ids=*;type=role;actions=create",
"ids=*;type=auth-token;actions=create",
},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "no worker type grant returns error",
input: &pbs.CreateWorkerLedRequest{Item: &pb.Worker{
ScopeId: scope.Global.String(),
WorkerGeneratedAuthToken: &wrapperspb.StringValue{Value: fetchReqFn()},
}},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeDescendants},
},
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeChildren},
},
{
RoleScopeId: org.PublicId,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
},
{
RoleScopeId: proj.PublicId,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
user, accountID := tc.userFunc()
tok, err := atRepo.CreateAuthToken(ctx, user, accountID.GetPublicId())
require.NoError(t, err)
fullGrantAuthCtx := cauth.TestAuthContextFromToken(t, conn, wrapper, tok, iamRepo)
_, finalErr := s.CreateWorkerLed(fullGrantAuthCtx, tc.input)
if tc.wantErr != nil {
require.ErrorIs(t, finalErr, tc.wantErr)
return
}
require.NoError(t, finalErr)
})
}
}
func TestGrants_CreateControllerLed(t *testing.T) {
t.Parallel()
ctx := context.Background()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
rw := db.New(conn)
kmsCache := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
atRepo, err := authtoken.NewRepository(ctx, rw, rw, kmsCache)
require.NoError(t, err)
iamRepoFn := func() (*iam.Repository, error) {
return iamRepo, nil
}
repoFn := func() (*server.Repository, error) {
return server.NewRepository(ctx, rw, rw, kmsCache)
}
workerAuthRepo, err := server.NewRepositoryStorage(ctx, rw, rw, kmsCache)
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)
org, proj := iam.TestScopes(t, iamRepo)
ider := func() string {
id, _ := uuid.GenerateUUID()
return id
}
testcases := []struct {
name string
input *pbs.CreateControllerLedRequest
userFunc func() (*iam.User, auth.Account)
wantErr error
}{
{
name: "valid grants success",
input: &pbs.CreateControllerLedRequest{Item: &pb.Worker{
ScopeId: scope.Global.String(),
Name: &wrapperspb.StringValue{Value: ider()},
}},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
},
{
name: "specific valid grants success",
input: &pbs.CreateControllerLedRequest{Item: &pb.Worker{
ScopeId: scope.Global.String(),
Name: &wrapperspb.StringValue{Value: ider()},
}},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=worker;actions=create"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
},
{
name: "no create actions grant returns error",
input: &pbs.CreateControllerLedRequest{Item: &pb.Worker{
ScopeId: scope.Global.String(),
Name: &wrapperspb.StringValue{Value: ider()},
}},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=list,read,no-op,set-worker-tags"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "no worker type grant returns error",
input: &pbs.CreateControllerLedRequest{Item: &pb.Worker{
ScopeId: scope.Global.String(),
Name: &wrapperspb.StringValue{Value: ider()},
}},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{
"ids=*;type=scope;actions=create",
"ids=*;type=session;actions=create",
"ids=*;type=user;actions=create",
"ids=*;type=group;actions=create",
"ids=*;type=role;actions=create",
"ids=*;type=auth-token;actions=create",
},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "no worker type grant returns error",
input: &pbs.CreateControllerLedRequest{Item: &pb.Worker{
ScopeId: scope.Global.String(),
Name: &wrapperspb.StringValue{Value: ider()},
}},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeDescendants},
},
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeChildren},
},
{
RoleScopeId: org.PublicId,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeThis, globals.GrantScopeChildren},
},
{
RoleScopeId: proj.PublicId,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
user, accountID := tc.userFunc()
tok, err := atRepo.CreateAuthToken(ctx, user, accountID.GetPublicId())
require.NoError(t, err)
fullGrantAuthCtx := cauth.TestAuthContextFromToken(t, conn, wrapper, tok, iamRepo)
_, finalErr := s.CreateControllerLed(fullGrantAuthCtx, tc.input)
if tc.wantErr != nil {
require.ErrorIs(t, finalErr, tc.wantErr)
return
}
require.NoError(t, finalErr)
})
}
}
func TestGrants_ReadCertificateAuthority(t *testing.T) {
t.Parallel()
ctx := context.Background()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
rw := db.New(conn)
kmsCache := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
atRepo, err := authtoken.NewRepository(ctx, rw, rw, kmsCache)
require.NoError(t, err)
iamRepoFn := func() (*iam.Repository, error) {
return iamRepo, nil
}
repoFn := func() (*server.Repository, error) {
return server.NewRepository(ctx, rw, rw, kmsCache)
}
workerAuthRepo, err := server.NewRepositoryStorage(ctx, rw, rw, kmsCache)
require.NoError(t, err)
workerAuthRepoFn := func() (*server.WorkerAuthRepositoryStorage, error) {
return workerAuthRepo, nil
}
// Store CA and check that initial version updates
_, err = rotation.RotateRootCertificates(ctx, workerAuthRepo)
require.NoError(t, err)
s, err := workers.NewService(context.Background(), repoFn, iamRepoFn, workerAuthRepoFn, nil)
require.NoError(t, err)
org, proj := iam.TestScopes(t, iamRepo)
testcases := []struct {
name string
input *pbs.ReadCertificateAuthorityRequest
userFunc func() (*iam.User, auth.Account)
wantErr error
}{
{
name: "valid specific grants success",
input: &pbs.ReadCertificateAuthorityRequest{
ScopeId: globals.GlobalPrefix,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=worker;actions=read-certificate-authority"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
},
{
name: "valid grants success",
input: &pbs.ReadCertificateAuthorityRequest{
ScopeId: globals.GlobalPrefix,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=worker;actions=*"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
},
{
name: "no actions grant returns error",
input: &pbs.ReadCertificateAuthorityRequest{
ScopeId: globals.GlobalPrefix,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=list,read,no-op,set-worker-tags"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "org role scope grant this returns error",
input: &pbs.ReadCertificateAuthorityRequest{
ScopeId: globals.GlobalPrefix,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: org.PublicId,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "proj role scope grant this returns error",
input: &pbs.ReadCertificateAuthorityRequest{
ScopeId: globals.GlobalPrefix,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: proj.PublicId,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "wrong scope grants returns error",
input: &pbs.ReadCertificateAuthorityRequest{
ScopeId: globals.GlobalPrefix,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeDescendants},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
user, accountID := tc.userFunc()
tok, err := atRepo.CreateAuthToken(ctx, user, accountID.GetPublicId())
require.NoError(t, err)
fullGrantAuthCtx := cauth.TestAuthContextFromToken(t, conn, wrapper, tok, iamRepo)
_, finalErr := s.ReadCertificateAuthority(fullGrantAuthCtx, tc.input)
if tc.wantErr != nil {
require.ErrorIs(t, finalErr, tc.wantErr)
return
}
require.NoError(t, finalErr)
})
}
}
func TestGrants_ReinitializeCertificateAuthority(t *testing.T) {
t.Parallel()
ctx := context.Background()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
rw := db.New(conn)
kmsCache := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
atRepo, err := authtoken.NewRepository(ctx, rw, rw, kmsCache)
require.NoError(t, err)
iamRepoFn := func() (*iam.Repository, error) {
return iamRepo, nil
}
repoFn := func() (*server.Repository, error) {
return server.NewRepository(ctx, rw, rw, kmsCache)
}
workerAuthRepo, err := server.NewRepositoryStorage(ctx, rw, rw, kmsCache)
require.NoError(t, err)
workerAuthRepoFn := func() (*server.WorkerAuthRepositoryStorage, error) {
return workerAuthRepo, nil
}
// Store CA and check that initial version updates
_, err = rotation.RotateRootCertificates(ctx, workerAuthRepo)
require.NoError(t, err)
s, err := workers.NewService(context.Background(), repoFn, iamRepoFn, workerAuthRepoFn, nil)
require.NoError(t, err)
org, proj := iam.TestScopes(t, iamRepo)
testcases := []struct {
name string
input *pbs.ReinitializeCertificateAuthorityRequest
userFunc func() (*iam.User, auth.Account)
wantErr error
}{
{
name: "valid specific grants success",
input: &pbs.ReinitializeCertificateAuthorityRequest{
ScopeId: globals.GlobalPrefix,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=worker;actions=reinitialize-certificate-authority"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
},
{
name: "valid grants success",
input: &pbs.ReinitializeCertificateAuthorityRequest{
ScopeId: globals.GlobalPrefix,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=worker;actions=*"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
},
{
name: "no actions grant returns error",
input: &pbs.ReinitializeCertificateAuthorityRequest{
ScopeId: globals.GlobalPrefix,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=create,list,read-certificate-authority"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "org role scope grant this returns error",
input: &pbs.ReinitializeCertificateAuthorityRequest{
ScopeId: globals.GlobalPrefix,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: org.PublicId,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "proj role scope grant this returns error",
input: &pbs.ReinitializeCertificateAuthorityRequest{
ScopeId: globals.GlobalPrefix,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: proj.PublicId,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "wrong scope grants returns error",
input: &pbs.ReinitializeCertificateAuthorityRequest{
ScopeId: globals.GlobalPrefix,
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeDescendants},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
user, accountID := tc.userFunc()
tok, err := atRepo.CreateAuthToken(ctx, user, accountID.GetPublicId())
require.NoError(t, err)
fullGrantAuthCtx := cauth.TestAuthContextFromToken(t, conn, wrapper, tok, iamRepo)
_, finalErr := s.ReinitializeCertificateAuthority(fullGrantAuthCtx, tc.input)
if tc.wantErr != nil {
require.ErrorIs(t, finalErr, tc.wantErr)
return
}
require.NoError(t, finalErr)
})
}
}
func TestGrants_AddWorkerTags(t *testing.T) {
t.Parallel()
ctx := context.Background()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
rw := db.New(conn)
kmsCache := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
atRepo, err := authtoken.NewRepository(ctx, rw, rw, kmsCache)
require.NoError(t, err)
iamRepoFn := func() (*iam.Repository, error) {
return iamRepo, nil
}
repoFn := func() (*server.Repository, error) {
return server.NewRepository(ctx, rw, rw, kmsCache)
}
workerAuthRepo, err := server.NewRepositoryStorage(ctx, rw, rw, kmsCache)
require.NoError(t, err)
workerAuthRepoFn := func() (*server.WorkerAuthRepositoryStorage, error) {
return workerAuthRepo, nil
}
// Store CA and check that initial version updates
_, err = rotation.RotateRootCertificates(ctx, workerAuthRepo)
require.NoError(t, err)
s, err := workers.NewService(context.Background(), repoFn, iamRepoFn, workerAuthRepoFn, nil)
require.NoError(t, err)
worker := server.TestPkiWorker(t, conn, wrapper,
server.WithName("worker-1"),
server.WithDescription("worker-1"),
server.WithWorkerTags(&server.Tag{
Key: "worker",
Value: "1",
}),
server.WithNewIdFunc(func(ctx context.Context) (string, error) {
return server.NewWorkerIdFromScopeAndName(ctx, scope.Global.String(), "worker-1")
}),
)
testcases := []struct {
name string
input func() *pbs.AddWorkerTagsRequest
userFunc func() (*iam.User, auth.Account)
wantErr error
wantOutputFields []string
}{
{
name: "valid specific grants success",
input: func() *pbs.AddWorkerTagsRequest {
randomTag, _ := uuid.GenerateUUID()
return &pbs.AddWorkerTagsRequest{
Id: worker.PublicId,
Version: worker.Version,
ApiTags: map[string]*structpb.ListValue{
randomTag: {Values: []*structpb.Value{structpb.NewStringValue(randomTag)}},
},
}
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=worker;actions=add-worker-tags;output_fields=id,version,scope_id,name,description"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantOutputFields: []string{globals.IdField, globals.VersionField, globals.ScopeIdField, globals.NameField, globals.DescriptionField},
},
{
name: "valid grants success",
input: func() *pbs.AddWorkerTagsRequest {
randomTag, _ := uuid.GenerateUUID()
return &pbs.AddWorkerTagsRequest{
Id: worker.PublicId,
Version: worker.Version,
ApiTags: map[string]*structpb.ListValue{
randomTag: {Values: []*structpb.Value{structpb.NewStringValue(randomTag)}},
},
}
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=worker;actions=*;output_fields=id,version,type,api_tags,authorized_actions"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantOutputFields: []string{globals.IdField, globals.VersionField, globals.TypeField, globals.ApiTagsField, globals.AuthorizedActionsField},
},
{
name: "specific id valid grants success",
input: func() *pbs.AddWorkerTagsRequest {
randomTag, _ := uuid.GenerateUUID()
return &pbs.AddWorkerTagsRequest{
Id: worker.PublicId,
Version: worker.Version,
ApiTags: map[string]*structpb.ListValue{
randomTag: {Values: []*structpb.Value{structpb.NewStringValue(randomTag)}},
},
}
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{fmt.Sprintf("ids=%s;actions=add-worker-tags;output_fields=id,version,scope_id,config_tags,api_tags,authorized_actions", worker.PublicId)},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantOutputFields: []string{globals.IdField, globals.VersionField, globals.ScopeIdField, globals.ConfigTagsField, globals.ApiTagsField, globals.AuthorizedActionsField},
},
{
name: "no actions grant returns error",
input: func() *pbs.AddWorkerTagsRequest {
randomTag, _ := uuid.GenerateUUID()
return &pbs.AddWorkerTagsRequest{
Id: worker.PublicId,
Version: worker.Version,
ApiTags: map[string]*structpb.ListValue{
randomTag: {Values: []*structpb.Value{structpb.NewStringValue(randomTag)}},
},
}
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=create,list,read-certificate-authority"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "wrong scope grants returns error",
input: func() *pbs.AddWorkerTagsRequest {
randomTag, _ := uuid.GenerateUUID()
return &pbs.AddWorkerTagsRequest{
Id: worker.PublicId,
Version: worker.Version,
ApiTags: map[string]*structpb.ListValue{
randomTag: {Values: []*structpb.Value{structpb.NewStringValue(randomTag)}},
},
}
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeDescendants},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
user, accountID := tc.userFunc()
tok, err := atRepo.CreateAuthToken(ctx, user, accountID.GetPublicId())
require.NoError(t, err)
fullGrantAuthCtx := cauth.TestAuthContextFromToken(t, conn, wrapper, tok, iamRepo)
out, finalErr := s.AddWorkerTags(fullGrantAuthCtx, tc.input())
if tc.wantErr != nil {
require.ErrorIs(t, finalErr, tc.wantErr)
return
}
worker.Version = out.Item.Version
require.NoError(t, finalErr)
handlers.TestAssertOutputFields(t, out.Item, tc.wantOutputFields)
})
}
}
func TestGrants_SetWorkerTags(t *testing.T) {
t.Parallel()
ctx := context.Background()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
rw := db.New(conn)
kmsCache := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
atRepo, err := authtoken.NewRepository(ctx, rw, rw, kmsCache)
require.NoError(t, err)
iamRepoFn := func() (*iam.Repository, error) {
return iamRepo, nil
}
repoFn := func() (*server.Repository, error) {
return server.NewRepository(ctx, rw, rw, kmsCache)
}
workerAuthRepo, err := server.NewRepositoryStorage(ctx, rw, rw, kmsCache)
require.NoError(t, err)
workerAuthRepoFn := func() (*server.WorkerAuthRepositoryStorage, error) {
return workerAuthRepo, nil
}
// Store CA and check that initial version updates
_, err = rotation.RotateRootCertificates(ctx, workerAuthRepo)
require.NoError(t, err)
s, err := workers.NewService(context.Background(), repoFn, iamRepoFn, workerAuthRepoFn, nil)
require.NoError(t, err)
worker := server.TestPkiWorker(t, conn, wrapper,
server.WithName("worker-1"),
server.WithDescription("worker-1"),
server.WithWorkerTags(&server.Tag{
Key: "worker",
Value: "1",
}),
server.WithNewIdFunc(func(ctx context.Context) (string, error) {
return server.NewWorkerIdFromScopeAndName(ctx, scope.Global.String(), "worker-1")
}),
)
testcases := []struct {
name string
input func() *pbs.SetWorkerTagsRequest
userFunc func() (*iam.User, auth.Account)
wantErr error
wantOutputFields []string
}{
{
name: "valid specific grants success",
input: func() *pbs.SetWorkerTagsRequest {
randomTag, _ := uuid.GenerateUUID()
return &pbs.SetWorkerTagsRequest{
Id: worker.PublicId,
Version: worker.Version,
ApiTags: map[string]*structpb.ListValue{
randomTag: {Values: []*structpb.Value{structpb.NewStringValue(randomTag)}},
},
}
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=worker;actions=set-worker-tags;output_fields=id,version,scope_id,name,description"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantOutputFields: []string{globals.IdField, globals.VersionField, globals.ScopeIdField, globals.NameField, globals.DescriptionField},
},
{
name: "valid grants success",
input: func() *pbs.SetWorkerTagsRequest {
randomTag, _ := uuid.GenerateUUID()
return &pbs.SetWorkerTagsRequest{
Id: worker.PublicId,
Version: worker.Version,
ApiTags: map[string]*structpb.ListValue{
randomTag: {Values: []*structpb.Value{structpb.NewStringValue(randomTag)}},
},
}
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=worker;actions=*;output_fields=id,version,type,api_tags,authorized_actions"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantOutputFields: []string{globals.IdField, globals.VersionField, globals.TypeField, globals.ApiTagsField, globals.AuthorizedActionsField},
},
{
name: "specific id valid grants success",
input: func() *pbs.SetWorkerTagsRequest {
randomTag, _ := uuid.GenerateUUID()
return &pbs.SetWorkerTagsRequest{
Id: worker.PublicId,
Version: worker.Version,
ApiTags: map[string]*structpb.ListValue{
randomTag: {Values: []*structpb.Value{structpb.NewStringValue(randomTag)}},
},
}
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{fmt.Sprintf("ids=%s;actions=set-worker-tags;output_fields=id,version,scope_id,config_tags,api_tags,authorized_actions", worker.PublicId)},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantOutputFields: []string{globals.IdField, globals.VersionField, globals.ScopeIdField, globals.ConfigTagsField, globals.ApiTagsField, globals.AuthorizedActionsField},
},
{
name: "no actions grant returns error",
input: func() *pbs.SetWorkerTagsRequest {
randomTag, _ := uuid.GenerateUUID()
return &pbs.SetWorkerTagsRequest{
Id: worker.PublicId,
Version: worker.Version,
ApiTags: map[string]*structpb.ListValue{
randomTag: {Values: []*structpb.Value{structpb.NewStringValue(randomTag)}},
},
}
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=create,list,read-certificate-authority"},
GrantScopes: []string{globals.GrantScopeThis},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "wrong scope grants returns error",
input: func() *pbs.SetWorkerTagsRequest {
randomTag, _ := uuid.GenerateUUID()
return &pbs.SetWorkerTagsRequest{
Id: worker.PublicId,
Version: worker.Version,
ApiTags: map[string]*structpb.ListValue{
randomTag: {Values: []*structpb.Value{structpb.NewStringValue(randomTag)}},
},
}
},
userFunc: iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeDescendants},
},
}),
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
user, accountID := tc.userFunc()
tok, err := atRepo.CreateAuthToken(ctx, user, accountID.GetPublicId())
require.NoError(t, err)
fullGrantAuthCtx := cauth.TestAuthContextFromToken(t, conn, wrapper, tok, iamRepo)
out, finalErr := s.SetWorkerTags(fullGrantAuthCtx, tc.input())
if tc.wantErr != nil {
require.ErrorIs(t, finalErr, tc.wantErr)
return
}
worker.Version = out.Item.Version
require.NoError(t, finalErr)
handlers.TestAssertOutputFields(t, out.Item, tc.wantOutputFields)
})
}
}
func TestGrants_RemoveWorkerTags(t *testing.T) {
t.Parallel()
ctx := context.Background()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
rw := db.New(conn)
kmsCache := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
atRepo, err := authtoken.NewRepository(ctx, rw, rw, kmsCache)
require.NoError(t, err)
iamRepoFn := func() (*iam.Repository, error) {
return iamRepo, nil
}
repoFn := func() (*server.Repository, error) {
return server.NewRepository(ctx, rw, rw, kmsCache)
}
workerAuthRepo, err := server.NewRepositoryStorage(ctx, rw, rw, kmsCache)
require.NoError(t, err)
workerAuthRepoFn := func() (*server.WorkerAuthRepositoryStorage, error) {
return workerAuthRepo, nil
}
// Store CA and check that initial version updates
_, err = rotation.RotateRootCertificates(ctx, workerAuthRepo)
require.NoError(t, err)
s, err := workers.NewService(context.Background(), repoFn, iamRepoFn, workerAuthRepoFn, nil)
require.NoError(t, err)
testcases := []struct {
name string
input func(w *server.Worker) *pbs.RemoveWorkerTagsRequest
userFunc func(w *server.Worker) func() (*iam.User, auth.Account)
wantErr error
wantOutputFields []string
}{
{
name: "valid specific grants success",
input: func(w *server.Worker) *pbs.RemoveWorkerTagsRequest {
return &pbs.RemoveWorkerTagsRequest{
Id: w.PublicId,
Version: w.Version,
ApiTags: map[string]*structpb.ListValue{
w.Name: {Values: []*structpb.Value{structpb.NewStringValue(w.Name)}},
},
}
},
userFunc: func(w *server.Worker) func() (*iam.User, auth.Account) {
return iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=worker;actions=remove-worker-tags;output_fields=id,version,scope_id,name,description"},
GrantScopes: []string{globals.GrantScopeThis},
},
})
},
wantOutputFields: []string{globals.IdField, globals.VersionField, globals.ScopeIdField, globals.NameField, globals.DescriptionField},
},
{
name: "valid grants success",
input: func(w *server.Worker) *pbs.RemoveWorkerTagsRequest {
return &pbs.RemoveWorkerTagsRequest{
Id: w.PublicId,
Version: w.Version,
ApiTags: map[string]*structpb.ListValue{
w.Name: {Values: []*structpb.Value{structpb.NewStringValue(w.Name)}},
},
}
},
userFunc: func(w *server.Worker) func() (*iam.User, auth.Account) {
return iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=worker;actions=*;output_fields=id,version,type,api_tags,authorized_actions"},
GrantScopes: []string{globals.GrantScopeThis},
},
})
},
wantOutputFields: []string{globals.IdField, globals.VersionField, globals.TypeField, globals.ApiTagsField, globals.AuthorizedActionsField},
},
{
name: "specific resource grants success",
input: func(w *server.Worker) *pbs.RemoveWorkerTagsRequest {
return &pbs.RemoveWorkerTagsRequest{
Id: w.PublicId,
Version: w.Version,
ApiTags: map[string]*structpb.ListValue{
w.Name: {Values: []*structpb.Value{structpb.NewStringValue(w.Name)}},
},
}
},
userFunc: func(w *server.Worker) func() (*iam.User, auth.Account) {
return iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{fmt.Sprintf("ids=%s;actions=*;output_fields=id,scope_id,api_tags,authorized_actions", w.PublicId)},
GrantScopes: []string{globals.GrantScopeThis},
},
})
},
wantOutputFields: []string{globals.IdField, globals.ScopeIdField, globals.ApiTagsField, globals.AuthorizedActionsField},
},
{
name: "no actions grant returns error",
input: func(w *server.Worker) *pbs.RemoveWorkerTagsRequest {
return &pbs.RemoveWorkerTagsRequest{
Id: w.PublicId,
Version: w.Version,
ApiTags: map[string]*structpb.ListValue{
w.Name: {Values: []*structpb.Value{structpb.NewStringValue(w.Name)}},
},
}
},
userFunc: func(w *server.Worker) func() (*iam.User, auth.Account) {
return iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=create,list,read-certificate-authority"},
GrantScopes: []string{globals.GrantScopeThis},
},
})
},
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
{
name: "wrong scope grants returns error",
input: func(w *server.Worker) *pbs.RemoveWorkerTagsRequest {
return &pbs.RemoveWorkerTagsRequest{
Id: w.PublicId,
Version: w.Version,
ApiTags: map[string]*structpb.ListValue{
w.Name: {Values: []*structpb.Value{structpb.NewStringValue(w.Name)}},
},
}
},
userFunc: func(w *server.Worker) func() (*iam.User, auth.Account) {
return iam.TestUserManagedGroupGrantsFunc(t, conn, kmsCache, globals.GlobalPrefix, ldap.TestAuthMethodWithAccountInManagedGroup, []iam.TestRoleGrantsRequest{
{
RoleScopeId: globals.GlobalPrefix,
Grants: []string{"ids=*;type=*;actions=*"},
GrantScopes: []string{globals.GrantScopeDescendants},
},
})
},
wantErr: handlers.ApiErrorWithCode(codes.PermissionDenied),
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
workerId, err := uuid.GenerateUUID()
require.NoError(t, err)
worker := server.TestPkiWorker(t, conn, wrapper,
server.WithName(workerId),
server.WithDescription(workerId),
server.WithTestUseInputTagsAsApiTags(true),
server.WithWorkerTags(&server.Tag{
Key: workerId,
Value: workerId,
}, &server.Tag{
Key: "another tag",
Value: "for output fields",
}),
server.WithNewIdFunc(func(ctx context.Context) (string, error) {
return server.NewWorkerIdFromScopeAndName(ctx, scope.Global.String(), workerId)
}),
)
user, accountID := tc.userFunc(worker)()
tok, err := atRepo.CreateAuthToken(ctx, user, accountID.GetPublicId())
require.NoError(t, err)
fullGrantAuthCtx := cauth.TestAuthContextFromToken(t, conn, wrapper, tok, iamRepo)
out, finalErr := s.RemoveWorkerTags(fullGrantAuthCtx, tc.input(worker))
if tc.wantErr != nil {
require.ErrorIs(t, finalErr, tc.wantErr)
return
}
require.NoError(t, finalErr)
handlers.TestAssertOutputFields(t, out.Item, tc.wantOutputFields)
})
}
}