backport of commit 551b8bf72c

pull/4665/head
Todd 2 years ago
parent 9ae97f845d
commit fe69e9564f

@ -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)

@ -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
}
}

@ -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)

@ -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

@ -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)

@ -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

@ -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"
}

@ -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)

@ -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]{

@ -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))

@ -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)

@ -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,
},
{

@ -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,
}
}

@ -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
}

@ -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

Loading…
Cancel
Save