diff --git a/src/Auth0.ManagementApi/Clients/IKeysClient.cs b/src/Auth0.ManagementApi/Clients/IKeysClient.cs index 961b718a..59834d4b 100644 --- a/src/Auth0.ManagementApi/Clients/IKeysClient.cs +++ b/src/Auth0.ManagementApi/Clients/IKeysClient.cs @@ -82,5 +82,11 @@ public interface IKeysClient /// /// The cancellation token to cancel operation. Task CreatePublicWrappingKeyAsync(WrappingKeyCreateRequest request, CancellationToken cancellationToken = default); + + /// + /// Perform rekeying operation on the key hierarchy. + /// + /// The cancellation token to cancel operation. + Task RekeyAsync(CancellationToken cancellationToken = default); } } diff --git a/src/Auth0.ManagementApi/Clients/KeysClient.cs b/src/Auth0.ManagementApi/Clients/KeysClient.cs index 455c1216..ab53a9cd 100644 --- a/src/Auth0.ManagementApi/Clients/KeysClient.cs +++ b/src/Auth0.ManagementApi/Clients/KeysClient.cs @@ -160,7 +160,7 @@ public Task CreatePublicWrappingKeyAsync( if (string.IsNullOrEmpty(request.Kid)) throw new ArgumentNullException(nameof(request.Kid)); - + return Connection.SendAsync( HttpMethod.Post, BuildUri($"keys/encryption/{EncodePath(request.Kid)}/wrapping-key"), @@ -168,5 +168,16 @@ public Task CreatePublicWrappingKeyAsync( headers: DefaultHeaders, cancellationToken: cancellationToken); } + + /// + public Task RekeyAsync(CancellationToken cancellationToken = default) + { + return Connection.SendAsync( + HttpMethod.Post, + BuildUri("keys/encryption/rekey"), + body: null, + headers: DefaultHeaders, + cancellationToken: cancellationToken); + } } } diff --git a/tests/Auth0.ManagementApi.IntegrationTests/KeysTests.cs b/tests/Auth0.ManagementApi.IntegrationTests/KeysTests.cs index 8a5ecd29..6fe24110 100644 --- a/tests/Auth0.ManagementApi.IntegrationTests/KeysTests.cs +++ b/tests/Auth0.ManagementApi.IntegrationTests/KeysTests.cs @@ -155,5 +155,41 @@ public async void Test_import_encrypted_keys() importedKeys.Type.Should().Be(EncryptionKeyType.CustomerProvidedRootKey); importedKeys.ParentKid.Should().Be("a20128c5-9bf5-4209-8c43-b6dfcee60e9b"); } + + [Fact] + public async void Test_rekey_encrypted_keys() + { + // Get the existing Tenant Master Key + var existingTenantMasterKey = await GetExistingTenantMasterKey(); + + await fixture.ApiClient.Keys.RekeyAsync(); + + var newTenantMasterKey = await GetExistingTenantMasterKey(); + + // After rekey operation, a new Tenant Master Key should be generated + existingTenantMasterKey.Should().NotBeEquivalentTo(newTenantMasterKey); + + var existingTenantMasterKeyAfterRekey = + await fixture.ApiClient.Keys.GetEncryptionKeyAsync( + new EncryptionKeyGetRequest() + { + Kid = existingTenantMasterKey.Kid + } + ); + + // Confirming that the old master key is destroyed + existingTenantMasterKeyAfterRekey.State.Should().Be(EncryptionKeyState.Destroyed); + } + + private async Task GetExistingTenantMasterKey() + { + var existingEncryptionKeys = await fixture.ApiClient.Keys.GetAllEncryptionKeysAsync(new PaginationInfo()); + + // Get the existing Tenant Master Key + var existingTenantMasterKey = + existingEncryptionKeys.FirstOrDefault(x => x.State == EncryptionKeyState.Active && + x.Type == EncryptionKeyType.TenantMasterKey); + return existingTenantMasterKey; + } } }