diff --git a/internal/clientcache/cmd/search/search.go b/internal/clientcache/cmd/search/search.go index 0693b35f0f..e3a4ff5526 100644 --- a/internal/clientcache/cmd/search/search.go +++ b/internal/clientcache/cmd/search/search.go @@ -30,7 +30,7 @@ var ( _ cli.CommandAutocomplete = (*SearchCommand)(nil) supportedResourceTypes = []string{ - "aliases", + "resolvable-aliases", "targets", "sessions", } @@ -165,8 +165,8 @@ func (c *SearchCommand) Run(args []string) int { } default: switch { - case len(result.Aliases) > 0: - c.UI.Output(printAliasListTable(result.Aliases)) + case len(result.ResolvableAliases) > 0: + c.UI.Output(printAliasListTable(result.ResolvableAliases)) case len(result.Targets) > 0: c.UI.Output(printTargetListTable(result.Targets)) case len(result.Sessions) > 0: @@ -247,12 +247,12 @@ func search(ctx context.Context, daemonPath string, fb filterBy, opt ...client.O func printAliasListTable(items []*aliases.Alias) string { if len(items) == 0 { - return "No aliases found" + return "No resolvable aliases found" } var output []string output = []string{ "", - "Alias information:", + "Resolvable Alias information:", } for i, item := range items { if i > 0 { @@ -267,11 +267,6 @@ func printAliasListTable(items []*aliases.Alias) string { fmt.Sprintf(" ID: %s", "(not available)"), ) } - if item.ScopeId != "" { - output = append(output, - fmt.Sprintf(" Scope ID: %s", item.ScopeId), - ) - } if item.Version > 0 { output = append(output, fmt.Sprintf(" Version: %d", item.Version), @@ -282,16 +277,6 @@ func printAliasListTable(items []*aliases.Alias) string { fmt.Sprintf(" Type: %s", item.Type), ) } - if item.Name != "" { - output = append(output, - fmt.Sprintf(" Name: %s", item.Name), - ) - } - if item.Description != "" { - output = append(output, - fmt.Sprintf(" Description: %s", item.Description), - ) - } if item.DestinationId != "" { output = append(output, fmt.Sprintf(" DestinationId: %s", item.DestinationId), @@ -302,12 +287,6 @@ func printAliasListTable(items []*aliases.Alias) string { fmt.Sprintf(" Value: %s", item.Value), ) } - if len(item.AuthorizedActions) > 0 { - output = append(output, - " Authorized Actions:", - base.WrapSlice(6, item.AuthorizedActions), - ) - } } return base.WrapForHelpText(output) diff --git a/internal/clientcache/internal/cache/options.go b/internal/clientcache/internal/cache/options.go index dd0f32dea9..6f68ebcea3 100644 --- a/internal/clientcache/internal/cache/options.go +++ b/internal/clientcache/internal/cache/options.go @@ -8,14 +8,14 @@ import ( ) type options struct { - withUpdateLastAccessedTime bool - withDbType dbw.DbType - withAuthTokenId string - withUserId string - withAliasRetrievalFunc AliasRetrievalFunc - withTargetRetrievalFunc TargetRetrievalFunc - withSessionRetrievalFunc SessionRetrievalFunc - withIgnoreSearchStaleness bool + withUpdateLastAccessedTime bool + withDbType dbw.DbType + withAuthTokenId string + withUserId string + withResolvableAliasRetrievalFunc ResolvableAliasRetrievalFunc + withTargetRetrievalFunc TargetRetrievalFunc + withSessionRetrievalFunc SessionRetrievalFunc + withIgnoreSearchStaleness bool } // Option - how options are passed as args @@ -63,9 +63,9 @@ func withUserId(id string) Option { } // WithAliasRetrievalFunc provides an option for specifying an aliasRetrievalFunc -func WithAliasRetrievalFunc(fn AliasRetrievalFunc) Option { +func WithAliasRetrievalFunc(fn ResolvableAliasRetrievalFunc) Option { return func(o *options) error { - o.withAliasRetrievalFunc = fn + o.withResolvableAliasRetrievalFunc = fn return nil } } diff --git a/internal/clientcache/internal/cache/options_test.go b/internal/clientcache/internal/cache/options_test.go index 7c0a7e7fa3..2475356203 100644 --- a/internal/clientcache/internal/cache/options_test.go +++ b/internal/clientcache/internal/cache/options_test.go @@ -74,14 +74,14 @@ func Test_GetOpts(t *testing.T) { assert.Equal(t, opts, testOpts) }) t.Run("WithAliasRetrievalFunc", func(t *testing.T) { - var f AliasRetrievalFunc = func(ctx context.Context, addr, authTok string, refreshTok RefreshTokenValue) ([]*aliases.Alias, []string, RefreshTokenValue, error) { + var f ResolvableAliasRetrievalFunc = func(ctx context.Context, addr, authTok, userId string, refreshTok RefreshTokenValue) ([]*aliases.Alias, []string, RefreshTokenValue, error) { return nil, nil, "", nil } opts, err := getOpts(WithAliasRetrievalFunc(f)) require.NoError(t, err) - assert.NotNil(t, opts.withAliasRetrievalFunc) - opts.withAliasRetrievalFunc = nil + assert.NotNil(t, opts.withResolvableAliasRetrievalFunc) + opts.withResolvableAliasRetrievalFunc = nil testOpts := getDefaultOptions() assert.Equal(t, opts, testOpts) diff --git a/internal/clientcache/internal/cache/refresh.go b/internal/clientcache/internal/cache/refresh.go index 5f223192e6..002e7ce8f7 100644 --- a/internal/clientcache/internal/cache/refresh.go +++ b/internal/clientcache/internal/cache/refresh.go @@ -197,8 +197,8 @@ func (r *RefreshService) RefreshForSearch(ctx context.Context, authTokenid strin } switch resourceType { - case Aliases: - rtv, err := r.repo.lookupRefreshToken(ctx, u, aliasResourceType) + case ResolvableAliases: + rtv, err := r.repo.lookupRefreshToken(ctx, u, resolvableAliasResourceType) if err != nil { return errors.Wrap(ctx, err, op) } @@ -208,7 +208,7 @@ func (r *RefreshService) RefreshForSearch(ctx context.Context, authTokenid strin args = append(args, "alias staleness", time.Since(rtv.UpdateTime)) } r.logger.Debug("refreshing aliases before performing search", args...) - if err := r.repo.refreshAliases(ctx, u, tokens, opt...); err != nil { + if err := r.repo.refreshResolvableAliases(ctx, u, tokens, opt...); err != nil { return errors.Wrap(ctx, err, op) } } @@ -283,7 +283,7 @@ func (r *RefreshService) Refresh(ctx context.Context, opt ...Option) error { continue } - if err := r.repo.refreshAliases(ctx, u, tokens, opt...); err != nil { + if err := r.repo.refreshResolvableAliases(ctx, u, tokens, opt...); err != nil { retErr = stderrors.Join(retErr, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("for user id %s", u.Id)))) } if err := r.repo.refreshTargets(ctx, u, tokens, opt...); err != nil { @@ -353,7 +353,7 @@ func (r *RefreshService) RecheckCachingSupport(ctx context.Context, opt ...Optio } retErr = stderrors.Join(retErr, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("for user id %s", u.Id)))) } - if err := r.repo.checkCachingAliases(ctx, u, tokens, opt...); err != nil { + if err := r.repo.checkCachingResolvableAliases(ctx, u, tokens, opt...); err != nil { if err == ErrRefreshNotSupported { // This is expected so no need to propagate the error up continue diff --git a/internal/clientcache/internal/cache/refresh_test.go b/internal/clientcache/internal/cache/refresh_test.go index f86d8d69e5..f7c0c003aa 100644 --- a/internal/clientcache/internal/cache/refresh_test.go +++ b/internal/clientcache/internal/cache/refresh_test.go @@ -74,6 +74,62 @@ func testErroringForRefreshTokenRetrievalFunc[T any](t *testing.T, ret []T) func } } +// testStaticResourceRetrievalFunc returns a function that always returns the +// provided slice and a nil error. The returned function can be passed into the +// options that provide a resource retrieval func such as +// WithTargetRetrievalFunc and WithSessionRetrievalFunc. The provided refresh +// token determines the returned value and is a string representation of an +// incrementing integer. This integer is the index into the provided return +// values and once it reaches the length of the provided slice it returns an +// empty slice and the same refresh token repeatedly. This is for retrieval +// functions that require an id be provided for listing purposes like when +// listing resolvable aliases. +func testStaticResourceRetrievalFuncForId[T any](t *testing.T, ret [][]T, removed [][]string) func(context.Context, string, string, string, RefreshTokenValue) ([]T, []string, RefreshTokenValue, error) { + t.Helper() + require.Equal(t, len(ret), len(removed), "returned slice and removed slice must be the same length") + return func(ctx context.Context, s1, s2, s3 string, refToken RefreshTokenValue) ([]T, []string, RefreshTokenValue, error) { + index := 0 + if refToken != "" { + var err error + index, err = strconv.Atoi(string(refToken)) + require.NoError(t, err) + } + + switch { + case len(ret) == 0: + return nil, nil, "", nil + case index > 0 && index >= len(ret): + return []T{}, []string{}, RefreshTokenValue(fmt.Sprintf("%d", index)), nil + default: + return ret[index], removed[index], RefreshTokenValue(fmt.Sprintf("%d", index+1)), nil + } + } +} + +// testNoRefreshRetrievalFunc simulates a controller that doesn't support refresh +// since it does not return any refresh token. This is for retrieval +// functions that require an id be provided for listing purposes like when +// listing resolvable aliases. +func testNoRefreshRetrievalFuncForId[T any](t *testing.T) func(context.Context, string, string, string, RefreshTokenValue) ([]T, []string, RefreshTokenValue, error) { + return func(_ context.Context, _, _, _ string, _ RefreshTokenValue) ([]T, []string, RefreshTokenValue, error) { + return nil, nil, "", ErrRefreshNotSupported + } +} + +// testErroringForRefreshTokenRetrievalFuncForId returns a refresh token error when +// the refresh token is not empty. This is useful for testing behavior when +// the refresh token has expired or is otherwise invalid. This is for retrieval +// functions that require an id be provided for listing purposes like when +// listing resolvable aliases. +func testErroringForRefreshTokenRetrievalFuncForId[T any](t *testing.T, ret []T) func(context.Context, string, string, string, RefreshTokenValue) ([]T, []string, RefreshTokenValue, error) { + return func(ctx context.Context, s1, s2, s3 string, refToken RefreshTokenValue) ([]T, []string, RefreshTokenValue, error) { + if refToken != "" { + return nil, nil, "", api.ErrInvalidListToken + } + return ret, nil, "1", nil + } +} + func TestCleanAndPickTokens(t *testing.T) { ctx := context.Background() s, err := db.Open(ctx) @@ -368,7 +424,7 @@ func TestRefreshForSearch(t *testing.T) { target("4"), } opts := []Option{ - WithAliasRetrievalFunc(testStaticResourceRetrievalFunc[*aliases.Alias](t, nil, nil)), + WithAliasRetrievalFunc(testStaticResourceRetrievalFuncForId[*aliases.Alias](t, nil, nil)), WithSessionRetrievalFunc(testStaticResourceRetrievalFunc[*sessions.Session](t, nil, nil)), WithTargetRetrievalFunc(testStaticResourceRetrievalFunc[*targets.Target](t, [][]*targets.Target{ @@ -420,7 +476,7 @@ func TestRefreshForSearch(t *testing.T) { target("4"), } opts := []Option{ - WithAliasRetrievalFunc(testStaticResourceRetrievalFunc[*aliases.Alias](t, nil, nil)), + WithAliasRetrievalFunc(testStaticResourceRetrievalFuncForId[*aliases.Alias](t, nil, nil)), WithSessionRetrievalFunc(testStaticResourceRetrievalFunc[*sessions.Session](t, nil, nil)), WithTargetRetrievalFunc(testStaticResourceRetrievalFunc[*targets.Target](t, [][]*targets.Target{ @@ -475,7 +531,7 @@ func TestRefreshForSearch(t *testing.T) { // Get the first set of resources, but no refresh tokens err = rs.Refresh(ctx, - WithAliasRetrievalFunc(testStaticResourceRetrievalFunc[*aliases.Alias](t, nil, nil)), + WithAliasRetrievalFunc(testStaticResourceRetrievalFuncForId[*aliases.Alias](t, nil, nil)), WithSessionRetrievalFunc(testNoRefreshRetrievalFunc[*sessions.Session](t)), WithTargetRetrievalFunc(testNoRefreshRetrievalFunc[*targets.Target](t))) assert.ErrorContains(t, err, ErrRefreshNotSupported.Error()) @@ -488,13 +544,13 @@ func TestRefreshForSearch(t *testing.T) { // wont be refreshed any more, and we wont see the error when refreshing // any more. err = rs.Refresh(ctx, - WithAliasRetrievalFunc(testNoRefreshRetrievalFunc[*aliases.Alias](t)), + WithAliasRetrievalFunc(testNoRefreshRetrievalFuncForId[*aliases.Alias](t)), WithSessionRetrievalFunc(testNoRefreshRetrievalFunc[*sessions.Session](t)), WithTargetRetrievalFunc(testNoRefreshRetrievalFunc[*targets.Target](t))) assert.Nil(t, err) err = rs.RecheckCachingSupport(ctx, - WithAliasRetrievalFunc(testNoRefreshRetrievalFunc[*aliases.Alias](t)), + WithAliasRetrievalFunc(testNoRefreshRetrievalFuncForId[*aliases.Alias](t)), WithSessionRetrievalFunc(testNoRefreshRetrievalFunc[*sessions.Session](t)), WithTargetRetrievalFunc(testNoRefreshRetrievalFunc[*targets.Target](t))) assert.Nil(t, err) @@ -506,7 +562,7 @@ func TestRefreshForSearch(t *testing.T) { // Now simulate the controller updating to support refresh tokens and // the resources starting to be cached. err = rs.RecheckCachingSupport(ctx, - WithAliasRetrievalFunc(testStaticResourceRetrievalFunc[*aliases.Alias](t, nil, nil)), + WithAliasRetrievalFunc(testStaticResourceRetrievalFuncForId[*aliases.Alias](t, nil, nil)), WithSessionRetrievalFunc(testStaticResourceRetrievalFunc[*sessions.Session](t, nil, nil)), WithTargetRetrievalFunc(testStaticResourceRetrievalFunc[*targets.Target](t, [][]*targets.Target{retTargets}, [][]string{{}}))) assert.Nil(t, err, err) @@ -532,7 +588,7 @@ func TestRefreshForSearch(t *testing.T) { session("4"), } opts := []Option{ - WithAliasRetrievalFunc(testStaticResourceRetrievalFunc[*aliases.Alias](t, nil, nil)), + WithAliasRetrievalFunc(testStaticResourceRetrievalFuncForId[*aliases.Alias](t, nil, nil)), WithTargetRetrievalFunc(testStaticResourceRetrievalFunc[*targets.Target](t, nil, nil)), WithSessionRetrievalFunc(testStaticResourceRetrievalFunc[*sessions.Session](t, [][]*sessions.Session{ @@ -581,7 +637,7 @@ func TestRefreshForSearch(t *testing.T) { session("4"), } opts := []Option{ - WithAliasRetrievalFunc(testStaticResourceRetrievalFunc[*aliases.Alias](t, nil, nil)), + WithAliasRetrievalFunc(testStaticResourceRetrievalFuncForId[*aliases.Alias](t, nil, nil)), WithTargetRetrievalFunc(testStaticResourceRetrievalFunc[*targets.Target](t, nil, nil)), WithSessionRetrievalFunc(testStaticResourceRetrievalFunc[*sessions.Session](t, [][]*sessions.Session{ @@ -637,7 +693,7 @@ func TestRefreshForSearch(t *testing.T) { opts := []Option{ WithSessionRetrievalFunc(testStaticResourceRetrievalFunc[*sessions.Session](t, nil, nil)), WithTargetRetrievalFunc(testStaticResourceRetrievalFunc[*targets.Target](t, nil, nil)), - WithAliasRetrievalFunc(testStaticResourceRetrievalFunc[*aliases.Alias](t, + WithAliasRetrievalFunc(testStaticResourceRetrievalFuncForId[*aliases.Alias](t, [][]*aliases.Alias{ retAl[:3], retAl[3:], @@ -650,19 +706,19 @@ func TestRefreshForSearch(t *testing.T) { } // First call doesn't sync anything because no aliases were already synced yet - assert.NoError(t, rs.RefreshForSearch(ctx, at.Id, Aliases, opts...)) - cachedAliases, err := r.ListAliases(ctx, at.Id) + assert.NoError(t, rs.RefreshForSearch(ctx, at.Id, ResolvableAliases, opts...)) + cachedAliases, err := r.ListResolvableAliases(ctx, at.Id) assert.NoError(t, err) assert.Empty(t, cachedAliases) assert.NoError(t, rs.Refresh(ctx, opts...)) - cachedAliases, err = r.ListAliases(ctx, at.Id) + cachedAliases, err = r.ListResolvableAliases(ctx, at.Id) assert.NoError(t, err) assert.ElementsMatch(t, retAl[:3], cachedAliases) // Second call removes the first 2 resources from the cache and adds the last - assert.NoError(t, rs.RefreshForSearch(ctx, at.Id, Aliases, opts...)) - cachedAliases, err = r.ListAliases(ctx, at.Id) + assert.NoError(t, rs.RefreshForSearch(ctx, at.Id, ResolvableAliases, opts...)) + cachedAliases, err = r.ListResolvableAliases(ctx, at.Id) assert.NoError(t, err) assert.ElementsMatch(t, retAl[2:], cachedAliases) }) @@ -686,7 +742,7 @@ func TestRefreshForSearch(t *testing.T) { opts := []Option{ WithSessionRetrievalFunc(testStaticResourceRetrievalFunc[*sessions.Session](t, nil, nil)), WithTargetRetrievalFunc(testStaticResourceRetrievalFunc[*targets.Target](t, nil, nil)), - WithAliasRetrievalFunc(testStaticResourceRetrievalFunc[*aliases.Alias](t, + WithAliasRetrievalFunc(testStaticResourceRetrievalFuncForId[*aliases.Alias](t, [][]*aliases.Alias{ retAls[:3], retAls[3:], @@ -699,25 +755,25 @@ func TestRefreshForSearch(t *testing.T) { } // First call doesn't sync anything because no aliases were already synced yet - assert.NoError(t, rs.RefreshForSearch(ctx, at.Id, Aliases, opts...)) - cachedAliases, err := r.ListAliases(ctx, at.Id) + assert.NoError(t, rs.RefreshForSearch(ctx, at.Id, ResolvableAliases, opts...)) + cachedAliases, err := r.ListResolvableAliases(ctx, at.Id) assert.NoError(t, err) assert.Empty(t, cachedAliases) assert.NoError(t, rs.Refresh(ctx, opts...)) - cachedAliases, err = r.ListAliases(ctx, at.Id) + cachedAliases, err = r.ListResolvableAliases(ctx, at.Id) assert.NoError(t, err) assert.ElementsMatch(t, retAls[:3], cachedAliases) // Refresh for search doesn't refresh anything because it isn't stale - assert.NoError(t, rs.RefreshForSearch(ctx, at.Id, Aliases, opts...)) - cachedAliases, err = r.ListAliases(ctx, at.Id) + assert.NoError(t, rs.RefreshForSearch(ctx, at.Id, ResolvableAliases, opts...)) + cachedAliases, err = r.ListResolvableAliases(ctx, at.Id) assert.NoError(t, err) assert.ElementsMatch(t, retAls[:3], cachedAliases) // Now force the refresh and see things get updated - assert.NoError(t, rs.RefreshForSearch(ctx, at.Id, Aliases, append(opts, WithIgnoreSearchStaleness(true))...)) - cachedAliases, err = r.ListAliases(ctx, at.Id) + assert.NoError(t, rs.RefreshForSearch(ctx, at.Id, ResolvableAliases, append(opts, WithIgnoreSearchStaleness(true))...)) + cachedAliases, err = r.ListResolvableAliases(ctx, at.Id) assert.NoError(t, err) assert.ElementsMatch(t, retAls[2:], cachedAliases) }) @@ -756,7 +812,7 @@ func TestRefresh(t *testing.T) { target("4"), } opts := []Option{ - WithAliasRetrievalFunc(testStaticResourceRetrievalFunc[*aliases.Alias](t, nil, nil)), + WithAliasRetrievalFunc(testStaticResourceRetrievalFuncForId[*aliases.Alias](t, nil, nil)), WithSessionRetrievalFunc(testStaticResourceRetrievalFunc[*sessions.Session](t, nil, nil)), WithTargetRetrievalFunc(testStaticResourceRetrievalFunc[*targets.Target](t, [][]*targets.Target{ @@ -798,7 +854,7 @@ func TestRefresh(t *testing.T) { session("4"), } opts := []Option{ - WithAliasRetrievalFunc(testStaticResourceRetrievalFunc[*aliases.Alias](t, nil, nil)), + WithAliasRetrievalFunc(testStaticResourceRetrievalFuncForId[*aliases.Alias](t, nil, nil)), WithTargetRetrievalFunc(testStaticResourceRetrievalFunc[*targets.Target](t, nil, nil)), WithSessionRetrievalFunc(testStaticResourceRetrievalFunc[*sessions.Session](t, [][]*sessions.Session{ @@ -841,7 +897,7 @@ func TestRefresh(t *testing.T) { opts := []Option{ WithSessionRetrievalFunc(testStaticResourceRetrievalFunc[*sessions.Session](t, nil, nil)), WithTargetRetrievalFunc(testStaticResourceRetrievalFunc[*targets.Target](t, nil, nil)), - WithAliasRetrievalFunc(testStaticResourceRetrievalFunc[*aliases.Alias](t, + WithAliasRetrievalFunc(testStaticResourceRetrievalFuncForId[*aliases.Alias](t, [][]*aliases.Alias{ retAls[:3], retAls[3:], @@ -853,13 +909,13 @@ func TestRefresh(t *testing.T) { )), } assert.NoError(t, rs.Refresh(ctx, opts...)) - cachedAliases, err := r.ListAliases(ctx, at.Id) + cachedAliases, err := r.ListResolvableAliases(ctx, at.Id) assert.NoError(t, err) assert.ElementsMatch(t, retAls[:3], cachedAliases) // Second call removes the first 2 resources from the cache and adds the last assert.NoError(t, rs.Refresh(ctx, opts...)) - cachedAliases, err = r.ListAliases(ctx, at.Id) + cachedAliases, err = r.ListResolvableAliases(ctx, at.Id) assert.NoError(t, err) assert.ElementsMatch(t, retAls[2:], cachedAliases) }) @@ -875,7 +931,7 @@ func TestRefresh(t *testing.T) { innerErr := errors.New("test error") err = rs.Refresh(ctx, - WithAliasRetrievalFunc(testStaticResourceRetrievalFunc[*aliases.Alias](t, nil, nil)), + WithAliasRetrievalFunc(testStaticResourceRetrievalFuncForId[*aliases.Alias](t, nil, nil)), WithSessionRetrievalFunc(testStaticResourceRetrievalFunc[*sessions.Session](t, nil, nil)), WithTargetRetrievalFunc(func(ctx context.Context, addr, token string, refreshTok RefreshTokenValue) ([]*targets.Target, []string, RefreshTokenValue, error) { require.Equal(t, boundaryAddr, addr) @@ -884,7 +940,7 @@ func TestRefresh(t *testing.T) { })) assert.ErrorContains(t, err, innerErr.Error()) err = rs.Refresh(ctx, - WithAliasRetrievalFunc(testStaticResourceRetrievalFunc[*aliases.Alias](t, nil, nil)), + WithAliasRetrievalFunc(testStaticResourceRetrievalFuncForId[*aliases.Alias](t, nil, nil)), WithTargetRetrievalFunc(testStaticResourceRetrievalFunc[*targets.Target](t, nil, nil)), WithSessionRetrievalFunc(func(ctx context.Context, addr, token string, refreshTok RefreshTokenValue) ([]*sessions.Session, []string, RefreshTokenValue, error) { require.Equal(t, boundaryAddr, addr) @@ -917,7 +973,7 @@ func TestRefresh(t *testing.T) { assert.Len(t, us, 1) require.NoError(t, rs.Refresh(ctx, - WithAliasRetrievalFunc(testStaticResourceRetrievalFunc[*aliases.Alias](t, nil, nil)), + WithAliasRetrievalFunc(testStaticResourceRetrievalFuncForId[*aliases.Alias](t, nil, nil)), WithSessionRetrievalFunc(testStaticResourceRetrievalFunc[*sessions.Session](t, nil, nil)), WithTargetRetrievalFunc(testStaticResourceRetrievalFunc[*targets.Target](t, nil, nil)))) @@ -961,7 +1017,7 @@ func TestRecheckCachingSupport(t *testing.T) { // Since this user doesn't have any resources, the user's data will still // only get updated with a call to Refresh. assert.NoError(t, rs.RecheckCachingSupport(ctx, - WithAliasRetrievalFunc(testNoRefreshRetrievalFunc[*aliases.Alias](t)), + WithAliasRetrievalFunc(testNoRefreshRetrievalFuncForId[*aliases.Alias](t)), WithSessionRetrievalFunc(testNoRefreshRetrievalFunc[*sessions.Session](t)), WithTargetRetrievalFunc(testNoRefreshRetrievalFunc[*targets.Target](t)))) @@ -970,7 +1026,7 @@ func TestRecheckCachingSupport(t *testing.T) { assert.Empty(t, got) err = rs.Refresh(ctx, - WithAliasRetrievalFunc(testNoRefreshRetrievalFunc[*aliases.Alias](t)), + WithAliasRetrievalFunc(testNoRefreshRetrievalFuncForId[*aliases.Alias](t)), WithSessionRetrievalFunc(testNoRefreshRetrievalFunc[*sessions.Session](t)), WithTargetRetrievalFunc(testNoRefreshRetrievalFunc[*targets.Target](t))) assert.ErrorIs(t, err, ErrRefreshNotSupported) @@ -981,7 +1037,7 @@ func TestRecheckCachingSupport(t *testing.T) { // now a full fetch will work since the user has resources and no refresh token assert.NoError(t, rs.RecheckCachingSupport(ctx, - WithAliasRetrievalFunc(testNoRefreshRetrievalFunc[*aliases.Alias](t)), + WithAliasRetrievalFunc(testNoRefreshRetrievalFuncForId[*aliases.Alias](t)), WithSessionRetrievalFunc(testNoRefreshRetrievalFunc[*sessions.Session](t)), WithTargetRetrievalFunc(testNoRefreshRetrievalFunc[*targets.Target](t)))) }) @@ -996,7 +1052,7 @@ func TestRecheckCachingSupport(t *testing.T) { require.NoError(t, r.AddKeyringToken(ctx, boundaryAddr, KeyringToken{KeyringType: "k", TokenName: "t", AuthTokenId: at.Id})) assert.NoError(t, rs.RecheckCachingSupport(ctx, - WithAliasRetrievalFunc(testNoRefreshRetrievalFunc[*aliases.Alias](t)), + WithAliasRetrievalFunc(testNoRefreshRetrievalFuncForId[*aliases.Alias](t)), WithTargetRetrievalFunc(testNoRefreshRetrievalFunc[*targets.Target](t)), WithSessionRetrievalFunc(testNoRefreshRetrievalFunc[*sessions.Session](t)))) @@ -1005,7 +1061,7 @@ func TestRecheckCachingSupport(t *testing.T) { assert.Empty(t, got) err = rs.Refresh(ctx, - WithAliasRetrievalFunc(testNoRefreshRetrievalFunc[*aliases.Alias](t)), + WithAliasRetrievalFunc(testNoRefreshRetrievalFuncForId[*aliases.Alias](t)), WithTargetRetrievalFunc(testNoRefreshRetrievalFunc[*targets.Target](t)), WithSessionRetrievalFunc(testNoRefreshRetrievalFunc[*sessions.Session](t))) assert.ErrorIs(t, err, ErrRefreshNotSupported) @@ -1015,7 +1071,7 @@ func TestRecheckCachingSupport(t *testing.T) { assert.Empty(t, got) assert.NoError(t, rs.RecheckCachingSupport(ctx, - WithAliasRetrievalFunc(testNoRefreshRetrievalFunc[*aliases.Alias](t)), + WithAliasRetrievalFunc(testNoRefreshRetrievalFuncForId[*aliases.Alias](t)), WithTargetRetrievalFunc(testNoRefreshRetrievalFunc[*targets.Target](t)), WithSessionRetrievalFunc(testNoRefreshRetrievalFunc[*sessions.Session](t)))) got, err = r.ListSessions(ctx, at.Id) @@ -1033,29 +1089,29 @@ func TestRecheckCachingSupport(t *testing.T) { require.NoError(t, r.AddKeyringToken(ctx, boundaryAddr, KeyringToken{KeyringType: "k", TokenName: "t", AuthTokenId: at.Id})) assert.NoError(t, rs.RecheckCachingSupport(ctx, - WithAliasRetrievalFunc(testNoRefreshRetrievalFunc[*aliases.Alias](t)), + WithAliasRetrievalFunc(testNoRefreshRetrievalFuncForId[*aliases.Alias](t)), WithTargetRetrievalFunc(testNoRefreshRetrievalFunc[*targets.Target](t)), WithSessionRetrievalFunc(testNoRefreshRetrievalFunc[*sessions.Session](t)))) - got, err := r.ListAliases(ctx, at.Id) + got, err := r.ListResolvableAliases(ctx, at.Id) assert.NoError(t, err) assert.Empty(t, got) err = rs.Refresh(ctx, - WithAliasRetrievalFunc(testNoRefreshRetrievalFunc[*aliases.Alias](t)), + WithAliasRetrievalFunc(testNoRefreshRetrievalFuncForId[*aliases.Alias](t)), WithTargetRetrievalFunc(testNoRefreshRetrievalFunc[*targets.Target](t)), WithSessionRetrievalFunc(testNoRefreshRetrievalFunc[*sessions.Session](t))) assert.ErrorIs(t, err, ErrRefreshNotSupported) - got, err = r.ListAliases(ctx, at.Id) + got, err = r.ListResolvableAliases(ctx, at.Id) assert.NoError(t, err) assert.Empty(t, got) assert.NoError(t, rs.RecheckCachingSupport(ctx, - WithAliasRetrievalFunc(testNoRefreshRetrievalFunc[*aliases.Alias](t)), + WithAliasRetrievalFunc(testNoRefreshRetrievalFuncForId[*aliases.Alias](t)), WithTargetRetrievalFunc(testNoRefreshRetrievalFunc[*targets.Target](t)), WithSessionRetrievalFunc(testNoRefreshRetrievalFunc[*sessions.Session](t)))) - got, err = r.ListAliases(ctx, at.Id) + got, err = r.ListResolvableAliases(ctx, at.Id) assert.NoError(t, err) assert.Empty(t, got) }) @@ -1070,14 +1126,14 @@ func TestRecheckCachingSupport(t *testing.T) { require.NoError(t, r.AddKeyringToken(ctx, boundaryAddr, KeyringToken{KeyringType: "k", TokenName: "t", AuthTokenId: at.Id})) err = rs.Refresh(ctx, - WithAliasRetrievalFunc(testNoRefreshRetrievalFunc[*aliases.Alias](t)), + WithAliasRetrievalFunc(testNoRefreshRetrievalFuncForId[*aliases.Alias](t)), WithTargetRetrievalFunc(testNoRefreshRetrievalFunc[*targets.Target](t)), WithSessionRetrievalFunc(testNoRefreshRetrievalFunc[*sessions.Session](t))) assert.ErrorIs(t, err, ErrRefreshNotSupported) innerErr := errors.New("test error") err = rs.RecheckCachingSupport(ctx, - WithAliasRetrievalFunc(testNoRefreshRetrievalFunc[*aliases.Alias](t)), + WithAliasRetrievalFunc(testNoRefreshRetrievalFuncForId[*aliases.Alias](t)), WithSessionRetrievalFunc(testNoRefreshRetrievalFunc[*sessions.Session](t)), WithTargetRetrievalFunc(func(ctx context.Context, addr, token string, refreshTok RefreshTokenValue) ([]*targets.Target, []string, RefreshTokenValue, error) { require.Equal(t, boundaryAddr, addr) @@ -1087,7 +1143,7 @@ func TestRecheckCachingSupport(t *testing.T) { assert.ErrorContains(t, err, innerErr.Error()) err = rs.RecheckCachingSupport(ctx, - WithAliasRetrievalFunc(testNoRefreshRetrievalFunc[*aliases.Alias](t)), + WithAliasRetrievalFunc(testNoRefreshRetrievalFuncForId[*aliases.Alias](t)), WithSessionRetrievalFunc(testNoRefreshRetrievalFunc[*sessions.Session](t)), WithTargetRetrievalFunc(func(ctx context.Context, addr, token string, refreshTok RefreshTokenValue) ([]*targets.Target, []string, RefreshTokenValue, error) { require.Equal(t, boundaryAddr, addr) @@ -1107,7 +1163,7 @@ func TestRecheckCachingSupport(t *testing.T) { require.NoError(t, r.AddKeyringToken(ctx, boundaryAddr, KeyringToken{KeyringType: "k", TokenName: "t", AuthTokenId: at.Id})) err = rs.Refresh(ctx, - WithAliasRetrievalFunc(testNoRefreshRetrievalFunc[*aliases.Alias](t)), + WithAliasRetrievalFunc(testNoRefreshRetrievalFuncForId[*aliases.Alias](t)), WithTargetRetrievalFunc(testNoRefreshRetrievalFunc[*targets.Target](t)), WithSessionRetrievalFunc(testNoRefreshRetrievalFunc[*sessions.Session](t))) assert.ErrorIs(t, err, ErrRefreshNotSupported) @@ -1126,7 +1182,7 @@ func TestRecheckCachingSupport(t *testing.T) { assert.Len(t, us, 1) err = rs.RecheckCachingSupport(ctx, - WithAliasRetrievalFunc(testNoRefreshRetrievalFunc[*aliases.Alias](t)), + WithAliasRetrievalFunc(testNoRefreshRetrievalFuncForId[*aliases.Alias](t)), WithSessionRetrievalFunc(testNoRefreshRetrievalFunc[*sessions.Session](t)), WithTargetRetrievalFunc(testNoRefreshRetrievalFunc[*targets.Target](t))) assert.NoError(t, err) diff --git a/internal/clientcache/internal/cache/repository_refresh_token.go b/internal/clientcache/internal/cache/repository_refresh_token.go index c773cca03d..ed7feaf934 100644 --- a/internal/clientcache/internal/cache/repository_refresh_token.go +++ b/internal/clientcache/internal/cache/repository_refresh_token.go @@ -218,15 +218,24 @@ func upsertRefreshToken(ctx context.Context, writer db.Writer, u *user, rt resou type resourceType string const ( - unknownResourceType resourceType = "unknown" - targetResourceType resourceType = "target" - sessionResourceType resourceType = "session" - aliasResourceType resourceType = "alias" + unknownResourceType resourceType = "unknown" + targetResourceType resourceType = "target" + sessionResourceType resourceType = "session" + resolvableAliasResourceType resourceType = "resolvable-alias" ) +func (r resourceType) ColumnName() string { + switch r { + case resolvableAliasResourceType: + return "resolvable_alias" + default: + return string(r) + } +} + func (r resourceType) valid() bool { switch r { - case aliasResourceType, targetResourceType, sessionResourceType: + case resolvableAliasResourceType, targetResourceType, sessionResourceType: return true } return false diff --git a/internal/clientcache/internal/cache/repository_aliases.go b/internal/clientcache/internal/cache/repository_resolvable_aliases.go similarity index 65% rename from internal/clientcache/internal/cache/repository_aliases.go rename to internal/clientcache/internal/cache/repository_resolvable_aliases.go index 5f5ddb215c..3b17b93817 100644 --- a/internal/clientcache/internal/cache/repository_aliases.go +++ b/internal/clientcache/internal/cache/repository_resolvable_aliases.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/boundary/api" "github.com/hashicorp/boundary/api/aliases" + "github.com/hashicorp/boundary/api/users" "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/event" @@ -19,12 +20,12 @@ import ( "github.com/hashicorp/mql" ) -// AliasRetrievalFunc is a function that retrieves aliases +// ResolvableAliasRetrievalFunc is a function that retrieves aliases // from the provided boundary addr using the provided token. -type AliasRetrievalFunc func(ctx context.Context, addr, authTok string, refreshTok RefreshTokenValue) (ret []*aliases.Alias, removedIds []string, refreshToken RefreshTokenValue, err error) +type ResolvableAliasRetrievalFunc func(ctx context.Context, addr, authTok, userId string, refreshTok RefreshTokenValue) (ret []*aliases.Alias, removedIds []string, refreshToken RefreshTokenValue, err error) -func defaultAliasFunc(ctx context.Context, addr, authTok string, refreshTok RefreshTokenValue) ([]*aliases.Alias, []string, RefreshTokenValue, error) { - const op = "cache.defaultAliasFunc" +func defaultResolvableAliasFunc(ctx context.Context, addr, authTok, userId string, refreshTok RefreshTokenValue) ([]*aliases.Alias, []string, RefreshTokenValue, error) { + const op = "cache.defaultResolvableAliasFunc" client, err := api.NewClient(&api.Config{ Addr: addr, Token: authTok, @@ -32,8 +33,8 @@ func defaultAliasFunc(ctx context.Context, addr, authTok string, refreshTok Refr if err != nil { return nil, nil, "", errors.Wrap(ctx, err, op) } - aClient := aliases.NewClient(client) - l, err := aClient.List(ctx, "global", aliases.WithRecursive(true), aliases.WithListToken(string(refreshTok))) + aClient := users.NewClient(client) + l, err := aClient.ListResolvableAliases(ctx, userId, users.WithListToken(string(refreshTok))) if err != nil { if api.ErrInvalidListToken.Is(err) { return nil, nil, "", err @@ -46,11 +47,11 @@ func defaultAliasFunc(ctx context.Context, addr, authTok string, refreshTok Refr return l.Items, l.RemovedIds, RefreshTokenValue(l.ListToken), nil } -// refreshAliases attempts to refresh the aliases for the provided user -// using the provided tokens. If available, it uses the refresh tokens in -// storage to retrieve and apply only the delta. -func (r *Repository) refreshAliases(ctx context.Context, u *user, tokens map[AuthToken]string, opt ...Option) error { - const op = "cache.(Repository).refreshAliases" +// refreshResolvableAliases attempts to refresh the resolvabl aliases for the +// provided user using the provided tokens. If available, it uses the refresh +// tokens in storage to retrieve and apply only the delta. +func (r *Repository) refreshResolvableAliases(ctx context.Context, u *user, tokens map[AuthToken]string, opt ...Option) error { + const op = "cache.(Repository).refreshResolvableAliases" switch { case util.IsNil(u): return errors.New(ctx, errors.InvalidParameter, op, "user is nil") @@ -59,14 +60,14 @@ func (r *Repository) refreshAliases(ctx context.Context, u *user, tokens map[Aut case u.Address == "": return errors.New(ctx, errors.InvalidParameter, op, "user boundary address is missing") } - const resourceType = aliasResourceType + const resourceType = resolvableAliasResourceType opts, err := getOpts(opt...) if err != nil { return errors.Wrap(ctx, err, op) } - if opts.withAliasRetrievalFunc == nil { - opts.withAliasRetrievalFunc = defaultAliasFunc + if opts.withResolvableAliasRetrievalFunc == nil { + opts.withResolvableAliasRetrievalFunc = defaultResolvableAliasFunc } var oldRefreshTokenVal RefreshTokenValue oldRefreshToken, err := r.lookupRefreshToken(ctx, u, resourceType) @@ -85,7 +86,7 @@ func (r *Repository) refreshAliases(ctx context.Context, u *user, tokens map[Aut var removedIds []string var retErr error for at, t := range tokens { - resp, removedIds, newRefreshToken, err = opts.withAliasRetrievalFunc(ctx, u.Address, t, oldRefreshTokenVal) + resp, removedIds, newRefreshToken, err = opts.withResolvableAliasRetrievalFunc(ctx, u.Address, t, u.Id, oldRefreshTokenVal) if api.ErrInvalidListToken.Is(err) { event.WriteSysEvent(ctx, op, "old list token is no longer valid, starting new initial fetch", "user_id", u.Id) if err := r.deleteRefreshToken(ctx, u, resourceType); err != nil { @@ -93,7 +94,7 @@ func (r *Repository) refreshAliases(ctx context.Context, u *user, tokens map[Aut } // try again without the refresh token oldRefreshToken = nil - resp, removedIds, newRefreshToken, err = opts.withAliasRetrievalFunc(ctx, u.Address, t, "") + resp, removedIds, newRefreshToken, err = opts.withResolvableAliasRetrievalFunc(ctx, u.Address, t, u.Id, "") } if err != nil { if err == ErrRefreshNotSupported { @@ -121,12 +122,12 @@ func (r *Repository) refreshAliases(ctx context.Context, u *user, tokens map[Aut var err error switch { case oldRefreshToken == nil: - if numDeleted, err = w.Exec(ctx, "delete from alias where fk_user_id = @fk_user_id", + if numDeleted, err = w.Exec(ctx, "delete from resolvable_alias where fk_user_id = @fk_user_id", []any{sql.Named("fk_user_id", u.Id)}); err != nil { return err } case len(removedIds) > 0: - if numDeleted, err = w.Exec(ctx, "delete from alias where id in @ids", + if numDeleted, err = w.Exec(ctx, "delete from resolvable_alias where id in @ids", []any{sql.Named("ids", removedIds)}); err != nil { return err } @@ -137,7 +138,7 @@ func (r *Repository) refreshAliases(ctx context.Context, u *user, tokens map[Aut return err } case newRefreshToken != "": - if err := upsertAliases(ctx, w, u, resp); err != nil { + if err := upsertResolvableAliases(ctx, w, u, resp); err != nil { return err } if err := upsertRefreshToken(ctx, w, u, resourceType, newRefreshToken); err != nil { @@ -154,15 +155,15 @@ func (r *Repository) refreshAliases(ctx context.Context, u *user, tokens map[Aut if unsupportedCacheRequest { return ErrRefreshNotSupported } - event.WriteSysEvent(ctx, op, "aliases updated", "deleted", numDeleted, "upserted", len(resp), "user_id", u.Id) + event.WriteSysEvent(ctx, op, "resolvable-aliases updated", "deleted", numDeleted, "upserted", len(resp), "user_id", u.Id) return nil } -// checkCachingAliases fetches all aliases for the provided user and sets the +// checkCachingResolvableAliases fetches all aliases for the provided user and sets the // cache to match the values returned. If the response includes a refresh // token it will save that as well. -func (r *Repository) checkCachingAliases(ctx context.Context, u *user, tokens map[AuthToken]string, opt ...Option) error { - const op = "cache.(Repository).checkAliasesForSearchability" +func (r *Repository) checkCachingResolvableAliases(ctx context.Context, u *user, tokens map[AuthToken]string, opt ...Option) error { + const op = "cache.(Repository).checkCachingResolvableAliases" switch { case util.IsNil(u): return errors.New(ctx, errors.InvalidParameter, op, "user is nil") @@ -171,14 +172,14 @@ func (r *Repository) checkCachingAliases(ctx context.Context, u *user, tokens ma case u.Address == "": return errors.New(ctx, errors.InvalidParameter, op, "user boundary address is missing") } - const resourceType = aliasResourceType + const resourceType = resolvableAliasResourceType opts, err := getOpts(opt...) if err != nil { return errors.Wrap(ctx, err, op) } - if opts.withAliasRetrievalFunc == nil { - opts.withAliasRetrievalFunc = defaultAliasFunc + if opts.withResolvableAliasRetrievalFunc == nil { + opts.withResolvableAliasRetrievalFunc = defaultResolvableAliasFunc } // Find and use a token for retrieving aliases @@ -188,7 +189,7 @@ func (r *Repository) checkCachingAliases(ctx context.Context, u *user, tokens ma var unsupportedCacheRequest bool var retErr error for at, t := range tokens { - resp, _, newRefreshToken, err = opts.withAliasRetrievalFunc(ctx, u.Address, t, "") + resp, _, newRefreshToken, err = opts.withResolvableAliasRetrievalFunc(ctx, u.Address, t, u.Id, "") if err != nil { if err == ErrRefreshNotSupported { unsupportedCacheRequest = true @@ -219,11 +220,11 @@ func (r *Repository) checkCachingAliases(ctx context.Context, u *user, tokens ma } case newRefreshToken != "": var err error - if numDeleted, err = w.Exec(ctx, "delete from alias where fk_user_id = @fk_user_id", + if numDeleted, err = w.Exec(ctx, "delete from resolvable_alias where fk_user_id = @fk_user_id", []any{sql.Named("fk_user_id", u.Id)}); err != nil { return err } - if err := upsertAliases(ctx, w, u, resp); err != nil { + if err := upsertResolvableAliases(ctx, w, u, resp); err != nil { return err } if err := upsertRefreshToken(ctx, w, u, resourceType, newRefreshToken); err != nil { @@ -244,13 +245,13 @@ func (r *Repository) checkCachingAliases(ctx context.Context, u *user, tokens ma if unsupportedCacheRequest { return ErrRefreshNotSupported } - event.WriteSysEvent(ctx, op, "aliases updated", "deleted", numDeleted, "upserted", len(resp), "user_id", u.Id) + event.WriteSysEvent(ctx, op, "resolvable-aliases updated", "deleted", numDeleted, "upserted", len(resp), "user_id", u.Id) return nil } -// upsertAliases upserts the provided aliases to be stored for the provided user. -func upsertAliases(ctx context.Context, w db.Writer, u *user, in []*aliases.Alias) error { - const op = "cache.upsertAliases" +// upsertResolvableAliases upserts the provided aliases to be stored for the provided user. +func upsertResolvableAliases(ctx context.Context, w db.Writer, u *user, in []*aliases.Alias) error { + const op = "cache.upsertResolvableAliases" switch { case util.IsNil(w): return errors.New(ctx, errors.InvalidParameter, op, "writer is nil") @@ -265,18 +266,17 @@ func upsertAliases(ctx context.Context, w db.Writer, u *user, in []*aliases.Alia if err != nil { return errors.Wrap(ctx, err, op) } - newAlias := &Alias{ + newAlias := &ResolvableAlias{ FkUserId: u.Id, Id: s.Id, Type: s.Type, - ScopeId: s.ScopeId, DestinationId: s.DestinationId, Value: s.Value, Item: string(item), } onConflict := db.OnConflict{ Target: db.Columns{"fk_user_id", "id"}, - Action: db.SetColumns([]string{"type", "scope_id", "destination_id", "value", "item"}), + Action: db.SetColumns([]string{"type", "destination_id", "value", "item"}), } if err := w.Create(ctx, newAlias, db.WithOnConflict(&onConflict)); err != nil { return errors.Wrap(ctx, err, op) @@ -285,21 +285,21 @@ func upsertAliases(ctx context.Context, w db.Writer, u *user, in []*aliases.Alia return nil } -func (r *Repository) ListAliases(ctx context.Context, authTokenId string) ([]*aliases.Alias, error) { - const op = "cache.(Repository).ListAliases" +func (r *Repository) ListResolvableAliases(ctx context.Context, authTokenId string) ([]*aliases.Alias, error) { + const op = "cache.(Repository).ListResolvableAliases" switch { case authTokenId == "": return nil, errors.New(ctx, errors.InvalidParameter, op, "auth token id is missing") } - ret, err := r.searchAliases(ctx, "true", nil, withAuthTokenId(authTokenId)) + ret, err := r.searchResolvableAliases(ctx, "true", nil, withAuthTokenId(authTokenId)) if err != nil { return nil, errors.Wrap(ctx, err, op) } return ret, nil } -func (r *Repository) QueryAliases(ctx context.Context, authTokenId, query string) ([]*aliases.Alias, error) { - const op = "cache.(Repository).QueryAliases" +func (r *Repository) QueryResolvableAliases(ctx context.Context, authTokenId, query string) ([]*aliases.Alias, error) { + const op = "cache.(Repository).QueryResolvableAliases" switch { case authTokenId == "": return nil, errors.New(ctx, errors.InvalidParameter, op, "auth token id is missing") @@ -307,19 +307,19 @@ func (r *Repository) QueryAliases(ctx context.Context, authTokenId, query string return nil, errors.New(ctx, errors.InvalidParameter, op, "query is missing") } - w, err := mql.Parse(query, Alias{}, mql.WithIgnoredFields("FkUserId", "Item")) + w, err := mql.Parse(query, ResolvableAlias{}, mql.WithIgnoredFields("FkUserId", "Item")) if err != nil { return nil, errors.Wrap(ctx, err, op, errors.WithCode(errors.InvalidParameter)) } - ret, err := r.searchAliases(ctx, w.Condition, w.Args, withAuthTokenId(authTokenId)) + ret, err := r.searchResolvableAliases(ctx, w.Condition, w.Args, withAuthTokenId(authTokenId)) if err != nil { return nil, errors.Wrap(ctx, err, op) } return ret, nil } -func (r *Repository) searchAliases(ctx context.Context, condition string, searchArgs []any, opt ...Option) ([]*aliases.Alias, error) { - const op = "cache.(Repository).searchAliases" +func (r *Repository) searchResolvableAliases(ctx context.Context, condition string, searchArgs []any, opt ...Option) ([]*aliases.Alias, error) { + const op = "cache.(Repository).searchResolvableAliases" switch { case condition == "": return nil, errors.New(ctx, errors.InvalidParameter, op, "condition is missing") @@ -342,32 +342,31 @@ func (r *Repository) searchAliases(ctx context.Context, condition string, search searchArgs = append(searchArgs, opts.withUserId) } - var cachedAliases []*Alias - if err := r.rw.SearchWhere(ctx, &cachedAliases, condition, searchArgs, db.WithLimit(-1)); err != nil { + var cachedResolvableAliases []*ResolvableAlias + if err := r.rw.SearchWhere(ctx, &cachedResolvableAliases, condition, searchArgs, db.WithLimit(-1)); err != nil { return nil, errors.Wrap(ctx, err, op) } - retAliases := make([]*aliases.Alias, 0, len(cachedAliases)) - for _, cachedSess := range cachedAliases { - var sess aliases.Alias - if err := json.Unmarshal([]byte(cachedSess.Item), &sess); err != nil { + retAliases := make([]*aliases.Alias, 0, len(cachedResolvableAliases)) + for _, cachedA := range cachedResolvableAliases { + var a aliases.Alias + if err := json.Unmarshal([]byte(cachedA.Item), &a); err != nil { return nil, errors.Wrap(ctx, err, op) } - retAliases = append(retAliases, &sess) + retAliases = append(retAliases, &a) } return retAliases, nil } -type Alias struct { +type ResolvableAlias struct { FkUserId string `gorm:"primaryKey"` Id string `gorm:"primaryKey"` Type string `gorm:"default:null"` - ScopeId string `gorm:"default:null"` DestinationId string `gorm:"default:null"` Value string `gorm:"default:null"` Item string `gorm:"default:null"` } -func (*Alias) TableName() string { - return "alias" +func (*ResolvableAlias) TableName() string { + return "resolvable_alias" } diff --git a/internal/clientcache/internal/cache/repository_aliases_test.go b/internal/clientcache/internal/cache/repository_resolvable_aliases_test.go similarity index 78% rename from internal/clientcache/internal/cache/repository_aliases_test.go rename to internal/clientcache/internal/cache/repository_resolvable_aliases_test.go index 0763a1b292..948241ef61 100644 --- a/internal/clientcache/internal/cache/repository_aliases_test.go +++ b/internal/clientcache/internal/cache/repository_resolvable_aliases_test.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/boundary/api/aliases" "github.com/hashicorp/boundary/api/authtokens" + "github.com/hashicorp/boundary/api/targets" "github.com/hashicorp/boundary/globals" cachedb "github.com/hashicorp/boundary/internal/clientcache/internal/db" "github.com/hashicorp/boundary/internal/daemon/controller" @@ -72,15 +73,14 @@ func TestRepository_refreshAliases(t *testing.T) { Type: "target", }, } - var want []*Alias + var want []*ResolvableAlias for _, al := range als { si, err := json.Marshal(al) require.NoError(t, err) - want = append(want, &Alias{ + want = append(want, &ResolvableAlias{ FkUserId: u.Id, Id: al.Id, Type: al.Type, - ScopeId: al.ScopeId, DestinationId: al.DestinationId, Value: al.Value, Item: string(si), @@ -90,7 +90,7 @@ func TestRepository_refreshAliases(t *testing.T) { name string u *user al []*aliases.Alias - want []*Alias + want []*ResolvableAlias errorContains string }{ { @@ -112,7 +112,7 @@ func TestRepository_refreshAliases(t *testing.T) { Id: als[0].Id, Value: "different.value", }), - want: append(want[1:], &Alias{ + want: append(want[1:], &ResolvableAlias{ FkUserId: want[0].FkUserId, Id: want[0].Id, Value: "different.value", @@ -137,19 +137,19 @@ func TestRepository_refreshAliases(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { - err := r.refreshAliases(ctx, tc.u, map[AuthToken]string{{Id: "id"}: "something"}, - WithAliasRetrievalFunc(testStaticResourceRetrievalFunc(t, [][]*aliases.Alias{tc.al}, [][]string{nil}))) + err := r.refreshResolvableAliases(ctx, tc.u, map[AuthToken]string{{Id: "id"}: "something"}, + WithAliasRetrievalFunc(testStaticResourceRetrievalFuncForId(t, [][]*aliases.Alias{tc.al}, [][]string{nil}))) if tc.errorContains == "" { assert.NoError(t, err) rw := db.New(s) - var got []*Alias + var got []*ResolvableAlias require.NoError(t, rw.SearchWhere(ctx, &got, "true", nil)) assert.ElementsMatch(t, got, tc.want) t.Cleanup(func() { refTok := &refreshToken{ UserId: tc.u.Id, - ResourceType: aliasResourceType, + ResourceType: resolvableAliasResourceType, } _, err := r.rw.Delete(ctx, refTok) require.NoError(t, err) @@ -216,40 +216,40 @@ func TestRepository_RefreshAliases_withRefreshTokens(t *testing.T) { }, } - err = r.refreshAliases(ctx, &u, map[AuthToken]string{{Id: "id"}: "something"}, - WithAliasRetrievalFunc(testStaticResourceRetrievalFunc(t, ss, [][]string{nil, nil}))) + err = r.refreshResolvableAliases(ctx, &u, map[AuthToken]string{{Id: "id"}: "something"}, + WithAliasRetrievalFunc(testStaticResourceRetrievalFuncForId(t, ss, [][]string{nil, nil}))) assert.NoError(t, err) - got, err := r.ListAliases(ctx, at.Id) + got, err := r.ListResolvableAliases(ctx, at.Id) require.NoError(t, err) assert.Len(t, got, 2) // Refreshing again uses the refresh token and get additional aliases, appending // them to the response - err = r.refreshAliases(ctx, &u, map[AuthToken]string{{Id: "id"}: "something"}, - WithAliasRetrievalFunc(testStaticResourceRetrievalFunc(t, ss, [][]string{nil, nil}))) + err = r.refreshResolvableAliases(ctx, &u, map[AuthToken]string{{Id: "id"}: "something"}, + WithAliasRetrievalFunc(testStaticResourceRetrievalFuncForId(t, ss, [][]string{nil, nil}))) assert.NoError(t, err) - got, err = r.ListAliases(ctx, at.Id) + got, err = r.ListResolvableAliases(ctx, at.Id) require.NoError(t, err) assert.Len(t, got, 3) // Refreshing again wont return any more resources, but also none should be // removed - require.NoError(t, r.refreshAliases(ctx, &u, map[AuthToken]string{{Id: "id"}: "something"}, - WithAliasRetrievalFunc(testStaticResourceRetrievalFunc(t, ss, [][]string{nil, nil})))) + require.NoError(t, r.refreshResolvableAliases(ctx, &u, map[AuthToken]string{{Id: "id"}: "something"}, + WithAliasRetrievalFunc(testStaticResourceRetrievalFuncForId(t, ss, [][]string{nil, nil})))) assert.NoError(t, err) - got, err = r.ListAliases(ctx, at.Id) + got, err = r.ListResolvableAliases(ctx, at.Id) require.NoError(t, err) assert.Len(t, got, 3) // Refresh again with the refresh token being reported as invalid. - require.NoError(t, r.refreshAliases(ctx, &u, map[AuthToken]string{{Id: "id"}: "something"}, - WithAliasRetrievalFunc(testErroringForRefreshTokenRetrievalFunc(t, ss[0])))) + require.NoError(t, r.refreshResolvableAliases(ctx, &u, map[AuthToken]string{{Id: "id"}: "something"}, + WithAliasRetrievalFunc(testErroringForRefreshTokenRetrievalFuncForId(t, ss[0])))) assert.NoError(t, err) - got, err = r.ListAliases(ctx, at.Id) + got, err = r.ListResolvableAliases(ctx, at.Id) require.NoError(t, err) assert.Len(t, got, 2) } @@ -298,7 +298,7 @@ func TestRepository_ListAliases(t *testing.T) { require.NoError(t, r.AddKeyringToken(ctx, addr, kt2)) t.Run("auth token id is missing", func(t *testing.T) { - l, err := r.ListAliases(ctx, "") + l, err := r.ListResolvableAliases(ctx, "") assert.Nil(t, l) assert.ErrorContains(t, err, "auth token id is missing") }) @@ -326,16 +326,16 @@ func TestRepository_ListAliases(t *testing.T) { Type: "tcp", }, } - require.NoError(t, r.refreshAliases(ctx, u1, map[AuthToken]string{{Id: "id"}: "something"}, - WithAliasRetrievalFunc(testStaticResourceRetrievalFunc(t, [][]*aliases.Alias{ss}, [][]string{nil})))) + require.NoError(t, r.refreshResolvableAliases(ctx, u1, map[AuthToken]string{{Id: "id"}: "something"}, + WithAliasRetrievalFunc(testStaticResourceRetrievalFuncForId(t, [][]*aliases.Alias{ss}, [][]string{nil})))) t.Run("wrong user gets no aliases", func(t *testing.T) { - l, err := r.ListAliases(ctx, kt2.AuthTokenId) + l, err := r.ListResolvableAliases(ctx, kt2.AuthTokenId) assert.NoError(t, err) assert.Empty(t, l) }) t.Run("correct token gets aliases", func(t *testing.T) { - l, err := r.ListAliases(ctx, kt1.AuthTokenId) + l, err := r.ListResolvableAliases(ctx, kt1.AuthTokenId) assert.NoError(t, err) assert.Len(t, l, len(ss)) assert.ElementsMatch(t, l, ss) @@ -407,7 +407,7 @@ func TestRepository_QueryAliases(t *testing.T) { } for _, tc := range errorCases { t.Run(tc.name, func(t *testing.T) { - l, err := r.QueryAliases(ctx, tc.t, tc.query) + l, err := r.QueryResolvableAliases(ctx, tc.t, tc.query) assert.Nil(t, l) assert.ErrorContains(t, err, tc.errContains) }) @@ -436,16 +436,16 @@ func TestRepository_QueryAliases(t *testing.T) { Type: "target", }, } - require.NoError(t, r.refreshAliases(ctx, u1, map[AuthToken]string{{Id: "id"}: "something"}, - WithAliasRetrievalFunc(testStaticResourceRetrievalFunc(t, [][]*aliases.Alias{ss}, [][]string{nil})))) + require.NoError(t, r.refreshResolvableAliases(ctx, u1, map[AuthToken]string{{Id: "id"}: "something"}, + WithAliasRetrievalFunc(testStaticResourceRetrievalFuncForId(t, [][]*aliases.Alias{ss}, [][]string{nil})))) t.Run("wrong token gets no aliases", func(t *testing.T) { - l, err := r.QueryAliases(ctx, kt2.AuthTokenId, query) + l, err := r.QueryResolvableAliases(ctx, kt2.AuthTokenId, query) assert.NoError(t, err) assert.Empty(t, l) }) t.Run("correct token gets aliases", func(t *testing.T) { - l, err := r.QueryAliases(ctx, kt1.AuthTokenId, query) + l, err := r.QueryResolvableAliases(ctx, kt1.AuthTokenId, query) assert.NoError(t, err) assert.Len(t, l, 2) assert.ElementsMatch(t, l, ss[0:2]) @@ -461,18 +461,23 @@ func TestDefaultAliasRetrievalFunc(t *testing.T) { tc := controller.NewTestController(t, nil) tc.Client().SetToken(tc.Token().Token) - tarClient := aliases.NewClient(tc.Client()) - al1, err := tarClient.Create(tc.Context(), "target", "global", aliases.WithName("al1"), aliases.WithValue("address")) + tarClient := targets.NewClient(tc.Client()) + tar1, err := tarClient.Create(tc.Context(), "tcp", "p_1234567890", targets.WithName("tar1"), targets.WithTcpTargetDefaultPort(22), targets.WithAliases([]targets.Alias{ + { + Value: "val1", + ScopeId: "global", + }, + })) require.NoError(t, err) - require.NotNil(t, al1) + require.NotNil(t, tar1) - got, removed, refTok, err := defaultAliasFunc(tc.Context(), tc.ApiAddrs()[0], tc.Token().Token, "") + got, removed, refTok, err := defaultResolvableAliasFunc(tc.Context(), tc.ApiAddrs()[0], tc.Token().Token, tc.Token().UserId, "") assert.NoError(t, err) assert.NotEmpty(t, refTok) assert.Empty(t, removed) assert.Len(t, got, 1) - got2, removed2, refTok2, err := defaultAliasFunc(tc.Context(), tc.ApiAddrs()[0], tc.Token().Token, refTok) + got2, removed2, refTok2, err := defaultResolvableAliasFunc(tc.Context(), tc.ApiAddrs()[0], tc.Token().Token, tc.Token().UserId, refTok) assert.NoError(t, err) assert.NotEmpty(t, refTok2) assert.Empty(t, removed2) diff --git a/internal/clientcache/internal/cache/search.go b/internal/clientcache/internal/cache/search.go index b6e2837be5..676fcdd8d3 100644 --- a/internal/clientcache/internal/cache/search.go +++ b/internal/clientcache/internal/cache/search.go @@ -19,15 +19,15 @@ import ( type SearchableResource string const ( - Unknown SearchableResource = "unknown" - Aliases SearchableResource = "aliases" - Targets SearchableResource = "targets" - Sessions SearchableResource = "sessions" + Unknown SearchableResource = "unknown" + ResolvableAliases SearchableResource = "resolvable-aliases" + Targets SearchableResource = "targets" + Sessions SearchableResource = "sessions" ) func (r SearchableResource) Valid() bool { switch r { - case Aliases, Targets, Sessions: + case ResolvableAliases, Targets, Sessions: return true } return false @@ -35,8 +35,8 @@ func (r SearchableResource) Valid() bool { func ToSearchableResource(s string) SearchableResource { switch { - case strings.EqualFold(s, string(Aliases)): - return Aliases + case strings.EqualFold(s, string(ResolvableAliases)): + return ResolvableAliases case strings.EqualFold(s, string(Targets)): return Targets case strings.EqualFold(s, string(Sessions)): @@ -59,9 +59,9 @@ type SearchParams struct { // SearchResult returns the results from searching the cache. type SearchResult struct { - Aliases []*aliases.Alias - Targets []*targets.Target - Sessions []*sessions.Session + ResolvableAliases []*aliases.Alias `json:"resolvable_aliases,omitempty"` + Targets []*targets.Target `json:"targets,omitempty"` + Sessions []*sessions.Session `json:"sessions,omitempty"` } // SearchService is a domain service that can search across all resources in the @@ -80,11 +80,11 @@ func NewSearchService(ctx context.Context, repo *Repository) (*SearchService, er return &SearchService{ repo: repo, searchableResources: map[SearchableResource]resourceSearcher{ - Aliases: &resourceSearchFns[*aliases.Alias]{ - list: repo.ListAliases, - query: repo.QueryAliases, + ResolvableAliases: &resourceSearchFns[*aliases.Alias]{ + list: repo.ListResolvableAliases, + query: repo.QueryResolvableAliases, searchResult: func(a []*aliases.Alias) *SearchResult { - return &SearchResult{Aliases: a} + return &SearchResult{ResolvableAliases: a} }, }, Targets: &resourceSearchFns[*targets.Target]{ diff --git a/internal/clientcache/internal/cache/search_test.go b/internal/clientcache/internal/cache/search_test.go index 2de224bc5b..b8d7c97947 100644 --- a/internal/clientcache/internal/cache/search_test.go +++ b/internal/clientcache/internal/cache/search_test.go @@ -205,8 +205,8 @@ func TestSearch(t *testing.T) { require.NoError(t, rw.Create(ctx, at)) aliases := []any{ - &Alias{FkUserId: u.Id, Id: "alt_1", Value: "one", Type: "target", Item: `{"id": "alt_1", "value": "one", "type": "target"}`}, - &Alias{FkUserId: u.Id, Id: "alt_2", Value: "two", Type: "target", Item: `{"id": "alt_2", "value": "two", "type": "target"}`}, + &ResolvableAlias{FkUserId: u.Id, Id: "alt_1", Value: "one", Type: "target", Item: `{"id": "alt_1", "value": "one", "type": "target"}`}, + &ResolvableAlias{FkUserId: u.Id, Id: "alt_2", Value: "two", Type: "target", Item: `{"id": "alt_2", "value": "two", "type": "target"}`}, } require.NoError(t, rw.CreateItems(ctx, aliases)) diff --git a/internal/clientcache/internal/cache/status.go b/internal/clientcache/internal/cache/status.go index e51224a1cc..68b5c3a618 100644 --- a/internal/clientcache/internal/cache/status.go +++ b/internal/clientcache/internal/cache/status.go @@ -125,7 +125,7 @@ func (s *StatusService) Status(ctx context.Context) (*Status, error) { us.AuthTokens = append(us.AuthTokens, *ts) } - for _, rt := range []resourceType{aliasResourceType, targetResourceType, sessionResourceType} { + for _, rt := range []resourceType{resolvableAliasResourceType, targetResourceType, sessionResourceType} { ts, err := s.resourceStatus(ctx, u, rt) if err != nil { return nil, errors.Wrap(ctx, err, op) @@ -165,7 +165,7 @@ func (s *StatusService) resourceStatus(ctx context.Context, u *user, rt resource ret.LastError = errStatus err = func() error { - query := fmt.Sprintf("select count(*) from %s where fk_user_id = @user_id", rt) + query := fmt.Sprintf("select count(*) from %s where fk_user_id = @user_id", rt.ColumnName()) r, err := s.repo.rw.Query(ctx, query, []any{sql.Named("user_id", u.Id)}) if err != nil { return errors.Wrap(ctx, err, op) diff --git a/internal/clientcache/internal/cache/status_test.go b/internal/clientcache/internal/cache/status_test.go index f18a5b089b..2a87384549 100644 --- a/internal/clientcache/internal/cache/status_test.go +++ b/internal/clientcache/internal/cache/status_test.go @@ -123,7 +123,7 @@ func TestStatus(t *testing.T) { }, Resources: []ResourceStatus{ { - Name: string(aliasResourceType), + Name: string(resolvableAliasResourceType), Count: 0, }, { @@ -151,7 +151,7 @@ func TestStatus(t *testing.T) { }, Resources: []ResourceStatus{ { - Name: string(aliasResourceType), + Name: string(resolvableAliasResourceType), Count: 0, }, { @@ -211,8 +211,8 @@ func TestStatus(t *testing.T) { alias("2"), alias("3"), } - err = r.refreshAliases(ctx, u1, map[AuthToken]string{{Id: "id"}: "something"}, - WithAliasRetrievalFunc(testStaticResourceRetrievalFunc(t, [][]*aliases.Alias{als}, [][]string{nil}))) + err = r.refreshResolvableAliases(ctx, u1, map[AuthToken]string{{Id: "id"}: "something"}, + WithAliasRetrievalFunc(testStaticResourceRetrievalFuncForId(t, [][]*aliases.Alias{als}, [][]string{nil}))) require.NoError(t, err) got, err := ss.Status(ctx) @@ -230,7 +230,7 @@ func TestStatus(t *testing.T) { assert.Equal(t, Map(got.Users[0].Resources, func(i ResourceStatus) string { return i.Name - }), []string{string(aliasResourceType), string(targetResourceType), string(sessionResourceType)}) + }), []string{string(resolvableAliasResourceType), string(targetResourceType), string(sessionResourceType)}) assert.Equal(t, Map(got.Users[0].Resources, func(i ResourceStatus) int { return i.Count @@ -251,7 +251,7 @@ func TestStatus(t *testing.T) { assert.Equal(t, Map(got.Users[1].Resources, func(i ResourceStatus) string { return i.Name - }), []string{string(aliasResourceType), string(targetResourceType), string(sessionResourceType)}) + }), []string{string(resolvableAliasResourceType), string(targetResourceType), string(sessionResourceType)}) assert.Equal(t, Map(got.Users[1].Resources, func(i ResourceStatus) int { return i.Count @@ -307,8 +307,8 @@ func TestStatus_unsupported(t *testing.T) { AuthTokenId: at1.Id, })) - err = r.refreshAliases(ctx, u1, map[AuthToken]string{{Id: "id"}: "something"}, - WithAliasRetrievalFunc(testNoRefreshRetrievalFunc[*aliases.Alias](t))) + err = r.refreshResolvableAliases(ctx, u1, map[AuthToken]string{{Id: "id"}: "something"}, + WithAliasRetrievalFunc(testNoRefreshRetrievalFuncForId[*aliases.Alias](t))) require.ErrorIs(t, err, ErrRefreshNotSupported) err = r.refreshTargets(ctx, u1, map[AuthToken]string{{Id: "id"}: "something"}, @@ -342,7 +342,7 @@ func TestStatus_unsupported(t *testing.T) { }, Resources: []ResourceStatus{ { - Name: string(aliasResourceType), + Name: string(resolvableAliasResourceType), Count: 0, }, { diff --git a/internal/clientcache/internal/daemon/search_handler.go b/internal/clientcache/internal/daemon/search_handler.go index be3bcaf469..d79a74b781 100644 --- a/internal/clientcache/internal/daemon/search_handler.go +++ b/internal/clientcache/internal/daemon/search_handler.go @@ -23,9 +23,9 @@ import ( // SearchResult is the struct returned to search requests. type SearchResult struct { - Aliases []*aliases.Alias `json:"aliases,omitempty"` - Targets []*targets.Target `json:"targets,omitempty"` - Sessions []*sessions.Session `json:"sessions,omitempty"` + ResolvableAliases []*aliases.Alias `json:"resolvable_aliases,omitempty"` + Targets []*targets.Target `json:"targets,omitempty"` + Sessions []*sessions.Session `json:"sessions,omitempty"` } const ( @@ -149,9 +149,9 @@ func newSearchHandlerFunc(ctx context.Context, repo *cache.Repository, refreshSe // toApiResult converts a domain search result to an api search result func toApiResult(sr *cache.SearchResult) *SearchResult { return &SearchResult{ - Aliases: sr.Aliases, - Targets: sr.Targets, - Sessions: sr.Sessions, + ResolvableAliases: sr.ResolvableAliases, + Targets: sr.Targets, + Sessions: sr.Sessions, } } diff --git a/internal/clientcache/internal/daemon/testing.go b/internal/clientcache/internal/daemon/testing.go index e4b61fc3b6..b29ffc6b7d 100644 --- a/internal/clientcache/internal/daemon/testing.go +++ b/internal/clientcache/internal/daemon/testing.go @@ -88,7 +88,7 @@ func (s *TestServer) AddResources(t *testing.T, p *authtokens.AuthToken, alts [] r, err := cache.NewRepository(ctx, s.CacheServer.store.Load(), &sync.Map{}, s.cmd.ReadTokenFromKeyring, atReadFn) require.NoError(t, err) - altFn := func(ctx context.Context, _, tok string, _ cache.RefreshTokenValue) ([]*aliases.Alias, []string, cache.RefreshTokenValue, error) { + altFn := func(ctx context.Context, _, tok, _ string, _ cache.RefreshTokenValue) ([]*aliases.Alias, []string, cache.RefreshTokenValue, error) { if tok != p.Token { return nil, nil, "", nil } diff --git a/internal/clientcache/internal/db/schema.sql b/internal/clientcache/internal/db/schema.sql index 6ec26401b7..be692f0a84 100644 --- a/internal/clientcache/internal/db/schema.sql +++ b/internal/clientcache/internal/db/schema.sql @@ -17,13 +17,13 @@ create table if not exists user ( create table if not exists resource_type_enm( string text not null primary key constraint only_predefined_resource_types_allowed - check(string in ('unknown', 'alias', 'target', 'session')) + check(string in ('unknown', 'resolvable-alias', 'target', 'session')) ); insert into resource_type_enm (string) values ('unknown'), - ('alias'), + ('resolvable-alias'), ('target'), ('session'); @@ -158,7 +158,7 @@ create table if not exists session ( -- alias contains cached boundary alias resource for a specific user and -- with specific fields extracted to facilitate searching over those fields -create table if not exists alias ( +create table if not exists resolvable_alias ( -- the boundary user id of the user who has was able to read/list this resource fk_user_id text not null references user(id) @@ -169,7 +169,6 @@ create table if not exists alias ( -- the following fields are used for searching and are set to the values -- from the boundary resource type text, - scope_id text, destination_id text, value text, -- item is the json representation of this resource from the perspective of