From a6f21181eb879095f14519db5b2221dfcfe0548b Mon Sep 17 00:00:00 2001 From: Thomas Avery Date: Tue, 15 Oct 2024 17:01:42 -0500 Subject: [PATCH 1/5] Add stored procedure --- .../UserAsymmetricKeys_Regenerate.sql | 17 +++++++++++++++++ ...10-15_01_AddUserAsymmetricKeysRegenerate.sql | 13 +++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/Sql/KeyManagement/dbo/Stored Procedures/UserAsymmetricKeys_Regenerate.sql create mode 100644 util/Migrator/DbScripts/2024-10-15_01_AddUserAsymmetricKeysRegenerate.sql 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 000000000000..17273fc33e84 --- /dev/null +++ b/src/Sql/KeyManagement/dbo/Stored Procedures/UserAsymmetricKeys_Regenerate.sql @@ -0,0 +1,17 @@ +CREATE PROCEDURE [dbo].[UserAsymmetricKeys_Regenerate] + @UserId UNIQUEIDENTIFIER OUTPUT, + @PublicKey VARCHAR(MAX), + @PrivateKey VARCHAR(MAX) +AS +BEGIN + SET NOCOUNT ON + + BEGIN TRANSACTION UserAsymmetricKeys_Regenerate + + UPDATE [dbo].[User] + SET [PublicKey] = @PublicKey, + [PrivateKey] = @PrivateKey + WHERE [Id] = @UserId + + COMMIT TRANSACTION UserAsymmetricKeys_Regenerate +END diff --git a/util/Migrator/DbScripts/2024-10-15_01_AddUserAsymmetricKeysRegenerate.sql b/util/Migrator/DbScripts/2024-10-15_01_AddUserAsymmetricKeysRegenerate.sql new file mode 100644 index 000000000000..34eb1df975f5 --- /dev/null +++ b/util/Migrator/DbScripts/2024-10-15_01_AddUserAsymmetricKeysRegenerate.sql @@ -0,0 +1,13 @@ +CREATE OR ALTER PROCEDURE [dbo].[UserAsymmetricKeys_Regenerate] + @UserId UNIQUEIDENTIFIER OUTPUT, + @PublicKey VARCHAR(MAX), + @PrivateKey VARCHAR(MAX) +AS +BEGIN + SET NOCOUNT ON + + UPDATE [dbo].[User] + SET [PublicKey] = @PublicKey, + [PrivateKey] = @PrivateKey + WHERE [Id] = @UserId +END From 4f49c0b3fcaef8a588467ec2ed9524e57aa90f7a Mon Sep 17 00:00:00 2001 From: Thomas Avery Date: Tue, 15 Oct 2024 17:02:06 -0500 Subject: [PATCH 2/5] Add repository --- .../Models/Data/UserAsymmetricKeys.cs | 9 ++++++ .../IUserAsymmetricKeysRepository.cs | 9 ++++++ .../DapperServiceCollectionExtensions.cs | 3 ++ .../UserAsymmetricKeysRepository.cs | 31 +++++++++++++++++++ ...ityFrameworkServiceCollectionExtensions.cs | 3 ++ .../UserAsymmetricKeysRepository.cs | 31 +++++++++++++++++++ 6 files changed, 86 insertions(+) create mode 100644 src/Core/KeyManagement/Models/Data/UserAsymmetricKeys.cs create mode 100644 src/Core/KeyManagement/Repositories/IUserAsymmetricKeysRepository.cs create mode 100644 src/Infrastructure.Dapper/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs create mode 100644 src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs diff --git a/src/Core/KeyManagement/Models/Data/UserAsymmetricKeys.cs b/src/Core/KeyManagement/Models/Data/UserAsymmetricKeys.cs new file mode 100644 index 000000000000..3c1362909260 --- /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 000000000000..fee9aee3bbb3 --- /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/Infrastructure.Dapper/DapperServiceCollectionExtensions.cs b/src/Infrastructure.Dapper/DapperServiceCollectionExtensions.cs index 6cfa1ef8b34a..48e730e98de4 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.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; @@ -58,6 +60,7 @@ public static void AddDapperRepositories(this IServiceCollection services, bool 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 000000000000..b232b0cf8cc2 --- /dev/null +++ b/src/Infrastructure.Dapper/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs @@ -0,0 +1,31 @@ +#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]", + userAsymmetricKeys, commandType: CommandType.StoredProcedure); + } +} diff --git a/src/Infrastructure.EntityFramework/EntityFrameworkServiceCollectionExtensions.cs b/src/Infrastructure.EntityFramework/EntityFrameworkServiceCollectionExtensions.cs index ad0b46277b78..6b6c515e0fe3 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.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; @@ -95,6 +97,7 @@ public static void AddPasswordManagerEFRepositories(this IServiceCollection serv 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 000000000000..a2bbe6bbc729 --- /dev/null +++ b/src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs @@ -0,0 +1,31 @@ +#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) + { + entity.PublicKey = userAsymmetricKeys.PublicKey; + entity.PrivateKey = userAsymmetricKeys.UserKeyEncryptedPrivateKey; + await dbContext.SaveChangesAsync(); + } + } +} From 2cb60452e8a6de4c46321abf32cdac3172baaa0c Mon Sep 17 00:00:00 2001 From: Thomas Avery Date: Tue, 15 Oct 2024 17:12:37 -0500 Subject: [PATCH 3/5] Update SQL stored procedure --- .../dbo/Stored Procedures/UserAsymmetricKeys_Regenerate.sql | 6 +----- .../2024-10-15_01_AddUserAsymmetricKeysRegenerate.sql | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Sql/KeyManagement/dbo/Stored Procedures/UserAsymmetricKeys_Regenerate.sql b/src/Sql/KeyManagement/dbo/Stored Procedures/UserAsymmetricKeys_Regenerate.sql index 17273fc33e84..31508d983245 100644 --- a/src/Sql/KeyManagement/dbo/Stored Procedures/UserAsymmetricKeys_Regenerate.sql +++ b/src/Sql/KeyManagement/dbo/Stored Procedures/UserAsymmetricKeys_Regenerate.sql @@ -1,17 +1,13 @@ CREATE PROCEDURE [dbo].[UserAsymmetricKeys_Regenerate] - @UserId UNIQUEIDENTIFIER OUTPUT, + @UserId UNIQUEIDENTIFIER, @PublicKey VARCHAR(MAX), @PrivateKey VARCHAR(MAX) AS BEGIN SET NOCOUNT ON - BEGIN TRANSACTION UserAsymmetricKeys_Regenerate - UPDATE [dbo].[User] SET [PublicKey] = @PublicKey, [PrivateKey] = @PrivateKey WHERE [Id] = @UserId - - COMMIT TRANSACTION UserAsymmetricKeys_Regenerate END diff --git a/util/Migrator/DbScripts/2024-10-15_01_AddUserAsymmetricKeysRegenerate.sql b/util/Migrator/DbScripts/2024-10-15_01_AddUserAsymmetricKeysRegenerate.sql index 34eb1df975f5..926af154338e 100644 --- a/util/Migrator/DbScripts/2024-10-15_01_AddUserAsymmetricKeysRegenerate.sql +++ b/util/Migrator/DbScripts/2024-10-15_01_AddUserAsymmetricKeysRegenerate.sql @@ -1,5 +1,5 @@ CREATE OR ALTER PROCEDURE [dbo].[UserAsymmetricKeys_Regenerate] - @UserId UNIQUEIDENTIFIER OUTPUT, + @UserId UNIQUEIDENTIFIER, @PublicKey VARCHAR(MAX), @PrivateKey VARCHAR(MAX) AS From 8a1c761d8ba865c408d98bb4b3f47728d00a9004 Mon Sep 17 00:00:00 2001 From: Thomas Avery Date: Wed, 16 Oct 2024 14:29:12 -0500 Subject: [PATCH 4/5] Bump revision dates --- .../Repositories/UserAsymmetricKeysRepository.cs | 3 +++ .../dbo/Stored Procedures/UserAsymmetricKeys_Regenerate.sql | 5 ++++- .../2024-10-15_01_AddUserAsymmetricKeysRegenerate.sql | 5 ++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs b/src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs index a2bbe6bbc729..c680424f56a2 100644 --- a/src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs +++ b/src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs @@ -23,8 +23,11 @@ public async Task RegenerateUserAsymmetricKeysAsync(UserAsymmetricKeys userAsymm 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/Sql/KeyManagement/dbo/Stored Procedures/UserAsymmetricKeys_Regenerate.sql b/src/Sql/KeyManagement/dbo/Stored Procedures/UserAsymmetricKeys_Regenerate.sql index 31508d983245..26d0c40183bb 100644 --- a/src/Sql/KeyManagement/dbo/Stored Procedures/UserAsymmetricKeys_Regenerate.sql +++ b/src/Sql/KeyManagement/dbo/Stored Procedures/UserAsymmetricKeys_Regenerate.sql @@ -5,9 +5,12 @@ CREATE PROCEDURE [dbo].[UserAsymmetricKeys_Regenerate] AS BEGIN SET NOCOUNT ON + DECLARE @UtcNow DATETIME2(7) = GETUTCDATE(); UPDATE [dbo].[User] SET [PublicKey] = @PublicKey, - [PrivateKey] = @PrivateKey + [PrivateKey] = @PrivateKey, + [RevisionDate] = @UtcNow, + [AccountRevisionDate] = @UtcNow WHERE [Id] = @UserId END diff --git a/util/Migrator/DbScripts/2024-10-15_01_AddUserAsymmetricKeysRegenerate.sql b/util/Migrator/DbScripts/2024-10-15_01_AddUserAsymmetricKeysRegenerate.sql index 926af154338e..e1f5431145eb 100644 --- a/util/Migrator/DbScripts/2024-10-15_01_AddUserAsymmetricKeysRegenerate.sql +++ b/util/Migrator/DbScripts/2024-10-15_01_AddUserAsymmetricKeysRegenerate.sql @@ -5,9 +5,12 @@ CREATE OR ALTER PROCEDURE [dbo].[UserAsymmetricKeys_Regenerate] AS BEGIN SET NOCOUNT ON + DECLARE @UtcNow DATETIME2(7) = GETUTCDATE(); UPDATE [dbo].[User] SET [PublicKey] = @PublicKey, - [PrivateKey] = @PrivateKey + [PrivateKey] = @PrivateKey, + [RevisionDate] = @UtcNow, + [AccountRevisionDate] = @UtcNow WHERE [Id] = @UserId END From 9278677d3065435027ea97c22ba81266fd33e99a Mon Sep 17 00:00:00 2001 From: Thomas Avery Date: Wed, 16 Oct 2024 14:29:27 -0500 Subject: [PATCH 5/5] fix dapper call --- .../Repositories/UserAsymmetricKeysRepository.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Infrastructure.Dapper/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs b/src/Infrastructure.Dapper/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs index b232b0cf8cc2..f176327f4ff8 100644 --- a/src/Infrastructure.Dapper/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs +++ b/src/Infrastructure.Dapper/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs @@ -26,6 +26,11 @@ public async Task RegenerateUserAsymmetricKeysAsync(UserAsymmetricKeys userAsymm await using var connection = new SqlConnection(ConnectionString); await connection.ExecuteAsync("[dbo].[UserAsymmetricKeys_Regenerate]", - userAsymmetricKeys, commandType: CommandType.StoredProcedure); + new + { + userAsymmetricKeys.UserId, + userAsymmetricKeys.PublicKey, + PrivateKey = userAsymmetricKeys.UserKeyEncryptedPrivateKey + }, commandType: CommandType.StoredProcedure); } }