Change aliases to resolvable aliases in client cache (#4656)
This commit is contained in:
15 files changed
+273
-226
No files matched your search
@@ -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)
|
||||
|
||||
+10
-10
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -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)
|
||||
|
||||
+5
-5
@@ -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
|
||||
|
||||
+103
-47
@@ -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
|
||||
|
||||
+55
-56
@@ -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"
|
||||
}
|
||||
+41
-36
@@ -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)
|
||||
+14
-14
@@ -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]{
|
||||
|
||||
+2
-2
@@ -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))
|
||||
|
||||
|
||||
+2
-2
@@ -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)
|
||||
|
||||
+9
-9
@@ -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
|
||||
|
||||
Reference in new issue
Block a user