// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: BUSL-1.1 package server_test import ( "context" "testing" "time" "github.com/hashicorp/boundary/api/recovery" "github.com/hashicorp/boundary/api/roles" "github.com/hashicorp/boundary/globals" "github.com/hashicorp/boundary/internal/daemon/controller" "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/server" "github.com/hashicorp/boundary/internal/types/scope" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestRecoveryNonces(t *testing.T) { assert, require := assert.New(t), require.New(t) // Set these low so that we can not have the test run forever globals.RecoveryTokenValidityPeriod = 10 * time.Second globals.WorkerAuthNonceValidityPeriod = 10 * time.Second controller.NonceCleanupInterval = 20 * time.Second wrapper := db.TestWrapper(t) tc := controller.NewTestController(t, &controller.TestControllerOpts{ RecoveryKms: wrapper, }) defer tc.Shutdown() externalWrappers := tc.Kms().GetExternalWrappers(context.Background()) externalRecovery := externalWrappers.Recovery() require.Equal(externalRecovery, wrapper) client := tc.Client() repo := tc.ServersRepo() // First, validate that we can't use the same token twice. Get two tokens, // try to use the first twice (should succeed first time, fail second), then // ensure second token works token1, err := recovery.GenerateRecoveryToken(tc.Context(), wrapper) require.NoError(err) token2, err := recovery.GenerateRecoveryToken(tc.Context(), wrapper) require.NoError(err) // Token 1, try 1 client.SetToken(token1) roleClient := roles.NewClient(client) _, err = roleClient.Create(tc.Context(), scope.Global.String()) require.NoError(err) nonces, err := repo.ListNonces(tc.Context(), server.NoncePurposeRecovery) require.NoError(err) assert.Len(nonces, 1) // Token 1, try 2 _, err = roleClient.Create(tc.Context(), scope.Global.String()) require.Error(err) nonces, err = repo.ListNonces(tc.Context(), server.NoncePurposeRecovery) require.NoError(err) assert.Len(nonces, 1) // Token 2 roleClient.ApiClient().SetToken(token2) _, err = roleClient.Create(tc.Context(), scope.Global.String()) require.NoError(err) nonces, err = repo.ListNonces(tc.Context(), server.NoncePurposeRecovery) require.NoError(err) assert.Len(nonces, 2) // Make sure they get cleaned up time.Sleep(2 * controller.NonceCleanupInterval) nonces, err = repo.ListNonces(tc.Context(), server.NoncePurposeRecovery) require.NoError(err) assert.Len(nonces, 0) // And finally, make sure they still can't be used for _, token := range []string{token1, token2} { roleClient.ApiClient().SetToken(token) _, err = roleClient.Create(tc.Context(), scope.Global.String()) require.Error(err) nonces, err = repo.ListNonces(tc.Context(), server.NoncePurposeRecovery) require.NoError(err) assert.Len(nonces, 0) } }