mirror of https://github.com/hashicorp/boundary
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1525 lines
47 KiB
1525 lines
47 KiB
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package aliases_test
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/google/go-cmp/cmp/cmpopts"
|
|
"github.com/hashicorp/boundary/globals"
|
|
"github.com/hashicorp/boundary/internal/alias/target"
|
|
"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"
|
|
"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"
|
|
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"
|
|
"github.com/hashicorp/boundary/internal/target/tcp"
|
|
"github.com/hashicorp/boundary/internal/types/scope"
|
|
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/aliases"
|
|
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes"
|
|
"google.golang.org/genproto/protobuf/field_mask"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/protobuf/proto"
|
|
"google.golang.org/protobuf/testing/protocmp"
|
|
"google.golang.org/protobuf/types/known/timestamppb"
|
|
"google.golang.org/protobuf/types/known/wrapperspb"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
var testAuthorizedActions = []string{"no-op", "read", "update", "delete"}
|
|
|
|
func TestGet(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)
|
|
}
|
|
_, p := iam.TestScopes(t, iamRepo)
|
|
tar := tcp.TestTarget(ctx, t, conn, p.GetPublicId(), "testTarget")
|
|
og := target.TestAlias(t, rw, "test.get", target.WithName("alias name"), target.WithDescription("default"), target.WithDestinationId(tar.GetPublicId()), target.WithHostId("hst_1234567890"))
|
|
|
|
toMerge := &pbs.GetAliasRequest{
|
|
Id: og.GetPublicId(),
|
|
}
|
|
|
|
globalScopeInfo := &scopes.ScopeInfo{Id: scope.Global.String(), Type: scope.Global.String(), Name: "global", Description: "Global Scope"}
|
|
wantAlias := &pb.Alias{
|
|
Type: "target",
|
|
Id: og.GetPublicId(),
|
|
ScopeId: "global",
|
|
Scope: globalScopeInfo,
|
|
Name: wrapperspb.String(og.GetName()),
|
|
Description: wrapperspb.String(og.GetDescription()),
|
|
CreatedTime: og.CreateTime.GetTimestamp(),
|
|
UpdatedTime: og.UpdateTime.GetTimestamp(),
|
|
Value: og.GetValue(),
|
|
Version: 1,
|
|
DestinationId: wrapperspb.String(og.GetDestinationId()),
|
|
Attrs: &pb.Alias_TargetAliasAttributes{
|
|
TargetAliasAttributes: &pb.TargetAliasAttributes{
|
|
AuthorizeSessionArguments: &pb.AuthorizeSessionArguments{
|
|
HostId: og.GetHostId(),
|
|
},
|
|
},
|
|
},
|
|
AuthorizedActions: testAuthorizedActions,
|
|
}
|
|
|
|
cases := []struct {
|
|
name string
|
|
scopeId string
|
|
req *pbs.GetAliasRequest
|
|
res *pbs.GetAliasResponse
|
|
err error
|
|
}{
|
|
{
|
|
name: "Get an Existing Alias",
|
|
scopeId: og.GetScopeId(),
|
|
req: &pbs.GetAliasRequest{Id: og.GetPublicId()},
|
|
res: &pbs.GetAliasResponse{Item: wantAlias},
|
|
},
|
|
{
|
|
name: "Get a non existent Alias",
|
|
req: &pbs.GetAliasRequest{Id: globals.TargetAliasPrefix + "_DoesntExis"},
|
|
res: nil,
|
|
err: handlers.ApiErrorWithCode(codes.NotFound),
|
|
},
|
|
{
|
|
name: "Wrong id prefix",
|
|
req: &pbs.GetAliasRequest{Id: "j_1234567890"},
|
|
res: nil,
|
|
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
|
},
|
|
{
|
|
name: "space in id",
|
|
req: &pbs.GetAliasRequest{Id: globals.TargetAliasPrefix + "_1 23456789"},
|
|
res: nil,
|
|
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
|
},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
req := proto.Clone(toMerge).(*pbs.GetAliasRequest)
|
|
proto.Merge(req, tc.req)
|
|
|
|
s, err := aliases.NewService(ctx, repoFn, iamRepoFn, 1000)
|
|
require.NoError(err, "Couldn't create new alias service.")
|
|
|
|
got, gErr := s.GetAlias(auth.DisabledAuthTestContext(iamRepoFn, tc.scopeId), req)
|
|
if tc.err != nil {
|
|
require.Error(gErr)
|
|
assert.True(errors.Is(gErr, tc.err), "GetAlias(%+v) got error %v, wanted %v", req, gErr, tc.err)
|
|
}
|
|
assert.Empty(cmp.Diff(
|
|
got,
|
|
tc.res,
|
|
protocmp.Transform(),
|
|
cmpopts.SortSlices(func(a, b string) bool {
|
|
return a < b
|
|
}),
|
|
), "GetAlias(%q) got response\n%q, wanted\n%q", req, got, tc.res)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestList(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
|
|
}
|
|
repo, err := target.NewRepository(ctx, rw, rw, kmsCache)
|
|
require.NoError(t, err)
|
|
repoFn := func() (*target.Repository, error) {
|
|
return repo, nil
|
|
}
|
|
|
|
var wantGlobalAliases []*pb.Alias
|
|
for i := 0; i < 10; i++ {
|
|
gg := target.TestAlias(t, rw, fmt.Sprintf("test%d.alias", i))
|
|
wantGlobalAliases = append(wantGlobalAliases, &pb.Alias{
|
|
Type: "target",
|
|
Id: gg.GetPublicId(),
|
|
ScopeId: gg.GetScopeId(),
|
|
Scope: &scopes.ScopeInfo{Id: scope.Global.String(), Type: scope.Global.String(), Name: "global", Description: "Global Scope"},
|
|
CreatedTime: gg.GetCreateTime().GetTimestamp(),
|
|
UpdatedTime: gg.GetUpdateTime().GetTimestamp(),
|
|
Version: 1,
|
|
Value: gg.GetValue(),
|
|
AuthorizedActions: testAuthorizedActions,
|
|
})
|
|
}
|
|
|
|
slices.Reverse(wantGlobalAliases)
|
|
|
|
cases := []struct {
|
|
name string
|
|
req *pbs.ListAliasesRequest
|
|
res *pbs.ListAliasesResponse
|
|
err error
|
|
}{
|
|
{
|
|
name: "List Global Aliases",
|
|
req: &pbs.ListAliasesRequest{ScopeId: "global"},
|
|
res: &pbs.ListAliasesResponse{
|
|
Items: wantGlobalAliases,
|
|
EstItemCount: uint32(len(wantGlobalAliases)),
|
|
ResponseType: "complete",
|
|
SortBy: "created_time",
|
|
SortDir: "desc",
|
|
},
|
|
},
|
|
{
|
|
name: "List global aliases recursively",
|
|
req: &pbs.ListAliasesRequest{ScopeId: "global", Recursive: true},
|
|
res: &pbs.ListAliasesResponse{
|
|
Items: wantGlobalAliases,
|
|
EstItemCount: uint32(len(wantGlobalAliases)),
|
|
ResponseType: "complete",
|
|
SortBy: "created_time",
|
|
SortDir: "desc",
|
|
},
|
|
},
|
|
{
|
|
name: "Filter to no aliases",
|
|
req: &pbs.ListAliasesRequest{ScopeId: "global", Recursive: true, Filter: `"/item/id"=="doesntmatch"`},
|
|
res: &pbs.ListAliasesResponse{
|
|
ResponseType: "complete",
|
|
SortBy: "created_time",
|
|
SortDir: "desc",
|
|
},
|
|
},
|
|
{
|
|
name: "Filter Bad Format",
|
|
req: &pbs.ListAliasesRequest{ScopeId: "global", Filter: `"//id/"=="bad"`},
|
|
err: handlers.InvalidArgumentErrorf("bad format", nil),
|
|
},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
s, err := aliases.NewService(ctx, repoFn, iamRepoFn, 1000)
|
|
require.NoError(err, "Couldn't create new alias service.")
|
|
|
|
// Test with a non-anon user
|
|
got, gErr := s.ListAliases(auth.DisabledAuthTestContext(iamRepoFn, tc.req.GetScopeId()), tc.req)
|
|
if tc.err != nil {
|
|
require.Error(gErr)
|
|
assert.True(errors.Is(gErr, tc.err), "ListAliases(%q) got error %v, wanted %v", tc.req.GetScopeId(), gErr, tc.err)
|
|
return
|
|
}
|
|
require.NoError(gErr)
|
|
assert.Empty(cmp.Diff(
|
|
got,
|
|
tc.res,
|
|
protocmp.Transform(),
|
|
protocmp.IgnoreFields(&pbs.ListAliasesResponse{}, "list_token"),
|
|
cmpopts.SortSlices(func(a, b string) bool {
|
|
return a < b
|
|
}),
|
|
), "ListAliases(%q) got response %q, wanted %q", tc.req.GetScopeId(), got, tc.res)
|
|
|
|
// Test the anon case
|
|
got, gErr = s.ListAliases(auth.DisabledAuthTestContext(iamRepoFn, tc.req.GetScopeId(), auth.WithUserId(globals.AnonymousUserId)), tc.req)
|
|
require.NoError(gErr)
|
|
assert.Len(got.Items, len(tc.res.Items))
|
|
for _, item := range got.GetItems() {
|
|
require.Nil(item.CreatedTime)
|
|
require.Nil(item.UpdatedTime)
|
|
require.Zero(item.Version)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func aliasToProto(u *target.Alias, si *scopes.ScopeInfo, authorizedActions []string) *pb.Alias {
|
|
pu := &pb.Alias{
|
|
Type: "target",
|
|
Id: u.GetPublicId(),
|
|
Value: u.GetValue(),
|
|
ScopeId: u.GetScopeId(),
|
|
Scope: si,
|
|
CreatedTime: u.GetCreateTime().GetTimestamp(),
|
|
UpdatedTime: u.GetUpdateTime().GetTimestamp(),
|
|
Version: u.GetVersion(),
|
|
AuthorizedActions: testAuthorizedActions,
|
|
}
|
|
if u.GetName() != "" {
|
|
pu.Name = wrapperspb.String(u.GetName())
|
|
}
|
|
if u.GetDestinationId() != "" {
|
|
pu.DestinationId = wrapperspb.String(u.GetDestinationId())
|
|
}
|
|
if u.GetHostId() != "" {
|
|
pu.Attrs = &pb.Alias_TargetAliasAttributes{
|
|
TargetAliasAttributes: &pb.TargetAliasAttributes{
|
|
AuthorizeSessionArguments: &pb.AuthorizeSessionArguments{
|
|
HostId: u.GetHostId(),
|
|
},
|
|
},
|
|
}
|
|
}
|
|
if u.GetDescription() != "" {
|
|
pu.Description = wrapperspb.String(u.GetDescription())
|
|
}
|
|
return pu
|
|
}
|
|
|
|
func TestListPagination(t *testing.T) {
|
|
// Set database read timeout to avoid duplicates in response
|
|
oldReadTimeout := globals.RefreshReadLookbackDuration
|
|
globals.RefreshReadLookbackDuration = 0
|
|
t.Cleanup(func() {
|
|
globals.RefreshReadLookbackDuration = oldReadTimeout
|
|
})
|
|
ctx := context.Background()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
sqlDB, err := conn.SqlDB(ctx)
|
|
require.NoError(t, err)
|
|
wrapper := db.TestWrapper(t)
|
|
kmsCache := kms.TestKms(t, conn, wrapper)
|
|
rw := db.New(conn)
|
|
|
|
repo, err := target.NewRepository(ctx, rw, rw, kmsCache)
|
|
require.NoError(t, err)
|
|
repoFn := func() (*target.Repository, error) {
|
|
return repo, nil
|
|
}
|
|
|
|
iamRepo := iam.TestRepo(t, conn, wrapper)
|
|
iamRepoFn := func() (*iam.Repository, error) {
|
|
return iamRepo, nil
|
|
}
|
|
tokenRepoFn := func() (*authtoken.Repository, error) {
|
|
return authtoken.NewRepository(ctx, rw, rw, kmsCache)
|
|
}
|
|
serversRepoFn := func() (*server.Repository, error) {
|
|
return server.NewRepository(ctx, rw, rw, kmsCache)
|
|
}
|
|
tokenRepo, err := tokenRepoFn()
|
|
require.NoError(t, err)
|
|
|
|
// Run analyze to update postgres meta tables
|
|
_, err = sqlDB.ExecContext(ctx, "analyze")
|
|
require.NoError(t, err)
|
|
|
|
authMethod := password.TestAuthMethods(t, conn, "global", 1)[0]
|
|
acct := password.TestAccount(t, conn, authMethod.GetPublicId(), "test_user")
|
|
u := iam.TestUser(t, iamRepo, "global", iam.WithAccountIds(acct.PublicId))
|
|
// add roles to be able to see all users
|
|
allowedRole := iam.TestRole(t, conn, "global")
|
|
iam.TestRoleGrant(t, conn, allowedRole.GetPublicId(), "id=*;type=*;actions=*")
|
|
iam.TestUserRole(t, conn, allowedRole.GetPublicId(), u.GetPublicId())
|
|
|
|
at, err := tokenRepo.CreateAuthToken(ctx, u, acct.GetPublicId())
|
|
require.NoError(t, err)
|
|
|
|
// Test without anon user
|
|
requestInfo := authpb.RequestInfo{
|
|
TokenFormat: uint32(auth.AuthTokenTypeBearer),
|
|
PublicId: at.GetPublicId(),
|
|
Token: at.GetToken(),
|
|
}
|
|
requestContext := context.WithValue(context.Background(), requests.ContextRequestInformationKey, &requests.RequestContext{})
|
|
ctx = auth.NewVerifierContext(requestContext, iamRepoFn, tokenRepoFn, serversRepoFn, kmsCache, &requestInfo)
|
|
|
|
var globalAliases []*pb.Alias
|
|
globalScopeInfo := &scopes.ScopeInfo{Id: scope.Global.String(), Type: scope.Global.String(), Name: "global", Description: "Global Scope"}
|
|
var safeToDeleteAlias string
|
|
for i := 0; i < 10; i++ {
|
|
gg := target.TestAlias(t, rw, fmt.Sprintf("test%d.alias", i))
|
|
globalAliases = append(globalAliases, aliasToProto(gg, globalScopeInfo, testAuthorizedActions))
|
|
safeToDeleteAlias = gg.GetPublicId()
|
|
}
|
|
slices.Reverse(globalAliases)
|
|
|
|
a, err := aliases.NewService(ctx, repoFn, iamRepoFn, 1000)
|
|
require.NoError(t, err, "Couldn't create new alias service.")
|
|
|
|
// Run analyze to update postgres estimates
|
|
_, err = sqlDB.ExecContext(context.Background(), "analyze")
|
|
require.NoError(t, err)
|
|
|
|
itemCount := uint32(len(globalAliases))
|
|
testPageSize := int((itemCount - 2) / 2)
|
|
|
|
// Start paginating, recursively
|
|
req := &pbs.ListAliasesRequest{
|
|
ScopeId: "global",
|
|
Recursive: true,
|
|
Filter: "",
|
|
ListToken: "",
|
|
PageSize: uint32(testPageSize),
|
|
}
|
|
got, err := a.ListAliases(ctx, req)
|
|
require.NoError(t, err)
|
|
require.Len(t, got.GetItems(), testPageSize)
|
|
// Compare without comparing the list token
|
|
assert.Empty(t,
|
|
cmp.Diff(
|
|
got,
|
|
&pbs.ListAliasesResponse{
|
|
Items: globalAliases[0:testPageSize],
|
|
ResponseType: "delta",
|
|
SortBy: "created_time",
|
|
SortDir: "desc",
|
|
RemovedIds: nil,
|
|
// In addition to the added aliases, there are the aliases added
|
|
// by the test setup when specifying the permissions of the
|
|
// requester
|
|
EstItemCount: itemCount,
|
|
},
|
|
protocmp.SortRepeated(func(a, b string) bool {
|
|
return strings.Compare(a, b) < 0
|
|
}),
|
|
protocmp.Transform(),
|
|
protocmp.IgnoreFields(&pbs.ListAliasesResponse{}, "list_token"),
|
|
),
|
|
)
|
|
|
|
// Request second page
|
|
req.ListToken = got.ListToken
|
|
got, err = a.ListAliases(ctx, req)
|
|
require.NoError(t, err)
|
|
require.Len(t, got.GetItems(), testPageSize)
|
|
// Compare without comparing the list token
|
|
assert.Empty(t,
|
|
cmp.Diff(
|
|
got,
|
|
&pbs.ListAliasesResponse{
|
|
Items: globalAliases[testPageSize : testPageSize*2],
|
|
ResponseType: "delta",
|
|
SortBy: "created_time",
|
|
SortDir: "desc",
|
|
RemovedIds: nil,
|
|
EstItemCount: itemCount,
|
|
},
|
|
protocmp.Transform(),
|
|
protocmp.SortRepeated(func(a, b string) bool {
|
|
return strings.Compare(a, b) < 0
|
|
}),
|
|
protocmp.IgnoreFields(&pbs.ListAliasesResponse{}, "list_token"),
|
|
),
|
|
)
|
|
|
|
// Request rest of results
|
|
req.ListToken = got.ListToken
|
|
req.PageSize = 10
|
|
got, err = a.ListAliases(ctx, req)
|
|
require.NoError(t, err)
|
|
require.Len(t, got.GetItems(), 2)
|
|
// Compare without comparing the list token
|
|
assert.Empty(t,
|
|
cmp.Diff(
|
|
got,
|
|
&pbs.ListAliasesResponse{
|
|
Items: globalAliases[testPageSize*2:],
|
|
ResponseType: "complete",
|
|
SortBy: "created_time",
|
|
SortDir: "desc",
|
|
RemovedIds: nil,
|
|
EstItemCount: itemCount,
|
|
},
|
|
protocmp.Transform(),
|
|
protocmp.SortRepeated(func(a, b string) bool {
|
|
return strings.Compare(a, b) < 0
|
|
}),
|
|
protocmp.IgnoreFields(&pbs.ListAliasesResponse{}, "list_token"),
|
|
),
|
|
)
|
|
|
|
// Update 2 aliases and see them in the refresh
|
|
g1 := globalAliases[len(globalAliases)-1]
|
|
g1.Description = wrapperspb.String("updated1")
|
|
resp1, err := a.UpdateAlias(ctx, &pbs.UpdateAliasRequest{
|
|
Id: g1.GetId(),
|
|
Item: &pb.Alias{Description: g1.GetDescription(), Version: g1.GetVersion()},
|
|
UpdateMask: &field_mask.FieldMask{Paths: []string{"description"}},
|
|
})
|
|
require.NoError(t, err)
|
|
g1.UpdatedTime = resp1.GetItem().GetUpdatedTime()
|
|
g1.Version = resp1.GetItem().GetVersion()
|
|
globalAliases = append([]*pb.Alias{g1}, globalAliases[:len(globalAliases)-1]...)
|
|
|
|
g2 := globalAliases[len(globalAliases)-1]
|
|
g2.Description = wrapperspb.String("updated2")
|
|
resp2, err := a.UpdateAlias(ctx, &pbs.UpdateAliasRequest{
|
|
Id: g2.GetId(),
|
|
Item: &pb.Alias{Description: g2.GetDescription(), Version: g2.GetVersion()},
|
|
UpdateMask: &field_mask.FieldMask{Paths: []string{"description"}},
|
|
})
|
|
require.NoError(t, err)
|
|
g2.UpdatedTime = resp2.GetItem().GetUpdatedTime()
|
|
g2.Version = resp2.GetItem().GetVersion()
|
|
globalAliases = append([]*pb.Alias{g2}, globalAliases[:len(globalAliases)-1]...)
|
|
|
|
// Run analyze to update postgres estimates
|
|
_, err = sqlDB.ExecContext(ctx, "analyze")
|
|
require.NoError(t, err)
|
|
|
|
// Request updated results
|
|
req.ListToken = got.ListToken
|
|
req.PageSize = 1
|
|
got, err = a.ListAliases(ctx, req)
|
|
require.NoError(t, err)
|
|
require.Len(t, got.GetItems(), 1)
|
|
// Compare without comparing the list token
|
|
assert.Empty(t,
|
|
cmp.Diff(
|
|
got,
|
|
&pbs.ListAliasesResponse{
|
|
Items: []*pb.Alias{globalAliases[0]},
|
|
ResponseType: "delta",
|
|
SortBy: "updated_time",
|
|
SortDir: "desc",
|
|
RemovedIds: nil,
|
|
EstItemCount: itemCount,
|
|
},
|
|
protocmp.Transform(),
|
|
protocmp.SortRepeated(func(a, b string) bool {
|
|
return strings.Compare(a, b) < 0
|
|
}),
|
|
protocmp.IgnoreFields(&pbs.ListAliasesResponse{}, "list_token"),
|
|
),
|
|
)
|
|
|
|
// Get next page
|
|
req.ListToken = got.ListToken
|
|
got, err = a.ListAliases(ctx, req)
|
|
require.NoError(t, err)
|
|
require.Len(t, got.GetItems(), 1)
|
|
// Compare without comparing the list token
|
|
assert.Empty(t,
|
|
cmp.Diff(
|
|
got,
|
|
&pbs.ListAliasesResponse{
|
|
Items: []*pb.Alias{globalAliases[1]},
|
|
ResponseType: "complete",
|
|
SortBy: "updated_time",
|
|
SortDir: "desc",
|
|
RemovedIds: nil,
|
|
EstItemCount: itemCount,
|
|
},
|
|
protocmp.Transform(),
|
|
protocmp.SortRepeated(func(a, b string) bool {
|
|
return strings.Compare(a, b) < 0
|
|
}),
|
|
protocmp.IgnoreFields(&pbs.ListAliasesResponse{}, "list_token"),
|
|
),
|
|
)
|
|
|
|
// Request new page with filter requiring looping
|
|
// to fill the page.
|
|
req.ListToken = ""
|
|
req.PageSize = 1
|
|
req.Filter = fmt.Sprintf(`"/item/id"==%q or "/item/id"==%q`, globalAliases[len(globalAliases)-2].Id, globalAliases[len(globalAliases)-1].Id)
|
|
got, err = a.ListAliases(ctx, req)
|
|
require.NoError(t, err)
|
|
require.Len(t, got.GetItems(), 1)
|
|
assert.Empty(t,
|
|
cmp.Diff(
|
|
got,
|
|
&pbs.ListAliasesResponse{
|
|
Items: []*pb.Alias{globalAliases[len(globalAliases)-2]},
|
|
ResponseType: "delta",
|
|
SortBy: "created_time",
|
|
SortDir: "desc",
|
|
// Should be empty again
|
|
RemovedIds: nil,
|
|
EstItemCount: itemCount,
|
|
},
|
|
protocmp.Transform(),
|
|
protocmp.SortRepeated(func(a, b string) bool {
|
|
return strings.Compare(a, b) < 0
|
|
}),
|
|
protocmp.IgnoreFields(&pbs.ListAliasesResponse{}, "list_token"),
|
|
),
|
|
)
|
|
req.ListToken = got.ListToken
|
|
// Get the second page
|
|
got, err = a.ListAliases(ctx, req)
|
|
require.NoError(t, err)
|
|
require.Len(t, got.GetItems(), 1)
|
|
assert.Empty(t,
|
|
cmp.Diff(
|
|
got,
|
|
&pbs.ListAliasesResponse{
|
|
Items: []*pb.Alias{globalAliases[len(globalAliases)-1]},
|
|
ResponseType: "complete",
|
|
SortBy: "created_time",
|
|
SortDir: "desc",
|
|
RemovedIds: nil,
|
|
EstItemCount: itemCount,
|
|
},
|
|
protocmp.Transform(),
|
|
protocmp.SortRepeated(func(a, b string) bool {
|
|
return strings.Compare(a, b) < 0
|
|
}),
|
|
protocmp.IgnoreFields(&pbs.ListAliasesResponse{}, "list_token"),
|
|
),
|
|
)
|
|
|
|
_, err = repo.DeleteAlias(ctx, safeToDeleteAlias)
|
|
require.NoError(t, err)
|
|
req.ListToken = got.ListToken
|
|
got, err = a.ListAliases(ctx, req)
|
|
require.NoError(t, err)
|
|
assert.Empty(t,
|
|
cmp.Diff(
|
|
got,
|
|
&pbs.ListAliasesResponse{
|
|
Items: nil,
|
|
ResponseType: "complete",
|
|
SortBy: "updated_time",
|
|
SortDir: "desc",
|
|
RemovedIds: []string{safeToDeleteAlias},
|
|
EstItemCount: itemCount,
|
|
},
|
|
protocmp.Transform(),
|
|
protocmp.SortRepeated(func(a, b string) bool {
|
|
return strings.Compare(a, b) < 0
|
|
}),
|
|
protocmp.IgnoreFields(&pbs.ListAliasesResponse{}, "list_token"),
|
|
),
|
|
)
|
|
}
|
|
|
|
func TestDelete(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
|
|
}
|
|
|
|
_, p := iam.TestScopes(t, iamRepo)
|
|
|
|
repoFn := func() (*target.Repository, error) {
|
|
return target.NewRepository(ctx, rw, rw, kmsCache)
|
|
}
|
|
tar := tcp.TestTarget(ctx, t, conn, p.GetPublicId(), "testTarget")
|
|
og := target.TestAlias(t, rw, "test.delete", target.WithDescription("default"), target.WithDestinationId(tar.GetPublicId()), target.WithHostId("hst_1234567890"))
|
|
|
|
s, err := aliases.NewService(context.Background(), repoFn, iamRepoFn, 1000)
|
|
require.NoError(t, err, "Error when getting new alias service.")
|
|
|
|
cases := []struct {
|
|
name string
|
|
scopeId string
|
|
req *pbs.DeleteAliasRequest
|
|
res *pbs.DeleteAliasResponse
|
|
err error
|
|
}{
|
|
{
|
|
name: "Delete an Existing Alias",
|
|
scopeId: og.GetScopeId(),
|
|
req: &pbs.DeleteAliasRequest{
|
|
Id: og.GetPublicId(),
|
|
},
|
|
},
|
|
{
|
|
name: "Delete bad alias id",
|
|
scopeId: og.GetScopeId(),
|
|
req: &pbs.DeleteAliasRequest{
|
|
Id: globals.TargetAliasPrefix + "_doesntexis",
|
|
},
|
|
err: handlers.ApiErrorWithCode(codes.NotFound),
|
|
},
|
|
{
|
|
name: "Bad Alias Id formatting",
|
|
scopeId: og.GetScopeId(),
|
|
req: &pbs.DeleteAliasRequest{
|
|
Id: "bad_format",
|
|
},
|
|
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
|
},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
got, gErr := s.DeleteAlias(auth.DisabledAuthTestContext(iamRepoFn, tc.scopeId), tc.req)
|
|
if tc.err != nil {
|
|
require.Error(gErr)
|
|
assert.True(errors.Is(gErr, tc.err), "DeleteAlias(%+v) got error %v, wanted %v", tc.req, gErr, tc.err)
|
|
}
|
|
assert.EqualValuesf(tc.res, got, "DeleteAlias(%+v) got response %q, wanted %q", tc.req, got, tc.res)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDelete_twice(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)
|
|
}
|
|
og := target.TestAlias(t, rw, "test.delete", target.WithDescription("default"))
|
|
|
|
s, err := aliases.NewService(context.Background(), repoFn, iamRepoFn, 1000)
|
|
require.NoError(t, err, "Error when getting new alias service")
|
|
scopeId := og.GetScopeId()
|
|
req := &pbs.DeleteAliasRequest{
|
|
Id: og.GetPublicId(),
|
|
}
|
|
ctx = auth.DisabledAuthTestContext(iamRepoFn, scopeId)
|
|
_, gErr := s.DeleteAlias(ctx, req)
|
|
assert.NoError(t, gErr, "First attempt")
|
|
_, gErr = s.DeleteAlias(ctx, req)
|
|
assert.Error(t, gErr, "Second attempt")
|
|
assert.True(t, errors.Is(gErr, handlers.ApiErrorWithCode(codes.NotFound)), "Expected permission denied for the second delete.")
|
|
}
|
|
|
|
func TestCreate(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
|
|
}
|
|
_, p := iam.TestScopes(t, iamRepo)
|
|
|
|
repoFn := func() (*target.Repository, error) {
|
|
return target.NewRepository(ctx, rw, rw, kmsCache)
|
|
}
|
|
tar := tcp.TestTarget(ctx, t, conn, p.GetPublicId(), "testTarget")
|
|
al := target.TestAlias(t, rw, "test.duplicated.create",
|
|
target.WithName("alias name"),
|
|
target.WithDestinationId(tar.GetPublicId()))
|
|
|
|
globalScopeInfo := &scopes.ScopeInfo{Id: scope.Global.String(), Type: scope.Global.String(), Name: "global", Description: "Global Scope"}
|
|
|
|
cases := []struct {
|
|
name string
|
|
req *pbs.CreateAliasRequest
|
|
res *pbs.CreateAliasResponse
|
|
errContains string
|
|
}{
|
|
{
|
|
name: "Create a valid Alias",
|
|
req: &pbs.CreateAliasRequest{Item: &pb.Alias{
|
|
Type: "target",
|
|
ScopeId: scope.Global.String(),
|
|
Value: "valid.alias",
|
|
}},
|
|
res: &pbs.CreateAliasResponse{
|
|
Uri: fmt.Sprintf("aliases/%s_", globals.TargetAliasPrefix),
|
|
Item: &pb.Alias{
|
|
Type: "target",
|
|
ScopeId: scope.Global.String(),
|
|
Scope: globalScopeInfo,
|
|
Value: "valid.alias",
|
|
Version: 1,
|
|
AuthorizedActions: testAuthorizedActions,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Alias to existing target",
|
|
req: &pbs.CreateAliasRequest{Item: &pb.Alias{
|
|
Type: "target",
|
|
ScopeId: scope.Global.String(),
|
|
Value: "target-assigned.valid.alias",
|
|
DestinationId: wrapperspb.String(tar.GetPublicId()),
|
|
}},
|
|
res: &pbs.CreateAliasResponse{
|
|
Uri: fmt.Sprintf("aliases/%s_", globals.TargetAliasPrefix),
|
|
Item: &pb.Alias{
|
|
Type: "target",
|
|
ScopeId: scope.Global.String(),
|
|
Scope: globalScopeInfo,
|
|
Value: "target-assigned.valid.alias",
|
|
DestinationId: wrapperspb.String(tar.GetPublicId()),
|
|
Version: 1,
|
|
AuthorizedActions: testAuthorizedActions,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Alias to poorly formatted target id",
|
|
req: &pbs.CreateAliasRequest{Item: &pb.Alias{
|
|
Type: "target",
|
|
ScopeId: scope.Global.String(),
|
|
Value: "target-assigned.valid.alias",
|
|
DestinationId: wrapperspb.String("this is not a valid target id"),
|
|
}},
|
|
errContains: `Incorrectly formatted identifier.`,
|
|
},
|
|
{
|
|
name: "Alias to existing target with static host id",
|
|
req: &pbs.CreateAliasRequest{Item: &pb.Alias{
|
|
Type: "target",
|
|
ScopeId: scope.Global.String(),
|
|
Value: "target-assigned.valid.alias.two",
|
|
Attrs: &pb.Alias_TargetAliasAttributes{
|
|
TargetAliasAttributes: &pb.TargetAliasAttributes{
|
|
AuthorizeSessionArguments: &pb.AuthorizeSessionArguments{
|
|
HostId: "hst_1234567890",
|
|
},
|
|
},
|
|
},
|
|
DestinationId: wrapperspb.String(tar.GetPublicId()),
|
|
}},
|
|
res: &pbs.CreateAliasResponse{
|
|
Uri: fmt.Sprintf("aliases/%s_", globals.TargetAliasPrefix),
|
|
Item: &pb.Alias{
|
|
Type: "target",
|
|
ScopeId: scope.Global.String(),
|
|
Scope: globalScopeInfo,
|
|
Value: "target-assigned.valid.alias.two",
|
|
Attrs: &pb.Alias_TargetAliasAttributes{
|
|
TargetAliasAttributes: &pb.TargetAliasAttributes{
|
|
AuthorizeSessionArguments: &pb.AuthorizeSessionArguments{
|
|
HostId: "hst_1234567890",
|
|
},
|
|
},
|
|
},
|
|
DestinationId: wrapperspb.String(tar.GetPublicId()),
|
|
Version: 1,
|
|
AuthorizedActions: testAuthorizedActions,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Alias to existing target with dynamic host id",
|
|
req: &pbs.CreateAliasRequest{Item: &pb.Alias{
|
|
Type: "target",
|
|
ScopeId: scope.Global.String(),
|
|
Value: "target-assigned.valid.alias.three",
|
|
Attrs: &pb.Alias_TargetAliasAttributes{
|
|
TargetAliasAttributes: &pb.TargetAliasAttributes{
|
|
AuthorizeSessionArguments: &pb.AuthorizeSessionArguments{
|
|
HostId: "hplg_1234567890",
|
|
},
|
|
},
|
|
},
|
|
DestinationId: wrapperspb.String(tar.GetPublicId()),
|
|
}},
|
|
res: &pbs.CreateAliasResponse{
|
|
Uri: fmt.Sprintf("aliases/%s_", globals.TargetAliasPrefix),
|
|
Item: &pb.Alias{
|
|
Type: "target",
|
|
ScopeId: scope.Global.String(),
|
|
Scope: globalScopeInfo,
|
|
Value: "target-assigned.valid.alias.three",
|
|
Attrs: &pb.Alias_TargetAliasAttributes{
|
|
TargetAliasAttributes: &pb.TargetAliasAttributes{
|
|
AuthorizeSessionArguments: &pb.AuthorizeSessionArguments{
|
|
HostId: "hplg_1234567890",
|
|
},
|
|
},
|
|
},
|
|
DestinationId: wrapperspb.String(tar.GetPublicId()),
|
|
Version: 1,
|
|
AuthorizedActions: testAuthorizedActions,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Omitting the alias type",
|
|
req: &pbs.CreateAliasRequest{Item: &pb.Alias{
|
|
ScopeId: scope.Global.String(),
|
|
Value: "target-assigned.valid.alias",
|
|
DestinationId: wrapperspb.String(tar.GetPublicId()),
|
|
}},
|
|
errContains: `This field is required`,
|
|
},
|
|
{
|
|
name: "host id with no destination target",
|
|
req: &pbs.CreateAliasRequest{Item: &pb.Alias{
|
|
Type: "target",
|
|
ScopeId: scope.Global.String(),
|
|
Value: "host-id.no-destination.alias",
|
|
Attrs: &pb.Alias_TargetAliasAttributes{
|
|
TargetAliasAttributes: &pb.TargetAliasAttributes{
|
|
AuthorizeSessionArguments: &pb.AuthorizeSessionArguments{
|
|
HostId: "hst_1234567890",
|
|
},
|
|
},
|
|
},
|
|
}},
|
|
errContains: `This field is required when 'attributes.authorize_session_arguments.host_id' is specified.`,
|
|
},
|
|
{
|
|
name: "improperly formatted host id",
|
|
req: &pbs.CreateAliasRequest{Item: &pb.Alias{
|
|
Type: "target",
|
|
ScopeId: scope.Global.String(),
|
|
Value: "bad-host-id.alias",
|
|
DestinationId: wrapperspb.String(tar.GetPublicId()),
|
|
Attrs: &pb.Alias_TargetAliasAttributes{
|
|
TargetAliasAttributes: &pb.TargetAliasAttributes{
|
|
AuthorizeSessionArguments: &pb.AuthorizeSessionArguments{
|
|
HostId: "badid_1234567890",
|
|
},
|
|
},
|
|
},
|
|
}},
|
|
errContains: `Incorrectly formatted identifier.`,
|
|
},
|
|
{
|
|
name: "Alias to non existing target",
|
|
req: &pbs.CreateAliasRequest{Item: &pb.Alias{
|
|
Type: "target",
|
|
ScopeId: scope.Global.String(),
|
|
Value: "unknowntarget.alias",
|
|
DestinationId: wrapperspb.String("ttcp_1234567890"),
|
|
}},
|
|
errContains: `target with specified destination id "ttcp_1234567890" was not found`,
|
|
},
|
|
{
|
|
name: "Duplicate Alias Value",
|
|
req: &pbs.CreateAliasRequest{Item: &pb.Alias{
|
|
Type: "target",
|
|
ScopeId: scope.Global.String(),
|
|
Value: al.GetValue(),
|
|
}},
|
|
errContains: `alias value "test.duplicated.create" is already in use`,
|
|
},
|
|
{
|
|
name: "Duplicate Alias Name",
|
|
req: &pbs.CreateAliasRequest{Item: &pb.Alias{
|
|
Type: "target",
|
|
ScopeId: scope.Global.String(),
|
|
Value: "duplicate.alias.name",
|
|
Name: wrapperspb.String(al.GetName()),
|
|
}},
|
|
errContains: `name "alias name" is already in use`,
|
|
},
|
|
{
|
|
name: "must be in global scope",
|
|
req: &pbs.CreateAliasRequest{Item: &pb.Alias{
|
|
Type: "target",
|
|
ScopeId: p.GetPublicId(),
|
|
Value: "must.be.in.global.scope",
|
|
}},
|
|
errContains: `{name: "scope_id", desc: "This field is missing or improperly formatted."}`,
|
|
},
|
|
{
|
|
name: "Can't specify Id",
|
|
req: &pbs.CreateAliasRequest{Item: &pb.Alias{
|
|
Type: "target",
|
|
ScopeId: scope.Global.String(),
|
|
Id: globals.TargetAliasPrefix + "_notallowed",
|
|
}},
|
|
res: nil,
|
|
errContains: "This is a read only field.",
|
|
},
|
|
{
|
|
name: "Can't specify Created Time",
|
|
req: &pbs.CreateAliasRequest{Item: &pb.Alias{
|
|
Type: "target",
|
|
ScopeId: scope.Global.String(),
|
|
CreatedTime: timestamppb.Now(),
|
|
}},
|
|
res: nil,
|
|
errContains: "This is a read only field.",
|
|
},
|
|
{
|
|
name: "Can't specify Update Time",
|
|
req: &pbs.CreateAliasRequest{Item: &pb.Alias{
|
|
Type: "target",
|
|
ScopeId: scope.Global.String(),
|
|
UpdatedTime: timestamppb.Now(),
|
|
}},
|
|
res: nil,
|
|
errContains: "This is a read only field.",
|
|
},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
|
|
s, err := aliases.NewService(context.Background(), repoFn, iamRepoFn, 1000)
|
|
require.NoError(err, "Error when getting new alias service.")
|
|
|
|
got, gErr := s.CreateAlias(auth.DisabledAuthTestContext(iamRepoFn, tc.req.GetItem().GetScopeId()), tc.req)
|
|
if tc.errContains != "" {
|
|
require.Error(gErr)
|
|
assert.ErrorContains(gErr, tc.errContains)
|
|
return
|
|
}
|
|
require.NoError(gErr)
|
|
assert.Contains(got.GetUri(), tc.res.Uri)
|
|
assert.True(strings.HasPrefix(got.GetItem().GetId(), globals.TargetAliasPrefix+"_"))
|
|
// Clear all values which are hard to compare against.
|
|
got.Uri, tc.res.Uri = "", ""
|
|
got.Item.Id, tc.res.Item.Id = "", ""
|
|
got.Item.CreatedTime, got.Item.UpdatedTime, tc.res.Item.CreatedTime, tc.res.Item.UpdatedTime = nil, nil, nil, nil
|
|
assert.Empty(cmp.Diff(
|
|
got,
|
|
tc.res,
|
|
protocmp.Transform(),
|
|
cmpopts.SortSlices(func(a, b string) bool {
|
|
return a < b
|
|
}),
|
|
), "CreateAlias(%q) got response %q, wanted %q", tc.req, got, tc.res)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUpdate(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
|
|
}
|
|
|
|
_, p := iam.TestScopes(t, iamRepo)
|
|
tar := tcp.TestTarget(ctx, t, conn, p.GetPublicId(), "testTarget")
|
|
tar2 := tcp.TestTarget(ctx, t, conn, p.GetPublicId(), "testTarget2")
|
|
|
|
repoFn := func() (*target.Repository, error) {
|
|
return target.NewRepository(ctx, rw, rw, kmsCache)
|
|
}
|
|
|
|
og := target.TestAlias(t, rw, "default",
|
|
target.WithDestinationId(tar.GetPublicId()),
|
|
target.WithName("default"),
|
|
target.WithDescription("default"))
|
|
|
|
var ogVersion uint32 = 1
|
|
|
|
resetAlias := func(version uint32) {
|
|
repo, err := repoFn()
|
|
require.NoError(t, err, "Couldn't get a new repo")
|
|
og, _, err = repo.UpdateAlias(ctx, og, version, []string{"Name", "Description", "DestinationId", "Value"})
|
|
require.NoError(t, err, "Failed to reset the alias")
|
|
ogVersion = og.GetVersion()
|
|
}
|
|
|
|
created := og.GetCreateTime().GetTimestamp().AsTime()
|
|
toMerge := &pbs.UpdateAliasRequest{
|
|
Id: og.GetPublicId(),
|
|
}
|
|
globalScopeInfo := &scopes.ScopeInfo{Id: scope.Global.String(), Type: scope.Global.String(), Name: "global", Description: "Global Scope"}
|
|
|
|
tested, err := aliases.NewService(ctx, repoFn, iamRepoFn, 1000)
|
|
require.NoError(t, err, "Error creating new service")
|
|
cases := []struct {
|
|
name string
|
|
scopeId string
|
|
req *pbs.UpdateAliasRequest
|
|
res *pbs.UpdateAliasResponse
|
|
err error
|
|
}{
|
|
{
|
|
name: "Update an Existing Alias",
|
|
scopeId: og.GetScopeId(),
|
|
req: &pbs.UpdateAliasRequest{
|
|
UpdateMask: &field_mask.FieldMask{
|
|
Paths: []string{"name", "description"},
|
|
},
|
|
Item: &pb.Alias{
|
|
Name: wrapperspb.String("updated"),
|
|
Description: wrapperspb.String("updated"),
|
|
},
|
|
},
|
|
res: &pbs.UpdateAliasResponse{
|
|
Item: &pb.Alias{
|
|
Type: "target",
|
|
Id: og.GetPublicId(),
|
|
ScopeId: og.GetScopeId(),
|
|
Scope: globalScopeInfo,
|
|
Value: "default",
|
|
DestinationId: wrapperspb.String(tar.GetPublicId()),
|
|
Name: wrapperspb.String("updated"),
|
|
Description: wrapperspb.String("updated"),
|
|
CreatedTime: og.GetCreateTime().GetTimestamp(),
|
|
AuthorizedActions: testAuthorizedActions,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Multiple Paths in single string",
|
|
scopeId: og.GetScopeId(),
|
|
req: &pbs.UpdateAliasRequest{
|
|
UpdateMask: &field_mask.FieldMask{
|
|
Paths: []string{"name,description"},
|
|
},
|
|
Item: &pb.Alias{
|
|
Name: wrapperspb.String("updated"),
|
|
Description: wrapperspb.String("updated"),
|
|
},
|
|
},
|
|
res: &pbs.UpdateAliasResponse{
|
|
Item: &pb.Alias{
|
|
Type: "target",
|
|
Id: og.GetPublicId(),
|
|
ScopeId: og.GetScopeId(),
|
|
Scope: globalScopeInfo,
|
|
Value: "default",
|
|
DestinationId: wrapperspb.String(tar.GetPublicId()),
|
|
Name: wrapperspb.String("updated"),
|
|
Description: wrapperspb.String("updated"),
|
|
CreatedTime: og.GetCreateTime().GetTimestamp(),
|
|
AuthorizedActions: testAuthorizedActions,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "No Update Mask",
|
|
req: &pbs.UpdateAliasRequest{
|
|
Item: &pb.Alias{
|
|
Description: wrapperspb.String("updated desc"),
|
|
},
|
|
},
|
|
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
|
},
|
|
{
|
|
name: "No Paths in Mask",
|
|
scopeId: og.GetScopeId(),
|
|
req: &pbs.UpdateAliasRequest{
|
|
UpdateMask: &field_mask.FieldMask{Paths: []string{}},
|
|
Item: &pb.Alias{
|
|
Description: wrapperspb.String("updated desc"),
|
|
},
|
|
},
|
|
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
|
},
|
|
{
|
|
name: "Only non-existent paths in Mask",
|
|
scopeId: og.GetScopeId(),
|
|
req: &pbs.UpdateAliasRequest{
|
|
UpdateMask: &field_mask.FieldMask{Paths: []string{"nonexistant_field"}},
|
|
Item: &pb.Alias{
|
|
Description: wrapperspb.String("updated desc"),
|
|
},
|
|
},
|
|
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
|
},
|
|
{
|
|
name: "Unset Name",
|
|
scopeId: og.GetScopeId(),
|
|
req: &pbs.UpdateAliasRequest{
|
|
UpdateMask: &field_mask.FieldMask{
|
|
Paths: []string{"name"},
|
|
},
|
|
Item: &pb.Alias{
|
|
Description: wrapperspb.String("ignored"),
|
|
},
|
|
},
|
|
res: &pbs.UpdateAliasResponse{
|
|
Item: &pb.Alias{
|
|
Type: "target",
|
|
Id: og.GetPublicId(),
|
|
ScopeId: og.GetScopeId(),
|
|
Scope: globalScopeInfo,
|
|
Value: "default",
|
|
DestinationId: wrapperspb.String(tar.GetPublicId()),
|
|
Description: wrapperspb.String("default"),
|
|
CreatedTime: og.GetCreateTime().GetTimestamp(),
|
|
AuthorizedActions: testAuthorizedActions,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Update Only Name",
|
|
scopeId: og.GetScopeId(),
|
|
req: &pbs.UpdateAliasRequest{
|
|
UpdateMask: &field_mask.FieldMask{
|
|
Paths: []string{"name"},
|
|
},
|
|
Item: &pb.Alias{
|
|
Name: wrapperspb.String("updated"),
|
|
Description: wrapperspb.String("ignored"),
|
|
},
|
|
},
|
|
res: &pbs.UpdateAliasResponse{
|
|
Item: &pb.Alias{
|
|
Type: "target",
|
|
Id: og.GetPublicId(),
|
|
Name: wrapperspb.String("updated"),
|
|
ScopeId: og.GetScopeId(),
|
|
Scope: globalScopeInfo,
|
|
Value: "default",
|
|
DestinationId: wrapperspb.String(tar.GetPublicId()),
|
|
Description: wrapperspb.String("default"),
|
|
CreatedTime: og.GetCreateTime().GetTimestamp(),
|
|
AuthorizedActions: testAuthorizedActions,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Update Only value",
|
|
scopeId: og.GetScopeId(),
|
|
req: &pbs.UpdateAliasRequest{
|
|
UpdateMask: &field_mask.FieldMask{
|
|
Paths: []string{"value"},
|
|
},
|
|
Item: &pb.Alias{
|
|
Name: wrapperspb.String("ignored"),
|
|
Value: "updated",
|
|
},
|
|
},
|
|
res: &pbs.UpdateAliasResponse{
|
|
Item: &pb.Alias{
|
|
Type: "target",
|
|
Id: og.GetPublicId(),
|
|
ScopeId: og.GetScopeId(),
|
|
Scope: globalScopeInfo,
|
|
Value: "updated",
|
|
DestinationId: wrapperspb.String(tar.GetPublicId()),
|
|
Name: wrapperspb.String("default"),
|
|
Description: wrapperspb.String("default"),
|
|
CreatedTime: og.GetCreateTime().GetTimestamp(),
|
|
AuthorizedActions: testAuthorizedActions,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Update destination id",
|
|
scopeId: og.GetScopeId(),
|
|
req: &pbs.UpdateAliasRequest{
|
|
UpdateMask: &field_mask.FieldMask{
|
|
Paths: []string{"destination_id"},
|
|
},
|
|
Item: &pb.Alias{
|
|
Name: wrapperspb.String("ignored"),
|
|
DestinationId: wrapperspb.String("invalid format for targets"),
|
|
},
|
|
},
|
|
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
|
},
|
|
{
|
|
name: "unset value",
|
|
scopeId: og.GetScopeId(),
|
|
req: &pbs.UpdateAliasRequest{
|
|
UpdateMask: &field_mask.FieldMask{
|
|
Paths: []string{"value"},
|
|
},
|
|
Item: &pb.Alias{
|
|
Name: wrapperspb.String("ignored"),
|
|
},
|
|
},
|
|
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
|
},
|
|
{
|
|
name: "Update Only destination id",
|
|
scopeId: og.GetScopeId(),
|
|
req: &pbs.UpdateAliasRequest{
|
|
UpdateMask: &field_mask.FieldMask{
|
|
Paths: []string{"destination_id"},
|
|
},
|
|
Item: &pb.Alias{
|
|
Value: "ignored",
|
|
DestinationId: wrapperspb.String(tar2.GetPublicId()),
|
|
},
|
|
},
|
|
res: &pbs.UpdateAliasResponse{
|
|
Item: &pb.Alias{
|
|
Type: "target",
|
|
Id: og.GetPublicId(),
|
|
ScopeId: og.GetScopeId(),
|
|
Scope: globalScopeInfo,
|
|
Value: "default",
|
|
DestinationId: wrapperspb.String(tar2.GetPublicId()),
|
|
Name: wrapperspb.String("default"),
|
|
Description: wrapperspb.String("default"),
|
|
CreatedTime: og.GetCreateTime().GetTimestamp(),
|
|
AuthorizedActions: testAuthorizedActions,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Unset destination id",
|
|
scopeId: og.GetScopeId(),
|
|
req: &pbs.UpdateAliasRequest{
|
|
UpdateMask: &field_mask.FieldMask{
|
|
Paths: []string{"destination_id"},
|
|
},
|
|
Item: &pb.Alias{
|
|
Value: "ignored",
|
|
},
|
|
},
|
|
res: &pbs.UpdateAliasResponse{
|
|
Item: &pb.Alias{
|
|
Type: "target",
|
|
Id: og.GetPublicId(),
|
|
ScopeId: og.GetScopeId(),
|
|
Scope: globalScopeInfo,
|
|
Value: "default",
|
|
Name: wrapperspb.String("default"),
|
|
Description: wrapperspb.String("default"),
|
|
CreatedTime: og.GetCreateTime().GetTimestamp(),
|
|
AuthorizedActions: testAuthorizedActions,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Update Only Description",
|
|
scopeId: og.GetScopeId(),
|
|
req: &pbs.UpdateAliasRequest{
|
|
UpdateMask: &field_mask.FieldMask{
|
|
Paths: []string{"description"},
|
|
},
|
|
Item: &pb.Alias{
|
|
Description: wrapperspb.String("updated"),
|
|
},
|
|
},
|
|
res: &pbs.UpdateAliasResponse{
|
|
Item: &pb.Alias{
|
|
Type: "target",
|
|
Id: og.GetPublicId(),
|
|
ScopeId: og.GetScopeId(),
|
|
Scope: globalScopeInfo,
|
|
Value: "default",
|
|
DestinationId: wrapperspb.String(tar.GetPublicId()),
|
|
Name: wrapperspb.String("default"),
|
|
Description: wrapperspb.String("updated"),
|
|
CreatedTime: og.GetCreateTime().GetTimestamp(),
|
|
AuthorizedActions: testAuthorizedActions,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Update a Non Existing Alias",
|
|
req: &pbs.UpdateAliasRequest{
|
|
Id: globals.TargetAliasPrefix + "_DoesntExis",
|
|
UpdateMask: &field_mask.FieldMask{
|
|
Paths: []string{"description"},
|
|
},
|
|
Item: &pb.Alias{
|
|
Description: wrapperspb.String("desc"),
|
|
},
|
|
},
|
|
err: handlers.ApiErrorWithCode(codes.NotFound),
|
|
},
|
|
{
|
|
name: "Cant change Id",
|
|
req: &pbs.UpdateAliasRequest{
|
|
Id: og.GetPublicId(),
|
|
UpdateMask: &field_mask.FieldMask{
|
|
Paths: []string{"id"},
|
|
},
|
|
Item: &pb.Alias{
|
|
Id: globals.TargetAliasPrefix + "_somethinge",
|
|
Description: wrapperspb.String("new desc"),
|
|
},
|
|
},
|
|
res: nil,
|
|
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
|
},
|
|
{
|
|
name: "Cant use invalid host id",
|
|
req: &pbs.UpdateAliasRequest{
|
|
Id: og.GetPublicId(),
|
|
UpdateMask: &field_mask.FieldMask{
|
|
Paths: []string{"host_id"},
|
|
},
|
|
Item: &pb.Alias{
|
|
Description: wrapperspb.String("new desc"),
|
|
Attrs: &pb.Alias_TargetAliasAttributes{
|
|
&pb.TargetAliasAttributes{
|
|
AuthorizeSessionArguments: &pb.AuthorizeSessionArguments{
|
|
HostId: "badid_1234567890",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
res: nil,
|
|
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
|
},
|
|
{
|
|
name: "Update with static host id",
|
|
req: &pbs.UpdateAliasRequest{
|
|
Id: og.GetPublicId(),
|
|
UpdateMask: &field_mask.FieldMask{
|
|
Paths: []string{"attributes.authorize_session_arguments.host_id"},
|
|
},
|
|
Item: &pb.Alias{
|
|
Description: wrapperspb.String("new desc"),
|
|
Attrs: &pb.Alias_TargetAliasAttributes{
|
|
&pb.TargetAliasAttributes{
|
|
AuthorizeSessionArguments: &pb.AuthorizeSessionArguments{
|
|
HostId: "hst_1234567890",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
res: &pbs.UpdateAliasResponse{
|
|
Item: &pb.Alias{
|
|
Type: "target",
|
|
Id: og.GetPublicId(),
|
|
Name: wrapperspb.String("default"),
|
|
ScopeId: og.GetScopeId(),
|
|
Scope: globalScopeInfo,
|
|
Value: "default",
|
|
DestinationId: wrapperspb.String(tar.GetPublicId()),
|
|
Description: wrapperspb.String("default"),
|
|
CreatedTime: og.GetCreateTime().GetTimestamp(),
|
|
AuthorizedActions: testAuthorizedActions,
|
|
Attrs: &pb.Alias_TargetAliasAttributes{
|
|
&pb.TargetAliasAttributes{
|
|
AuthorizeSessionArguments: &pb.AuthorizeSessionArguments{
|
|
HostId: "hst_1234567890",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Update with dynamic host id",
|
|
req: &pbs.UpdateAliasRequest{
|
|
Id: og.GetPublicId(),
|
|
UpdateMask: &field_mask.FieldMask{
|
|
Paths: []string{"attributes.authorize_session_arguments.host_id"},
|
|
},
|
|
Item: &pb.Alias{
|
|
Description: wrapperspb.String("new desc"),
|
|
Attrs: &pb.Alias_TargetAliasAttributes{
|
|
&pb.TargetAliasAttributes{
|
|
AuthorizeSessionArguments: &pb.AuthorizeSessionArguments{
|
|
HostId: "hplg_1234567890",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
res: &pbs.UpdateAliasResponse{
|
|
Item: &pb.Alias{
|
|
Type: "target",
|
|
Id: og.GetPublicId(),
|
|
Name: wrapperspb.String("default"),
|
|
ScopeId: og.GetScopeId(),
|
|
Scope: globalScopeInfo,
|
|
Value: "default",
|
|
DestinationId: wrapperspb.String(tar.GetPublicId()),
|
|
Description: wrapperspb.String("default"),
|
|
CreatedTime: og.GetCreateTime().GetTimestamp(),
|
|
AuthorizedActions: testAuthorizedActions,
|
|
Attrs: &pb.Alias_TargetAliasAttributes{
|
|
&pb.TargetAliasAttributes{
|
|
AuthorizeSessionArguments: &pb.AuthorizeSessionArguments{
|
|
HostId: "hplg_1234567890",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Cant specify Created Time",
|
|
req: &pbs.UpdateAliasRequest{
|
|
UpdateMask: &field_mask.FieldMask{
|
|
Paths: []string{"created_time"},
|
|
},
|
|
Item: &pb.Alias{
|
|
CreatedTime: timestamppb.Now(),
|
|
},
|
|
},
|
|
res: nil,
|
|
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
|
},
|
|
{
|
|
name: "Cant specify Updated Time",
|
|
req: &pbs.UpdateAliasRequest{
|
|
UpdateMask: &field_mask.FieldMask{
|
|
Paths: []string{"updated_time"},
|
|
},
|
|
Item: &pb.Alias{
|
|
UpdatedTime: timestamppb.Now(),
|
|
},
|
|
},
|
|
res: nil,
|
|
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
|
},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
ver := ogVersion
|
|
tc.req.Item.Version = ver
|
|
|
|
assert, require := assert.New(t), require.New(t)
|
|
req := proto.Clone(toMerge).(*pbs.UpdateAliasRequest)
|
|
proto.Merge(req, tc.req)
|
|
|
|
// Test with bad version (too high, too low)
|
|
req.Item.Version = ver + 2
|
|
_, gErr := tested.UpdateAlias(auth.DisabledAuthTestContext(iamRepoFn, tc.scopeId), req)
|
|
require.Error(gErr)
|
|
req.Item.Version = ver - 1
|
|
_, gErr = tested.UpdateAlias(auth.DisabledAuthTestContext(iamRepoFn, tc.scopeId), req)
|
|
require.Error(gErr)
|
|
req.Item.Version = ver
|
|
|
|
got, gErr := tested.UpdateAlias(auth.DisabledAuthTestContext(iamRepoFn, tc.scopeId), req)
|
|
if tc.err != nil {
|
|
require.Error(gErr)
|
|
assert.True(errors.Is(gErr, tc.err), "UpdateAlias(%+v) got error %v, wanted %v", req, gErr, tc.err)
|
|
return
|
|
}
|
|
require.NoError(gErr)
|
|
defer resetAlias(got.GetItem().GetVersion())
|
|
|
|
assert.NotNilf(tc.res, "Expected UpdateAlias response to be nil, but was %v", got)
|
|
gotUpdateTime := got.GetItem().GetUpdatedTime().AsTime()
|
|
// Verify it is a alias updated after it was created
|
|
assert.True(gotUpdateTime.After(created), "Updated alias should have been updated after it's creation. Was updated %v, which is after %v", gotUpdateTime, created)
|
|
|
|
// Clear all values which are hard to compare against.
|
|
got.Item.UpdatedTime, tc.res.Item.UpdatedTime = nil, nil
|
|
|
|
assert.Equal(ver+1, got.GetItem().GetVersion())
|
|
tc.res.Item.Version = ver + 1
|
|
assert.Empty(cmp.Diff(
|
|
got,
|
|
tc.res,
|
|
protocmp.Transform(),
|
|
cmpopts.SortSlices(func(a, b string) bool {
|
|
return a < b
|
|
}),
|
|
), "UpdateAlias(%q) got response %q, wanted %q", req, got, tc.res)
|
|
})
|
|
}
|
|
}
|