From 86fd41885a85f508950880d00b6e2da00e862bce Mon Sep 17 00:00:00 2001 From: Johan Brandhorst-Satzkorn Date: Fri, 14 Feb 2025 20:37:35 +0000 Subject: [PATCH 1/6] backport of commit fb4847a3cde9d1ec026f6372c16e4517dcdbbae9 --- internal/clientcache/internal/cache/repository_token.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/clientcache/internal/cache/repository_token.go b/internal/clientcache/internal/cache/repository_token.go index 77823c16f9..2ade8eface 100644 --- a/internal/clientcache/internal/cache/repository_token.go +++ b/internal/clientcache/internal/cache/repository_token.go @@ -51,7 +51,8 @@ func upsertUserAndAuthToken(ctx context.Context, reader db.Reader, writer db.Wri } onConflict := &db.OnConflict{ Target: db.Columns{"id"}, - Action: db.DoNothing(true), + // Unset the deleted_at column if it was set to un-delete the user + Action: db.SetColumnValues(map[string]any{"deleted_at": "infinity"}), } if err := writer.Create(ctx, u, db.WithOnConflict(onConflict)); err != nil { return errors.Wrap(ctx, err, op) From 470b86b536e8ca5423d0cb586c05a66220aacdc5 Mon Sep 17 00:00:00 2001 From: Johan Brandhorst-Satzkorn Date: Fri, 14 Feb 2025 20:40:04 +0000 Subject: [PATCH 2/6] backport of commit fbc039ae1cd0c085f6494a40a743b1d54959e12d --- internal/clientcache/internal/cache/refresh.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/clientcache/internal/cache/refresh.go b/internal/clientcache/internal/cache/refresh.go index aff0febddd..9114cbd779 100644 --- a/internal/clientcache/internal/cache/refresh.go +++ b/internal/clientcache/internal/cache/refresh.go @@ -119,6 +119,9 @@ func (r *RefreshService) cleanAndPickAuthTokens(ctx context.Context, u *user) (m case err != nil && (api.ErrUnauthorized.Is(err) || api.ErrNotFound.Is(err)): r.repo.idToKeyringlessAuthToken.Delete(t.Id) event.WriteSysEvent(ctx, op, "Removed auth token from cache because it was not found to be valid in boundary", "auth token id", at.Id) + if err := r.repo.cleanExpiredOrOrphanedAuthTokens(ctx); err != nil { + return nil, errors.Wrap(ctx, err, op, errors.WithMsg("for user %q, auth token %q", u.Id, t.Id)) + } continue case err != nil && !errors.Is(err, apiErr): event.WriteError(ctx, op, err, event.WithInfoMsg("validating in memory stored token against boundary", "auth token id", at.Id)) From 3511b9c285bfa5fd7566460ab737a7c1a9f0bb1c Mon Sep 17 00:00:00 2001 From: Johan Brandhorst-Satzkorn Date: Fri, 14 Feb 2025 20:41:15 +0000 Subject: [PATCH 3/6] backport of commit 3f57b096507437e34621fbd7484767ea223109e2 --- internal/clientcache/internal/cache/refresh.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/clientcache/internal/cache/refresh.go b/internal/clientcache/internal/cache/refresh.go index 9114cbd779..f40ea89a3a 100644 --- a/internal/clientcache/internal/cache/refresh.go +++ b/internal/clientcache/internal/cache/refresh.go @@ -94,7 +94,7 @@ func (r *RefreshService) cleanAndPickAuthTokens(ctx context.Context, u *user) (m if err := r.repo.deleteKeyringToken(ctx, *kt); err != nil { return nil, errors.Wrap(ctx, err, op, errors.WithMsg("for user %q, auth token %q", u.Id, t.Id)) } - case at != nil: + default: _, err := r.repo.tokenReadFromBoundaryFn(ctx, u.Address, at.Token) var apiErr *api.Error switch { From 600b63b1f1784badc10fd432cd0d02ce5077469c Mon Sep 17 00:00:00 2001 From: Johan Brandhorst-Satzkorn Date: Fri, 14 Feb 2025 20:43:31 +0000 Subject: [PATCH 4/6] backport of commit 35feed08c95d6a4056c451a83445e7a3aaac52ba --- internal/clientcache/internal/cache/refresh.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/internal/clientcache/internal/cache/refresh.go b/internal/clientcache/internal/cache/refresh.go index f40ea89a3a..12440dc1d8 100644 --- a/internal/clientcache/internal/cache/refresh.go +++ b/internal/clientcache/internal/cache/refresh.go @@ -96,7 +96,6 @@ func (r *RefreshService) cleanAndPickAuthTokens(ctx context.Context, u *user) (m } default: _, err := r.repo.tokenReadFromBoundaryFn(ctx, u.Address, at.Token) - var apiErr *api.Error switch { case err != nil && (api.ErrUnauthorized.Is(err) || api.ErrNotFound.Is(err)): if err := r.repo.deleteKeyringToken(ctx, *kt); err != nil { @@ -104,7 +103,7 @@ func (r *RefreshService) cleanAndPickAuthTokens(ctx context.Context, u *user) (m } event.WriteSysEvent(ctx, op, "Removed auth token from cache because it was not found to be valid in boundary", "auth token id", at.Id) continue - case err != nil && !errors.Is(err, apiErr): + case err != nil: event.WriteError(ctx, op, err, event.WithInfoMsg("validating keyring stored token against boundary", "auth token id", at.Id)) continue } @@ -114,7 +113,6 @@ func (r *RefreshService) cleanAndPickAuthTokens(ctx context.Context, u *user) (m if atv, ok := r.repo.idToKeyringlessAuthToken.Load(t.Id); ok { if at, ok := atv.(*authtokens.AuthToken); ok { _, err := r.repo.tokenReadFromBoundaryFn(ctx, u.Address, at.Token) - var apiErr *api.Error switch { case err != nil && (api.ErrUnauthorized.Is(err) || api.ErrNotFound.Is(err)): r.repo.idToKeyringlessAuthToken.Delete(t.Id) @@ -123,11 +121,10 @@ func (r *RefreshService) cleanAndPickAuthTokens(ctx context.Context, u *user) (m return nil, errors.Wrap(ctx, err, op, errors.WithMsg("for user %q, auth token %q", u.Id, t.Id)) } continue - case err != nil && !errors.Is(err, apiErr): + case err != nil: event.WriteError(ctx, op, err, event.WithInfoMsg("validating in memory stored token against boundary", "auth token id", at.Id)) continue } - ret[*t] = at.Token } } From 335276610eb30a4ba0fdb394d83b518a7c0f507b Mon Sep 17 00:00:00 2001 From: Johan Brandhorst-Satzkorn Date: Fri, 14 Feb 2025 20:45:01 +0000 Subject: [PATCH 5/6] backport of commit acda04bafb3c1358cf86f91a6f1552cbf843c8e6 --- internal/clientcache/internal/cache/refresh.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/clientcache/internal/cache/refresh.go b/internal/clientcache/internal/cache/refresh.go index 12440dc1d8..1434b33b56 100644 --- a/internal/clientcache/internal/cache/refresh.go +++ b/internal/clientcache/internal/cache/refresh.go @@ -101,7 +101,7 @@ func (r *RefreshService) cleanAndPickAuthTokens(ctx context.Context, u *user) (m if err := r.repo.deleteKeyringToken(ctx, *kt); err != nil { return nil, errors.Wrap(ctx, err, op, errors.WithMsg("for user %q, auth token %q", u.Id, t.Id)) } - event.WriteSysEvent(ctx, op, "Removed auth token from cache because it was not found to be valid in boundary", "auth token id", at.Id) + event.WriteSysEvent(ctx, op, "Removed auth token from db because it was not found to be valid in boundary", "auth token id", at.Id) continue case err != nil: event.WriteError(ctx, op, err, event.WithInfoMsg("validating keyring stored token against boundary", "auth token id", at.Id)) @@ -116,7 +116,7 @@ func (r *RefreshService) cleanAndPickAuthTokens(ctx context.Context, u *user) (m switch { case err != nil && (api.ErrUnauthorized.Is(err) || api.ErrNotFound.Is(err)): r.repo.idToKeyringlessAuthToken.Delete(t.Id) - event.WriteSysEvent(ctx, op, "Removed auth token from cache because it was not found to be valid in boundary", "auth token id", at.Id) + event.WriteSysEvent(ctx, op, "Removed auth token from in memory cache because it was not found to be valid in boundary", "auth token id", at.Id) if err := r.repo.cleanExpiredOrOrphanedAuthTokens(ctx); err != nil { return nil, errors.Wrap(ctx, err, op, errors.WithMsg("for user %q, auth token %q", u.Id, t.Id)) } From eed69b69c2db71aa4b896becee538452fd48dc87 Mon Sep 17 00:00:00 2001 From: Michael Li Date: Tue, 18 Feb 2025 20:15:10 +0000 Subject: [PATCH 6/6] backport of commit c215a757486151211d1d3d97103b56b7480b2246 --- .../internal/e2e/tests/base/search_test.go | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/testing/internal/e2e/tests/base/search_test.go b/testing/internal/e2e/tests/base/search_test.go index 5a1c9e8aad..8ee2006278 100644 --- a/testing/internal/e2e/tests/base/search_test.go +++ b/testing/internal/e2e/tests/base/search_test.go @@ -285,4 +285,131 @@ func TestCliSearch(t *testing.T) { err = json.Unmarshal(output.Stdout, &searchResult) require.NoError(t, err) require.Len(t, searchResult.Item.Sessions, 0) + + // Log out and confirm search does not work + output = e2e.RunCommand(ctx, "boundary", e2e.WithArgs("logout")) + require.NoError(t, output.Err, string(output.Stderr)) + output = e2e.RunCommand(ctx, "boundary", + e2e.WithArgs( + "search", + "-resource", "targets", + "-format", "json", + "-query", fmt.Sprintf(`name %% "%s" and scope_id = "%s"`, targetPrefix, projectId), + ), + ) + require.Error(t, output.Err) + + // Log back in and confirm search works + boundary.AuthenticateAdminCli(t, ctx) + output = e2e.RunCommand(ctx, "boundary", + e2e.WithArgs( + "search", + "-resource", "targets", + "-format", "json", + "-query", fmt.Sprintf(`name %% "%s" and scope_id = "%s"`, targetPrefix, projectId), + ), + ) + require.NoError(t, output.Err, string(output.Stderr)) + searchResult = clientcache.SearchResult{} + err = json.Unmarshal(output.Stdout, &searchResult) + require.NoError(t, err) + require.Len(t, searchResult.Item.Targets, len(targetIds)) + + // Restart cache and confirm search works + t.Log("Restarting cache...") + output = e2e.RunCommand(ctx, "boundary", e2e.WithArgs("cache", "stop")) + require.NoError(t, output.Err, string(output.Stderr)) + output = e2e.RunCommand(ctx, "boundary", + e2e.WithArgs( + "cache", "start", + "-refresh-interval", "5s", + "-background", + ), + ) + require.NoError(t, output.Err, string(output.Stderr)) + err = backoff.RetryNotify( + func() error { + output := e2e.RunCommand(ctx, "boundary", e2e.WithArgs("cache", "status", "-format", "json")) + if output.Err != nil { + return errors.New(strings.TrimSpace(string(output.Stderr))) + } + + err = json.Unmarshal(output.Stdout, &statusResult) + if err != nil { + return backoff.Permanent(err) + } + + return nil + }, + backoff.WithMaxRetries(backoff.NewConstantBackOff(1*time.Second), 5), + func(err error, td time.Duration) { + t.Logf("%s. Retrying...", err.Error()) + }, + ) + require.NoError(t, err) + require.Equal(t, statusResult.StatusCode, 200) + require.GreaterOrEqual(t, statusResult.Item.Uptime, 0*time.Second) + output = e2e.RunCommand(ctx, "boundary", + e2e.WithArgs( + "search", + "-resource", "targets", + "-format", "json", + "-query", fmt.Sprintf(`name %% "%s" and scope_id = "%s"`, targetPrefix, projectId), + ), + ) + require.NoError(t, output.Err, string(output.Stderr)) + searchResult = clientcache.SearchResult{} + err = json.Unmarshal(output.Stdout, &searchResult) + require.NoError(t, err) + require.Len(t, searchResult.Item.Targets, len(targetIds)) + + // Log out and restart cache. Log in and confirm search works + output = e2e.RunCommand(ctx, "boundary", e2e.WithArgs("logout")) + t.Log("Restarting cache...") + output = e2e.RunCommand(ctx, "boundary", e2e.WithArgs("cache", "stop")) + require.NoError(t, output.Err, string(output.Stderr)) + output = e2e.RunCommand(ctx, "boundary", + e2e.WithArgs( + "cache", "start", + "-refresh-interval", "5s", + "-background", + ), + ) + require.NoError(t, output.Err, string(output.Stderr)) + err = backoff.RetryNotify( + func() error { + output := e2e.RunCommand(ctx, "boundary", e2e.WithArgs("cache", "status", "-format", "json")) + if output.Err != nil { + return errors.New(strings.TrimSpace(string(output.Stderr))) + } + + err = json.Unmarshal(output.Stdout, &statusResult) + if err != nil { + return backoff.Permanent(err) + } + + return nil + }, + backoff.WithMaxRetries(backoff.NewConstantBackOff(1*time.Second), 5), + func(err error, td time.Duration) { + t.Logf("%s. Retrying...", err.Error()) + }, + ) + require.NoError(t, err) + require.Equal(t, statusResult.StatusCode, 200) + require.GreaterOrEqual(t, statusResult.Item.Uptime, 0*time.Second) + boundary.AuthenticateAdminCli(t, ctx) + output = e2e.RunCommand(ctx, "boundary", + e2e.WithArgs( + "search", + "-resource", "targets", + "-format", "json", + "-query", fmt.Sprintf(`name %% "%s" and scope_id = "%s"`, targetPrefix, projectId), + ), + ) + require.NoError(t, output.Err, string(output.Stderr)) + searchResult = clientcache.SearchResult{} + err = json.Unmarshal(output.Stdout, &searchResult) + require.NoError(t, err) + require.Len(t, searchResult.Item.Targets, len(targetIds)) }