diff --git a/src/Admin/AdminConsole/Models/OrganizationEditModel.cs b/src/Admin/AdminConsole/Models/OrganizationEditModel.cs
index 4ba22130f7..48340df708 100644
--- a/src/Admin/AdminConsole/Models/OrganizationEditModel.cs
+++ b/src/Admin/AdminConsole/Models/OrganizationEditModel.cs
@@ -143,7 +143,7 @@ public class OrganizationEditModel : OrganizationViewModel
[Display(Name = "SCIM")]
public bool UseScim { get; set; }
[Display(Name = "Secrets Manager")]
- public bool UseSecretsManager { get; set; }
+ public new bool UseSecretsManager { get; set; }
[Display(Name = "Self Host")]
public bool SelfHost { get; set; }
[Display(Name = "Users Get Premium")]
diff --git a/src/Api/AdminConsole/Public/Models/MemberBaseModel.cs b/src/Api/AdminConsole/Public/Models/MemberBaseModel.cs
index c56117ae71..dc3f91d49f 100644
--- a/src/Api/AdminConsole/Public/Models/MemberBaseModel.cs
+++ b/src/Api/AdminConsole/Public/Models/MemberBaseModel.cs
@@ -1,8 +1,11 @@
using System.ComponentModel.DataAnnotations;
+using System.Diagnostics.CodeAnalysis;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
+#nullable enable
+
namespace Bit.Api.AdminConsole.Public.Models;
public abstract class MemberBaseModel
@@ -25,6 +28,7 @@ public abstract class MemberBaseModel
}
}
+ [SetsRequiredMembers]
public MemberBaseModel(OrganizationUserUserDetails user)
{
if (user == null)
@@ -46,14 +50,13 @@ public abstract class MemberBaseModel
///
[Required]
[EnumDataType(typeof(OrganizationUserType))]
- public OrganizationUserType? Type { get; set; }
+ public required OrganizationUserType? Type { get; set; }
///
/// External identifier for reference or linking this member to another system, such as a user directory.
///
/// external_id_123456
[StringLength(300)]
- public string ExternalId { get; set; }
-
+ public string? ExternalId { get; set; }
///
/// The member's custom permissions if the member has a Custom role. If not supplied, all custom permissions will
/// default to false.
diff --git a/src/Api/AdminConsole/Public/Models/Response/MemberResponseModel.cs b/src/Api/AdminConsole/Public/Models/Response/MemberResponseModel.cs
index ab6ecbca44..499c27cfc9 100644
--- a/src/Api/AdminConsole/Public/Models/Response/MemberResponseModel.cs
+++ b/src/Api/AdminConsole/Public/Models/Response/MemberResponseModel.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
using Bit.Api.Models.Public.Response;
using Bit.Core.Entities;
@@ -16,6 +17,7 @@ public class MemberResponseModel : MemberBaseModel, IResponseModel
[JsonConstructor]
public MemberResponseModel() { }
+ [SetsRequiredMembers]
public MemberResponseModel(OrganizationUser user, IEnumerable collections) : base(user)
{
if (user == null)
@@ -31,6 +33,7 @@ public class MemberResponseModel : MemberBaseModel, IResponseModel
ResetPasswordEnrolled = user.ResetPasswordKey != null;
}
+ [SetsRequiredMembers]
public MemberResponseModel(OrganizationUserUserDetails user, bool twoFactorEnabled,
IEnumerable collections) : base(user)
{
diff --git a/src/Api/Auth/Controllers/AccountsController.cs b/src/Api/Auth/Controllers/AccountsController.cs
index 193077dc15..a94e170cbb 100644
--- a/src/Api/Auth/Controllers/AccountsController.cs
+++ b/src/Api/Auth/Controllers/AccountsController.cs
@@ -3,7 +3,7 @@ using Bit.Api.AdminConsole.Models.Response;
using Bit.Api.Auth.Models.Request;
using Bit.Api.Auth.Models.Request.Accounts;
using Bit.Api.Auth.Models.Request.WebAuthn;
-using Bit.Api.Auth.Validators;
+using Bit.Api.KeyManagement.Validators;
using Bit.Api.Models.Request;
using Bit.Api.Models.Request.Accounts;
using Bit.Api.Models.Response;
@@ -18,7 +18,6 @@ using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Models.Api.Request.Accounts;
using Bit.Core.Auth.Models.Data;
using Bit.Core.Auth.UserFeatures.TdeOffboardingPassword.Interfaces;
-using Bit.Core.Auth.UserFeatures.UserKey;
using Bit.Core.Auth.UserFeatures.UserMasterPassword.Interfaces;
using Bit.Core.Billing.Models;
using Bit.Core.Billing.Services;
@@ -26,6 +25,8 @@ using Bit.Core.Context;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
+using Bit.Core.KeyManagement.Models.Data;
+using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Models.Api.Response;
using Bit.Core.Models.Business;
using Bit.Core.Repositories;
diff --git a/src/Api/Vault/Validators/CipherRotationValidator.cs b/src/Api/KeyManagement/Validators/CipherRotationValidator.cs
similarity index 92%
rename from src/Api/Vault/Validators/CipherRotationValidator.cs
rename to src/Api/KeyManagement/Validators/CipherRotationValidator.cs
index 77e437017a..ab56db4195 100644
--- a/src/Api/Vault/Validators/CipherRotationValidator.cs
+++ b/src/Api/KeyManagement/Validators/CipherRotationValidator.cs
@@ -1,11 +1,10 @@
-using Bit.Api.Auth.Validators;
-using Bit.Api.Vault.Models.Request;
+using Bit.Api.Vault.Models.Request;
using Bit.Core.Entities;
using Bit.Core.Exceptions;
using Bit.Core.Vault.Entities;
using Bit.Core.Vault.Repositories;
-namespace Bit.Api.Vault.Validators;
+namespace Bit.Api.KeyManagement.Validators;
public class CipherRotationValidator : IRotationValidator, IEnumerable>
{
diff --git a/src/Api/Auth/Validators/EmergencyAccessRotationValidator.cs b/src/Api/KeyManagement/Validators/EmergencyAccessRotationValidator.cs
similarity index 97%
rename from src/Api/Auth/Validators/EmergencyAccessRotationValidator.cs
rename to src/Api/KeyManagement/Validators/EmergencyAccessRotationValidator.cs
index 5a038730e3..3fd9273e4e 100644
--- a/src/Api/Auth/Validators/EmergencyAccessRotationValidator.cs
+++ b/src/Api/KeyManagement/Validators/EmergencyAccessRotationValidator.cs
@@ -5,7 +5,7 @@ using Bit.Core.Exceptions;
using Bit.Core.Repositories;
using Bit.Core.Services;
-namespace Bit.Api.Auth.Validators;
+namespace Bit.Api.KeyManagement.Validators;
public class EmergencyAccessRotationValidator : IRotationValidator,
IEnumerable>
diff --git a/src/Api/Vault/Validators/FolderRotationValidator.cs b/src/Api/KeyManagement/Validators/FolderRotationValidator.cs
similarity index 91%
rename from src/Api/Vault/Validators/FolderRotationValidator.cs
rename to src/Api/KeyManagement/Validators/FolderRotationValidator.cs
index 4290c08b13..add0a46c1c 100644
--- a/src/Api/Vault/Validators/FolderRotationValidator.cs
+++ b/src/Api/KeyManagement/Validators/FolderRotationValidator.cs
@@ -1,11 +1,10 @@
-using Bit.Api.Auth.Validators;
-using Bit.Api.Vault.Models.Request;
+using Bit.Api.Vault.Models.Request;
using Bit.Core.Entities;
using Bit.Core.Exceptions;
using Bit.Core.Vault.Entities;
using Bit.Core.Vault.Repositories;
-namespace Bit.Api.Vault.Validators;
+namespace Bit.Api.KeyManagement.Validators;
public class FolderRotationValidator : IRotationValidator, IEnumerable>
{
diff --git a/src/Api/Auth/Validators/IRotationValidator.cs b/src/Api/KeyManagement/Validators/IRotationValidator.cs
similarity index 94%
rename from src/Api/Auth/Validators/IRotationValidator.cs
rename to src/Api/KeyManagement/Validators/IRotationValidator.cs
index fb6534ebee..50f4dd0043 100644
--- a/src/Api/Auth/Validators/IRotationValidator.cs
+++ b/src/Api/KeyManagement/Validators/IRotationValidator.cs
@@ -1,7 +1,7 @@
using Bit.Core.Entities;
using Bit.Core.Exceptions;
-namespace Bit.Api.Auth.Validators;
+namespace Bit.Api.KeyManagement.Validators;
///
/// A consistent interface for domains to validate re-encrypted data before saved to database. Some examples are:
diff --git a/src/Api/AdminConsole/Validators/OrganizationUserRotationValidator.cs b/src/Api/KeyManagement/Validators/OrganizationUserRotationValidator.cs
similarity index 96%
rename from src/Api/AdminConsole/Validators/OrganizationUserRotationValidator.cs
rename to src/Api/KeyManagement/Validators/OrganizationUserRotationValidator.cs
index c9cf39ae04..5023521fe3 100644
--- a/src/Api/AdminConsole/Validators/OrganizationUserRotationValidator.cs
+++ b/src/Api/KeyManagement/Validators/OrganizationUserRotationValidator.cs
@@ -1,10 +1,9 @@
using Bit.Api.AdminConsole.Models.Request.Organizations;
-using Bit.Api.Auth.Validators;
using Bit.Core.Entities;
using Bit.Core.Exceptions;
using Bit.Core.Repositories;
-namespace Bit.Api.AdminConsole.Validators;
+namespace Bit.Api.KeyManagement.Validators;
///
/// Organization user implementation for
diff --git a/src/Api/Tools/Validators/SendRotationValidator.cs b/src/Api/KeyManagement/Validators/SendRotationValidator.cs
similarity index 94%
rename from src/Api/Tools/Validators/SendRotationValidator.cs
rename to src/Api/KeyManagement/Validators/SendRotationValidator.cs
index 74b36832ff..c39f563b51 100644
--- a/src/Api/Tools/Validators/SendRotationValidator.cs
+++ b/src/Api/KeyManagement/Validators/SendRotationValidator.cs
@@ -1,12 +1,11 @@
-using Bit.Api.Auth.Validators;
-using Bit.Api.Tools.Models.Request;
+using Bit.Api.Tools.Models.Request;
using Bit.Core.Entities;
using Bit.Core.Exceptions;
using Bit.Core.Tools.Entities;
using Bit.Core.Tools.Repositories;
using Bit.Core.Tools.Services;
-namespace Bit.Api.Tools.Validators;
+namespace Bit.Api.KeyManagement.Validators;
///
/// Send implementation for
diff --git a/src/Api/Auth/Validators/WebAuthnLoginKeyRotationValidator.cs b/src/Api/KeyManagement/Validators/WebAuthnLoginKeyRotationValidator.cs
similarity index 97%
rename from src/Api/Auth/Validators/WebAuthnLoginKeyRotationValidator.cs
rename to src/Api/KeyManagement/Validators/WebAuthnLoginKeyRotationValidator.cs
index 5c4d0ef302..1706aebd78 100644
--- a/src/Api/Auth/Validators/WebAuthnLoginKeyRotationValidator.cs
+++ b/src/Api/KeyManagement/Validators/WebAuthnLoginKeyRotationValidator.cs
@@ -4,7 +4,7 @@ using Bit.Core.Auth.Repositories;
using Bit.Core.Entities;
using Bit.Core.Exceptions;
-namespace Bit.Api.Auth.Validators;
+namespace Bit.Api.KeyManagement.Validators;
public class WebAuthnLoginKeyRotationValidator : IRotationValidator, IEnumerable>
{
diff --git a/src/Api/Startup.cs b/src/Api/Startup.cs
index 65935440c5..1adf3f67dc 100644
--- a/src/Api/Startup.cs
+++ b/src/Api/Startup.cs
@@ -8,13 +8,10 @@ using Bit.Core.Utilities;
using IdentityModel;
using System.Globalization;
using Bit.Api.AdminConsole.Models.Request.Organizations;
-using Bit.Api.AdminConsole.Validators;
using Bit.Api.Auth.Models.Request;
-using Bit.Api.Auth.Validators;
+using Bit.Api.KeyManagement.Validators;
using Bit.Api.Tools.Models.Request;
-using Bit.Api.Tools.Validators;
using Bit.Api.Vault.Models.Request;
-using Bit.Api.Vault.Validators;
using Bit.Core.Auth.Entities;
using Bit.Core.IdentityServer;
using Bit.SharedWeb.Health;
diff --git a/src/Core/AdminConsole/Repositories/IOrganizationUserRepository.cs b/src/Core/AdminConsole/Repositories/IOrganizationUserRepository.cs
index 488d037733..516b4614af 100644
--- a/src/Core/AdminConsole/Repositories/IOrganizationUserRepository.cs
+++ b/src/Core/AdminConsole/Repositories/IOrganizationUserRepository.cs
@@ -1,7 +1,7 @@
using Bit.Core.AdminConsole.Enums;
-using Bit.Core.Auth.UserFeatures.UserKey;
using Bit.Core.Entities;
using Bit.Core.Enums;
+using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Models.Data;
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
diff --git a/src/Core/Auth/Repositories/IEmergencyAccessRepository.cs b/src/Core/Auth/Repositories/IEmergencyAccessRepository.cs
index 6edb941d32..63ec04106e 100644
--- a/src/Core/Auth/Repositories/IEmergencyAccessRepository.cs
+++ b/src/Core/Auth/Repositories/IEmergencyAccessRepository.cs
@@ -1,6 +1,6 @@
using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Models.Data;
-using Bit.Core.Auth.UserFeatures.UserKey;
+using Bit.Core.KeyManagement.UserKey;
#nullable enable
diff --git a/src/Core/Auth/Repositories/IWebAuthnCredentialRepository.cs b/src/Core/Auth/Repositories/IWebAuthnCredentialRepository.cs
index 9a7fc88207..29ed9d2210 100644
--- a/src/Core/Auth/Repositories/IWebAuthnCredentialRepository.cs
+++ b/src/Core/Auth/Repositories/IWebAuthnCredentialRepository.cs
@@ -1,6 +1,6 @@
using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Models.Data;
-using Bit.Core.Auth.UserFeatures.UserKey;
+using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Repositories;
#nullable enable
diff --git a/src/Core/Auth/UserFeatures/UserServiceCollectionExtensions.cs b/src/Core/Auth/UserFeatures/UserServiceCollectionExtensions.cs
index 2469c124b3..df102c855f 100644
--- a/src/Core/Auth/UserFeatures/UserServiceCollectionExtensions.cs
+++ b/src/Core/Auth/UserFeatures/UserServiceCollectionExtensions.cs
@@ -5,12 +5,12 @@ using Bit.Core.Auth.UserFeatures.Registration.Implementations;
using Bit.Core.Auth.UserFeatures.TdeOffboardingPassword.Interfaces;
using Bit.Core.Auth.UserFeatures.TwoFactorAuth;
using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces;
-using Bit.Core.Auth.UserFeatures.UserKey;
-using Bit.Core.Auth.UserFeatures.UserKey.Implementations;
using Bit.Core.Auth.UserFeatures.UserMasterPassword;
using Bit.Core.Auth.UserFeatures.UserMasterPassword.Interfaces;
using Bit.Core.Auth.UserFeatures.WebAuthnLogin;
using Bit.Core.Auth.UserFeatures.WebAuthnLogin.Implementations;
+using Bit.Core.KeyManagement.UserKey;
+using Bit.Core.KeyManagement.UserKey.Implementations;
using Bit.Core.Services;
using Bit.Core.Settings;
using Microsoft.Extensions.DependencyInjection;
diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj
index 913c4b3877..2f40fb7b23 100644
--- a/src/Core/Core.csproj
+++ b/src/Core/Core.csproj
@@ -21,8 +21,8 @@
-
-
+
+
@@ -44,7 +44,7 @@
-
+
diff --git a/src/Core/Auth/Models/Data/RotateUserKeyData.cs b/src/Core/KeyManagement/Models/Data/RotateUserKeyData.cs
similarity index 89%
rename from src/Core/Auth/Models/Data/RotateUserKeyData.cs
rename to src/Core/KeyManagement/Models/Data/RotateUserKeyData.cs
index f361c2a2cc..9813f760f3 100644
--- a/src/Core/Auth/Models/Data/RotateUserKeyData.cs
+++ b/src/Core/KeyManagement/Models/Data/RotateUserKeyData.cs
@@ -1,9 +1,10 @@
using Bit.Core.Auth.Entities;
+using Bit.Core.Auth.Models.Data;
using Bit.Core.Entities;
using Bit.Core.Tools.Entities;
using Bit.Core.Vault.Entities;
-namespace Bit.Core.Auth.Models.Data;
+namespace Bit.Core.KeyManagement.Models.Data;
public class RotateUserKeyData
{
diff --git a/src/Core/KeyManagement/Models/Data/UserAsymmetricKeys.cs b/src/Core/KeyManagement/Models/Data/UserAsymmetricKeys.cs
new file mode 100644
index 0000000000..3c13629092
--- /dev/null
+++ b/src/Core/KeyManagement/Models/Data/UserAsymmetricKeys.cs
@@ -0,0 +1,9 @@
+#nullable enable
+namespace Bit.Core.KeyManagement.Models.Data;
+
+public class UserAsymmetricKeys
+{
+ public Guid UserId { get; set; }
+ public required string PublicKey { get; set; }
+ public required string UserKeyEncryptedPrivateKey { get; set; }
+}
diff --git a/src/Core/KeyManagement/Repositories/IUserAsymmetricKeysRepository.cs b/src/Core/KeyManagement/Repositories/IUserAsymmetricKeysRepository.cs
new file mode 100644
index 0000000000..fee9aee3bb
--- /dev/null
+++ b/src/Core/KeyManagement/Repositories/IUserAsymmetricKeysRepository.cs
@@ -0,0 +1,9 @@
+#nullable enable
+using Bit.Core.KeyManagement.Models.Data;
+
+namespace Bit.Core.KeyManagement.Repositories;
+
+public interface IUserAsymmetricKeysRepository
+{
+ Task RegenerateUserAsymmetricKeysAsync(UserAsymmetricKeys userAsymmetricKeys);
+}
diff --git a/src/Core/Auth/UserFeatures/UserKey/IRotateUserKeyCommand.cs b/src/Core/KeyManagement/UserKey/IRotateUserKeyCommand.cs
similarity index 91%
rename from src/Core/Auth/UserFeatures/UserKey/IRotateUserKeyCommand.cs
rename to src/Core/KeyManagement/UserKey/IRotateUserKeyCommand.cs
index cd2df59645..90dc90541f 100644
--- a/src/Core/Auth/UserFeatures/UserKey/IRotateUserKeyCommand.cs
+++ b/src/Core/KeyManagement/UserKey/IRotateUserKeyCommand.cs
@@ -1,9 +1,9 @@
-using Bit.Core.Auth.Models.Data;
-using Bit.Core.Entities;
+using Bit.Core.Entities;
+using Bit.Core.KeyManagement.Models.Data;
using Microsoft.AspNetCore.Identity;
using Microsoft.Data.SqlClient;
-namespace Bit.Core.Auth.UserFeatures.UserKey;
+namespace Bit.Core.KeyManagement.UserKey;
///
/// Responsible for rotation of a user key and updating database with re-encrypted data
diff --git a/src/Core/Auth/UserFeatures/UserKey/Implementations/RotateUserKeyCommand.cs b/src/Core/KeyManagement/UserKey/Implementations/RotateUserKeyCommand.cs
similarity index 97%
rename from src/Core/Auth/UserFeatures/UserKey/Implementations/RotateUserKeyCommand.cs
rename to src/Core/KeyManagement/UserKey/Implementations/RotateUserKeyCommand.cs
index 4c7ca20737..68b2c60293 100644
--- a/src/Core/Auth/UserFeatures/UserKey/Implementations/RotateUserKeyCommand.cs
+++ b/src/Core/KeyManagement/UserKey/Implementations/RotateUserKeyCommand.cs
@@ -1,13 +1,13 @@
-using Bit.Core.Auth.Models.Data;
-using Bit.Core.Auth.Repositories;
+using Bit.Core.Auth.Repositories;
using Bit.Core.Entities;
+using Bit.Core.KeyManagement.Models.Data;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Tools.Repositories;
using Bit.Core.Vault.Repositories;
using Microsoft.AspNetCore.Identity;
-namespace Bit.Core.Auth.UserFeatures.UserKey.Implementations;
+namespace Bit.Core.KeyManagement.UserKey.Implementations;
///
public class RotateUserKeyCommand : IRotateUserKeyCommand
diff --git a/src/Core/Models/Mail/Provider/ProviderInitiateDeleteModel.cs b/src/Core/Models/Mail/Provider/ProviderInitiateDeleteModel.cs
index 196decb5ee..a5071527fe 100644
--- a/src/Core/Models/Mail/Provider/ProviderInitiateDeleteModel.cs
+++ b/src/Core/Models/Mail/Provider/ProviderInitiateDeleteModel.cs
@@ -8,10 +8,8 @@ public class ProviderInitiateDeleteModel : BaseMailModel
Token,
ProviderNameUrlEncoded);
- public string WebVaultUrl { get; set; }
public string Token { get; set; }
public Guid ProviderId { get; set; }
- public string SiteName { get; set; }
public string ProviderName { get; set; }
public string ProviderNameUrlEncoded { get; set; }
public string ProviderBillingEmail { get; set; }
diff --git a/src/Core/Repositories/IUserRepository.cs b/src/Core/Repositories/IUserRepository.cs
index b7c654f431..22e2ec1a07 100644
--- a/src/Core/Repositories/IUserRepository.cs
+++ b/src/Core/Repositories/IUserRepository.cs
@@ -1,5 +1,5 @@
-using Bit.Core.Auth.UserFeatures.UserKey;
-using Bit.Core.Entities;
+using Bit.Core.Entities;
+using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Models.Data;
#nullable enable
diff --git a/src/Core/Tools/Repositories/ISendRepository.cs b/src/Core/Tools/Repositories/ISendRepository.cs
index 2cbcce1f92..6de89f0374 100644
--- a/src/Core/Tools/Repositories/ISendRepository.cs
+++ b/src/Core/Tools/Repositories/ISendRepository.cs
@@ -1,6 +1,6 @@
#nullable enable
-using Bit.Core.Auth.UserFeatures.UserKey;
+using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Repositories;
using Bit.Core.Tools.Entities;
diff --git a/src/Core/Vault/Repositories/ICipherRepository.cs b/src/Core/Vault/Repositories/ICipherRepository.cs
index 132aa5ac60..f3f34c595b 100644
--- a/src/Core/Vault/Repositories/ICipherRepository.cs
+++ b/src/Core/Vault/Repositories/ICipherRepository.cs
@@ -1,5 +1,5 @@
-using Bit.Core.Auth.UserFeatures.UserKey;
-using Bit.Core.Entities;
+using Bit.Core.Entities;
+using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Repositories;
using Bit.Core.Vault.Entities;
using Bit.Core.Vault.Models.Data;
diff --git a/src/Core/Vault/Repositories/IFolderRepository.cs b/src/Core/Vault/Repositories/IFolderRepository.cs
index f192437613..c4693b2a13 100644
--- a/src/Core/Vault/Repositories/IFolderRepository.cs
+++ b/src/Core/Vault/Repositories/IFolderRepository.cs
@@ -1,4 +1,4 @@
-using Bit.Core.Auth.UserFeatures.UserKey;
+using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Repositories;
using Bit.Core.Vault.Entities;
diff --git a/src/Infrastructure.Dapper/AdminConsole/Repositories/OrganizationUserRepository.cs b/src/Infrastructure.Dapper/AdminConsole/Repositories/OrganizationUserRepository.cs
index 4a205a73a8..42f79852f3 100644
--- a/src/Infrastructure.Dapper/AdminConsole/Repositories/OrganizationUserRepository.cs
+++ b/src/Infrastructure.Dapper/AdminConsole/Repositories/OrganizationUserRepository.cs
@@ -2,9 +2,9 @@
using System.Text.Json;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums;
-using Bit.Core.Auth.UserFeatures.UserKey;
using Bit.Core.Entities;
using Bit.Core.Enums;
+using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Models.Data;
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
using Bit.Core.Repositories;
diff --git a/src/Infrastructure.Dapper/Auth/Repositories/EmergencyAccessRepository.cs b/src/Infrastructure.Dapper/Auth/Repositories/EmergencyAccessRepository.cs
index e6bf92bdea..4d597ab045 100644
--- a/src/Infrastructure.Dapper/Auth/Repositories/EmergencyAccessRepository.cs
+++ b/src/Infrastructure.Dapper/Auth/Repositories/EmergencyAccessRepository.cs
@@ -1,7 +1,7 @@
using System.Data;
using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Models.Data;
-using Bit.Core.Auth.UserFeatures.UserKey;
+using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Repositories;
using Bit.Core.Settings;
using Bit.Infrastructure.Dapper.Auth.Helpers;
diff --git a/src/Infrastructure.Dapper/Auth/Repositories/WebAuthnCredentialRepository.cs b/src/Infrastructure.Dapper/Auth/Repositories/WebAuthnCredentialRepository.cs
index 0f7e1ea1b9..7dfcd15d49 100644
--- a/src/Infrastructure.Dapper/Auth/Repositories/WebAuthnCredentialRepository.cs
+++ b/src/Infrastructure.Dapper/Auth/Repositories/WebAuthnCredentialRepository.cs
@@ -2,7 +2,7 @@
using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Models.Data;
using Bit.Core.Auth.Repositories;
-using Bit.Core.Auth.UserFeatures.UserKey;
+using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Settings;
using Bit.Core.Utilities;
using Bit.Infrastructure.Dapper.Repositories;
diff --git a/src/Infrastructure.Dapper/DapperServiceCollectionExtensions.cs b/src/Infrastructure.Dapper/DapperServiceCollectionExtensions.cs
index 550c572cf5..c873f84aa0 100644
--- a/src/Infrastructure.Dapper/DapperServiceCollectionExtensions.cs
+++ b/src/Infrastructure.Dapper/DapperServiceCollectionExtensions.cs
@@ -1,6 +1,7 @@
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Auth.Repositories;
using Bit.Core.Billing.Repositories;
+using Bit.Core.KeyManagement.Repositories;
using Bit.Core.NotificationCenter.Repositories;
using Bit.Core.Repositories;
using Bit.Core.SecretsManager.Repositories;
@@ -9,6 +10,7 @@ using Bit.Core.Vault.Repositories;
using Bit.Infrastructure.Dapper.AdminConsole.Repositories;
using Bit.Infrastructure.Dapper.Auth.Repositories;
using Bit.Infrastructure.Dapper.Billing.Repositories;
+using Bit.Infrastructure.Dapper.KeyManagement.Repositories;
using Bit.Infrastructure.Dapper.NotificationCenter.Repositories;
using Bit.Infrastructure.Dapper.Repositories;
using Bit.Infrastructure.Dapper.SecretsManager.Repositories;
@@ -60,6 +62,7 @@ public static class DapperServiceCollectionExtensions
.AddSingleton();
services.AddSingleton();
services.AddSingleton();
+ services.AddSingleton();
if (selfHosted)
{
diff --git a/src/Infrastructure.Dapper/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs b/src/Infrastructure.Dapper/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs
new file mode 100644
index 0000000000..f176327f4f
--- /dev/null
+++ b/src/Infrastructure.Dapper/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs
@@ -0,0 +1,36 @@
+#nullable enable
+using System.Data;
+using Bit.Core.KeyManagement.Models.Data;
+using Bit.Core.KeyManagement.Repositories;
+using Bit.Core.Settings;
+using Bit.Infrastructure.Dapper.Repositories;
+using Dapper;
+using Microsoft.Data.SqlClient;
+
+namespace Bit.Infrastructure.Dapper.KeyManagement.Repositories;
+
+public class UserAsymmetricKeysRepository : BaseRepository, IUserAsymmetricKeysRepository
+{
+ public UserAsymmetricKeysRepository(GlobalSettings globalSettings)
+ : this(globalSettings.SqlServer.ConnectionString, globalSettings.SqlServer.ReadOnlyConnectionString)
+ {
+ }
+
+ public UserAsymmetricKeysRepository(string connectionString, string readOnlyConnectionString) : base(
+ connectionString, readOnlyConnectionString)
+ {
+ }
+
+ public async Task RegenerateUserAsymmetricKeysAsync(UserAsymmetricKeys userAsymmetricKeys)
+ {
+ await using var connection = new SqlConnection(ConnectionString);
+
+ await connection.ExecuteAsync("[dbo].[UserAsymmetricKeys_Regenerate]",
+ new
+ {
+ userAsymmetricKeys.UserId,
+ userAsymmetricKeys.PublicKey,
+ PrivateKey = userAsymmetricKeys.UserKeyEncryptedPrivateKey
+ }, commandType: CommandType.StoredProcedure);
+ }
+}
diff --git a/src/Infrastructure.Dapper/Repositories/UserRepository.cs b/src/Infrastructure.Dapper/Repositories/UserRepository.cs
index a96c986778..9e613fdf08 100644
--- a/src/Infrastructure.Dapper/Repositories/UserRepository.cs
+++ b/src/Infrastructure.Dapper/Repositories/UserRepository.cs
@@ -1,8 +1,8 @@
using System.Data;
using System.Text.Json;
using Bit.Core;
-using Bit.Core.Auth.UserFeatures.UserKey;
using Bit.Core.Entities;
+using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Models.Data;
using Bit.Core.Repositories;
using Bit.Core.Settings;
diff --git a/src/Infrastructure.Dapper/Tools/Repositories/SendRepository.cs b/src/Infrastructure.Dapper/Tools/Repositories/SendRepository.cs
index 12fbbd4eb6..81a94f0f7c 100644
--- a/src/Infrastructure.Dapper/Tools/Repositories/SendRepository.cs
+++ b/src/Infrastructure.Dapper/Tools/Repositories/SendRepository.cs
@@ -1,7 +1,7 @@
#nullable enable
using System.Data;
-using Bit.Core.Auth.UserFeatures.UserKey;
+using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Settings;
using Bit.Core.Tools.Entities;
using Bit.Core.Tools.Repositories;
diff --git a/src/Infrastructure.Dapper/Vault/Repositories/CipherRepository.cs b/src/Infrastructure.Dapper/Vault/Repositories/CipherRepository.cs
index 697edb3f37..69b1383f4b 100644
--- a/src/Infrastructure.Dapper/Vault/Repositories/CipherRepository.cs
+++ b/src/Infrastructure.Dapper/Vault/Repositories/CipherRepository.cs
@@ -1,7 +1,7 @@
using System.Data;
using System.Text.Json;
-using Bit.Core.Auth.UserFeatures.UserKey;
using Bit.Core.Entities;
+using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Settings;
using Bit.Core.Tools.Entities;
using Bit.Core.Vault.Entities;
diff --git a/src/Infrastructure.Dapper/Vault/Repositories/FolderRepository.cs b/src/Infrastructure.Dapper/Vault/Repositories/FolderRepository.cs
index bf1548b24c..a6f6f2ee22 100644
--- a/src/Infrastructure.Dapper/Vault/Repositories/FolderRepository.cs
+++ b/src/Infrastructure.Dapper/Vault/Repositories/FolderRepository.cs
@@ -1,5 +1,5 @@
using System.Data;
-using Bit.Core.Auth.UserFeatures.UserKey;
+using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Settings;
using Bit.Core.Vault.Entities;
using Bit.Core.Vault.Repositories;
diff --git a/src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs b/src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs
index 7c56ef799b..007ff1a7ff 100644
--- a/src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs
+++ b/src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs
@@ -1,7 +1,7 @@
using AutoMapper;
using Bit.Core.AdminConsole.Enums;
-using Bit.Core.Auth.UserFeatures.UserKey;
using Bit.Core.Enums;
+using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Models.Data;
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
using Bit.Core.Repositories;
diff --git a/src/Infrastructure.EntityFramework/Auth/Repositories/EmergencyAccessRepository.cs b/src/Infrastructure.EntityFramework/Auth/Repositories/EmergencyAccessRepository.cs
index 22ca89fa0a..e1ea9bc03f 100644
--- a/src/Infrastructure.EntityFramework/Auth/Repositories/EmergencyAccessRepository.cs
+++ b/src/Infrastructure.EntityFramework/Auth/Repositories/EmergencyAccessRepository.cs
@@ -1,7 +1,7 @@
using AutoMapper;
using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Models.Data;
-using Bit.Core.Auth.UserFeatures.UserKey;
+using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Repositories;
using Bit.Infrastructure.EntityFramework.Auth.Models;
using Bit.Infrastructure.EntityFramework.Auth.Repositories.Queries;
diff --git a/src/Infrastructure.EntityFramework/Auth/Repositories/WebAuthnCredentialRepository.cs b/src/Infrastructure.EntityFramework/Auth/Repositories/WebAuthnCredentialRepository.cs
index b670a3f1de..e198a5f79d 100644
--- a/src/Infrastructure.EntityFramework/Auth/Repositories/WebAuthnCredentialRepository.cs
+++ b/src/Infrastructure.EntityFramework/Auth/Repositories/WebAuthnCredentialRepository.cs
@@ -1,7 +1,7 @@
using AutoMapper;
using Bit.Core.Auth.Models.Data;
using Bit.Core.Auth.Repositories;
-using Bit.Core.Auth.UserFeatures.UserKey;
+using Bit.Core.KeyManagement.UserKey;
using Bit.Infrastructure.EntityFramework.Auth.Models;
using Bit.Infrastructure.EntityFramework.Repositories;
using Microsoft.EntityFrameworkCore;
diff --git a/src/Infrastructure.EntityFramework/EntityFrameworkServiceCollectionExtensions.cs b/src/Infrastructure.EntityFramework/EntityFrameworkServiceCollectionExtensions.cs
index b8c84f649f..b2eefe4523 100644
--- a/src/Infrastructure.EntityFramework/EntityFrameworkServiceCollectionExtensions.cs
+++ b/src/Infrastructure.EntityFramework/EntityFrameworkServiceCollectionExtensions.cs
@@ -2,6 +2,7 @@
using Bit.Core.Auth.Repositories;
using Bit.Core.Billing.Repositories;
using Bit.Core.Enums;
+using Bit.Core.KeyManagement.Repositories;
using Bit.Core.NotificationCenter.Repositories;
using Bit.Core.Repositories;
using Bit.Core.SecretsManager.Repositories;
@@ -10,6 +11,7 @@ using Bit.Core.Vault.Repositories;
using Bit.Infrastructure.EntityFramework.AdminConsole.Repositories;
using Bit.Infrastructure.EntityFramework.Auth.Repositories;
using Bit.Infrastructure.EntityFramework.Billing.Repositories;
+using Bit.Infrastructure.EntityFramework.KeyManagement.Repositories;
using Bit.Infrastructure.EntityFramework.NotificationCenter.Repositories;
using Bit.Infrastructure.EntityFramework.Repositories;
using Bit.Infrastructure.EntityFramework.SecretsManager.Repositories;
@@ -97,6 +99,7 @@ public static class EntityFrameworkServiceCollectionExtensions
.AddSingleton();
services.AddSingleton();
services.AddSingleton();
+ services.AddSingleton();
if (selfHosted)
{
diff --git a/src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs b/src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs
new file mode 100644
index 0000000000..c680424f56
--- /dev/null
+++ b/src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs
@@ -0,0 +1,34 @@
+#nullable enable
+using AutoMapper;
+using Bit.Core.KeyManagement.Models.Data;
+using Bit.Core.KeyManagement.Repositories;
+using Bit.Infrastructure.EntityFramework.Repositories;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Bit.Infrastructure.EntityFramework.KeyManagement.Repositories;
+
+public class UserAsymmetricKeysRepository : BaseEntityFrameworkRepository, IUserAsymmetricKeysRepository
+{
+ public UserAsymmetricKeysRepository(IServiceScopeFactory serviceScopeFactory, IMapper mapper) : base(
+ serviceScopeFactory,
+ mapper)
+ {
+ }
+
+ public async Task RegenerateUserAsymmetricKeysAsync(UserAsymmetricKeys userAsymmetricKeys)
+ {
+ await using var scope = ServiceScopeFactory.CreateAsyncScope();
+ var dbContext = GetDatabaseContext(scope);
+
+ var entity = await dbContext.Users.FindAsync(userAsymmetricKeys.UserId);
+ if (entity != null)
+ {
+ var utcNow = DateTime.UtcNow;
+ entity.PublicKey = userAsymmetricKeys.PublicKey;
+ entity.PrivateKey = userAsymmetricKeys.UserKeyEncryptedPrivateKey;
+ entity.RevisionDate = utcNow;
+ entity.AccountRevisionDate = utcNow;
+ await dbContext.SaveChangesAsync();
+ }
+ }
+}
diff --git a/src/Infrastructure.EntityFramework/Repositories/UserRepository.cs b/src/Infrastructure.EntityFramework/Repositories/UserRepository.cs
index 735625ce42..d234d25455 100644
--- a/src/Infrastructure.EntityFramework/Repositories/UserRepository.cs
+++ b/src/Infrastructure.EntityFramework/Repositories/UserRepository.cs
@@ -1,5 +1,5 @@
using AutoMapper;
-using Bit.Core.Auth.UserFeatures.UserKey;
+using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Repositories;
using Bit.Infrastructure.EntityFramework.Models;
using Microsoft.EntityFrameworkCore;
diff --git a/src/Infrastructure.EntityFramework/Tools/Repositories/SendRepository.cs b/src/Infrastructure.EntityFramework/Tools/Repositories/SendRepository.cs
index 2db07f154b..adf3fcc1f1 100644
--- a/src/Infrastructure.EntityFramework/Tools/Repositories/SendRepository.cs
+++ b/src/Infrastructure.EntityFramework/Tools/Repositories/SendRepository.cs
@@ -1,7 +1,7 @@
#nullable enable
using AutoMapper;
-using Bit.Core.Auth.UserFeatures.UserKey;
+using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Tools.Repositories;
using Bit.Infrastructure.EntityFramework.Models;
using Bit.Infrastructure.EntityFramework.Repositories;
diff --git a/src/Infrastructure.EntityFramework/Vault/Repositories/CipherRepository.cs b/src/Infrastructure.EntityFramework/Vault/Repositories/CipherRepository.cs
index b94cbad7ce..c12167a78c 100644
--- a/src/Infrastructure.EntityFramework/Vault/Repositories/CipherRepository.cs
+++ b/src/Infrastructure.EntityFramework/Vault/Repositories/CipherRepository.cs
@@ -1,7 +1,7 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using AutoMapper;
-using Bit.Core.Auth.UserFeatures.UserKey;
+using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Utilities;
using Bit.Core.Vault.Enums;
using Bit.Core.Vault.Models.Data;
diff --git a/src/Infrastructure.EntityFramework/Vault/Repositories/FolderRepository.cs b/src/Infrastructure.EntityFramework/Vault/Repositories/FolderRepository.cs
index 0bab189de9..09ac256332 100644
--- a/src/Infrastructure.EntityFramework/Vault/Repositories/FolderRepository.cs
+++ b/src/Infrastructure.EntityFramework/Vault/Repositories/FolderRepository.cs
@@ -1,5 +1,5 @@
using AutoMapper;
-using Bit.Core.Auth.UserFeatures.UserKey;
+using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Vault.Repositories;
using Bit.Infrastructure.EntityFramework.Repositories;
using Bit.Infrastructure.EntityFramework.Vault.Models;
diff --git a/src/Sql/KeyManagement/dbo/Stored Procedures/UserAsymmetricKeys_Regenerate.sql b/src/Sql/KeyManagement/dbo/Stored Procedures/UserAsymmetricKeys_Regenerate.sql
new file mode 100644
index 0000000000..26d0c40183
--- /dev/null
+++ b/src/Sql/KeyManagement/dbo/Stored Procedures/UserAsymmetricKeys_Regenerate.sql
@@ -0,0 +1,16 @@
+CREATE PROCEDURE [dbo].[UserAsymmetricKeys_Regenerate]
+ @UserId UNIQUEIDENTIFIER,
+ @PublicKey VARCHAR(MAX),
+ @PrivateKey VARCHAR(MAX)
+AS
+BEGIN
+ SET NOCOUNT ON
+ DECLARE @UtcNow DATETIME2(7) = GETUTCDATE();
+
+ UPDATE [dbo].[User]
+ SET [PublicKey] = @PublicKey,
+ [PrivateKey] = @PrivateKey,
+ [RevisionDate] = @UtcNow,
+ [AccountRevisionDate] = @UtcNow
+ WHERE [Id] = @UserId
+END
diff --git a/test/Api.Test/Auth/Controllers/AccountsControllerTests.cs b/test/Api.Test/Auth/Controllers/AccountsControllerTests.cs
index 13c80f8563..4a0a29a5d4 100644
--- a/test/Api.Test/Auth/Controllers/AccountsControllerTests.cs
+++ b/test/Api.Test/Auth/Controllers/AccountsControllerTests.cs
@@ -4,7 +4,7 @@ using Bit.Api.Auth.Controllers;
using Bit.Api.Auth.Models.Request;
using Bit.Api.Auth.Models.Request.Accounts;
using Bit.Api.Auth.Models.Request.WebAuthn;
-using Bit.Api.Auth.Validators;
+using Bit.Api.KeyManagement.Validators;
using Bit.Api.Tools.Models.Request;
using Bit.Api.Vault.Models.Request;
using Bit.Core;
@@ -14,12 +14,12 @@ using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Models.Api.Request.Accounts;
using Bit.Core.Auth.Models.Data;
using Bit.Core.Auth.UserFeatures.TdeOffboardingPassword.Interfaces;
-using Bit.Core.Auth.UserFeatures.UserKey;
using Bit.Core.Auth.UserFeatures.UserMasterPassword.Interfaces;
using Bit.Core.Billing.Services;
using Bit.Core.Context;
using Bit.Core.Entities;
using Bit.Core.Exceptions;
+using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Settings;
diff --git a/test/Api.Test/Vault/Validators/CipherRotationValidatorTests.cs b/test/Api.Test/KeyManagement/Validators/CipherRotationValidatorTests.cs
similarity index 94%
rename from test/Api.Test/Vault/Validators/CipherRotationValidatorTests.cs
rename to test/Api.Test/KeyManagement/Validators/CipherRotationValidatorTests.cs
index 632bb49676..a4633e78cb 100644
--- a/test/Api.Test/Vault/Validators/CipherRotationValidatorTests.cs
+++ b/test/Api.Test/KeyManagement/Validators/CipherRotationValidatorTests.cs
@@ -1,5 +1,5 @@
-using Bit.Api.Vault.Models.Request;
-using Bit.Api.Vault.Validators;
+using Bit.Api.KeyManagement.Validators;
+using Bit.Api.Vault.Models.Request;
using Bit.Core.Entities;
using Bit.Core.Exceptions;
using Bit.Core.Vault.Models.Data;
@@ -9,7 +9,7 @@ using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
using Xunit;
-namespace Bit.Api.Test.Vault.Validators;
+namespace Bit.Api.Test.KeyManagement.Validators;
[SutProviderCustomize]
public class CipherRotationValidatorTests
diff --git a/test/Api.Test/Auth/Validators/EmergencyAccessRotationValidatorTests.cs b/test/Api.Test/KeyManagement/Validators/EmergencyAccessRotationValidatorTests.cs
similarity index 98%
rename from test/Api.Test/Auth/Validators/EmergencyAccessRotationValidatorTests.cs
rename to test/Api.Test/KeyManagement/Validators/EmergencyAccessRotationValidatorTests.cs
index c75ccd6437..e00129fd89 100644
--- a/test/Api.Test/Auth/Validators/EmergencyAccessRotationValidatorTests.cs
+++ b/test/Api.Test/KeyManagement/Validators/EmergencyAccessRotationValidatorTests.cs
@@ -1,5 +1,5 @@
using Bit.Api.Auth.Models.Request;
-using Bit.Api.Auth.Validators;
+using Bit.Api.KeyManagement.Validators;
using Bit.Core.Auth.Models.Data;
using Bit.Core.Entities;
using Bit.Core.Exceptions;
@@ -10,7 +10,7 @@ using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
using Xunit;
-namespace Bit.Api.Test.Auth.Validators;
+namespace Bit.Api.Test.KeyManagement.Validators;
[SutProviderCustomize]
public class EmergencyAccessRotationValidatorTests
diff --git a/test/Api.Test/Vault/Validators/FolderRotationValidatorTests.cs b/test/Api.Test/KeyManagement/Validators/FolderRotationValidatorTests.cs
similarity index 94%
rename from test/Api.Test/Vault/Validators/FolderRotationValidatorTests.cs
rename to test/Api.Test/KeyManagement/Validators/FolderRotationValidatorTests.cs
index 0888fd32d4..3778741bbc 100644
--- a/test/Api.Test/Vault/Validators/FolderRotationValidatorTests.cs
+++ b/test/Api.Test/KeyManagement/Validators/FolderRotationValidatorTests.cs
@@ -1,5 +1,5 @@
-using Bit.Api.Vault.Models.Request;
-using Bit.Api.Vault.Validators;
+using Bit.Api.KeyManagement.Validators;
+using Bit.Api.Vault.Models.Request;
using Bit.Core.Entities;
using Bit.Core.Exceptions;
using Bit.Core.Vault.Entities;
@@ -9,7 +9,7 @@ using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
using Xunit;
-namespace Bit.Api.Test.Vault.Validators;
+namespace Bit.Api.Test.KeyManagement.Validators;
[SutProviderCustomize]
public class FolderRotationValidatorTests
diff --git a/test/Api.Test/AdminConsole/Validators/OrganizationUserRotationValidatorTests.cs b/test/Api.Test/KeyManagement/Validators/OrganizationUserRotationValidatorTests.cs
similarity index 98%
rename from test/Api.Test/AdminConsole/Validators/OrganizationUserRotationValidatorTests.cs
rename to test/Api.Test/KeyManagement/Validators/OrganizationUserRotationValidatorTests.cs
index 5d4ffeef60..964c801903 100644
--- a/test/Api.Test/AdminConsole/Validators/OrganizationUserRotationValidatorTests.cs
+++ b/test/Api.Test/KeyManagement/Validators/OrganizationUserRotationValidatorTests.cs
@@ -1,5 +1,5 @@
using Bit.Api.AdminConsole.Models.Request.Organizations;
-using Bit.Api.AdminConsole.Validators;
+using Bit.Api.KeyManagement.Validators;
using Bit.Core.Entities;
using Bit.Core.Exceptions;
using Bit.Core.Repositories;
@@ -8,7 +8,7 @@ using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
using Xunit;
-namespace Bit.Api.Test.AdminConsole.Validators;
+namespace Bit.Api.Test.KeyManagement.Validators;
[SutProviderCustomize]
public class OrganizationUserRotationValidatorTests
diff --git a/test/Api.Test/Tools/Validators/SendRotationValidatorTests.cs b/test/Api.Test/KeyManagement/Validators/SendRotationValidatorTests.cs
similarity index 98%
rename from test/Api.Test/Tools/Validators/SendRotationValidatorTests.cs
rename to test/Api.Test/KeyManagement/Validators/SendRotationValidatorTests.cs
index 76f938d1c4..842343ba33 100644
--- a/test/Api.Test/Tools/Validators/SendRotationValidatorTests.cs
+++ b/test/Api.Test/KeyManagement/Validators/SendRotationValidatorTests.cs
@@ -1,7 +1,7 @@
using System.Text.Json;
+using Bit.Api.KeyManagement.Validators;
using Bit.Api.Tools.Models;
using Bit.Api.Tools.Models.Request;
-using Bit.Api.Tools.Validators;
using Bit.Core.Entities;
using Bit.Core.Exceptions;
using Bit.Core.Tools.Entities;
@@ -14,7 +14,7 @@ using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
using Xunit;
-namespace Bit.Api.Test.Tools.Validators;
+namespace Bit.Api.Test.KeyManagement.Validators;
[SutProviderCustomize]
public class SendRotationValidatorTests
diff --git a/test/Api.Test/Auth/Validators/WebauthnLoginKeyRotationValidatorTests.cs b/test/Api.Test/KeyManagement/Validators/WebauthnLoginKeyRotationValidatorTests.cs
similarity index 97%
rename from test/Api.Test/Auth/Validators/WebauthnLoginKeyRotationValidatorTests.cs
rename to test/Api.Test/KeyManagement/Validators/WebauthnLoginKeyRotationValidatorTests.cs
index 97eadcbdc3..de661497e4 100644
--- a/test/Api.Test/Auth/Validators/WebauthnLoginKeyRotationValidatorTests.cs
+++ b/test/Api.Test/KeyManagement/Validators/WebauthnLoginKeyRotationValidatorTests.cs
@@ -1,5 +1,5 @@
using Bit.Api.Auth.Models.Request.WebAuthn;
-using Bit.Api.Auth.Validators;
+using Bit.Api.KeyManagement.Validators;
using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Repositories;
using Bit.Core.Entities;
@@ -9,7 +9,7 @@ using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
using Xunit;
-namespace Bit.Api.Test.Auth.Validators;
+namespace Bit.Api.Test.KeyManagement.Validators;
[SutProviderCustomize]
public class WebAuthnLoginKeyRotationValidatorTests
diff --git a/test/Core.Test/Auth/UserFeatures/UserKey/RotateUserKeyCommandTests.cs b/test/Core.Test/KeyManagement/UserKey/RotateUserKeyCommandTests.cs
similarity index 95%
rename from test/Core.Test/Auth/UserFeatures/UserKey/RotateUserKeyCommandTests.cs
rename to test/Core.Test/KeyManagement/UserKey/RotateUserKeyCommandTests.cs
index 41c78f4272..b650d17240 100644
--- a/test/Core.Test/Auth/UserFeatures/UserKey/RotateUserKeyCommandTests.cs
+++ b/test/Core.Test/KeyManagement/UserKey/RotateUserKeyCommandTests.cs
@@ -1,8 +1,8 @@
using Bit.Core.Auth.Entities;
-using Bit.Core.Auth.Models.Data;
using Bit.Core.Auth.Repositories;
-using Bit.Core.Auth.UserFeatures.UserKey.Implementations;
using Bit.Core.Entities;
+using Bit.Core.KeyManagement.Models.Data;
+using Bit.Core.KeyManagement.UserKey.Implementations;
using Bit.Core.Services;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
@@ -10,7 +10,7 @@ using Microsoft.AspNetCore.Identity;
using NSubstitute;
using Xunit;
-namespace Bit.Core.Test.Auth.UserFeatures.UserKey;
+namespace Bit.Core.Test.KeyManagement.UserFeatures.UserKey;
[SutProviderCustomize]
public class RotateUserKeyCommandTests
diff --git a/util/Migrator/DbScripts/2024-11-21_00_AddUserAsymmetricKeysRegenerate.sql b/util/Migrator/DbScripts/2024-11-21_00_AddUserAsymmetricKeysRegenerate.sql
new file mode 100644
index 0000000000..e1f5431145
--- /dev/null
+++ b/util/Migrator/DbScripts/2024-11-21_00_AddUserAsymmetricKeysRegenerate.sql
@@ -0,0 +1,16 @@
+CREATE OR ALTER PROCEDURE [dbo].[UserAsymmetricKeys_Regenerate]
+ @UserId UNIQUEIDENTIFIER,
+ @PublicKey VARCHAR(MAX),
+ @PrivateKey VARCHAR(MAX)
+AS
+BEGIN
+ SET NOCOUNT ON
+ DECLARE @UtcNow DATETIME2(7) = GETUTCDATE();
+
+ UPDATE [dbo].[User]
+ SET [PublicKey] = @PublicKey,
+ [PrivateKey] = @PrivateKey,
+ [RevisionDate] = @UtcNow,
+ [AccountRevisionDate] = @UtcNow
+ WHERE [Id] = @UserId
+END