Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PM-13706] Add repository + stored procedures for private key regeneration #4898

Merged
merged 12 commits into from
Nov 21, 2024
9 changes: 9 additions & 0 deletions src/Core/KeyManagement/Models/Data/UserAsymmetricKeys.cs
Original file line number Diff line number Diff line change
@@ -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; }

Check warning on line 8 in src/Core/KeyManagement/Models/Data/UserAsymmetricKeys.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/KeyManagement/Models/Data/UserAsymmetricKeys.cs#L6-L8

Added lines #L6 - L8 were not covered by tests
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
๏ปฟ#nullable enable
using Bit.Core.KeyManagement.Models.Data;

namespace Bit.Core.KeyManagement.Repositories;

public interface IUserAsymmetricKeysRepository
{
Task RegenerateUserAsymmetricKeysAsync(UserAsymmetricKeys userAsymmetricKeys);
}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -60,6 +62,7 @@
.AddSingleton<IClientOrganizationMigrationRecordRepository, ClientOrganizationMigrationRecordRepository>();
services.AddSingleton<IPasswordHealthReportApplicationRepository, PasswordHealthReportApplicationRepository>();
services.AddSingleton<ISecurityTaskRepository, SecurityTaskRepository>();
services.AddSingleton<IUserAsymmetricKeysRepository, UserAsymmetricKeysRepository>();

Check warning on line 65 in src/Infrastructure.Dapper/DapperServiceCollectionExtensions.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.Dapper/DapperServiceCollectionExtensions.cs#L65

Added line #L65 was not covered by tests

if (selfHosted)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -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)
{
}

Check warning on line 17 in src/Infrastructure.Dapper/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.Dapper/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs#L15-L17

Added lines #L15 - L17 were not covered by tests

public UserAsymmetricKeysRepository(string connectionString, string readOnlyConnectionString) : base(
connectionString, readOnlyConnectionString)
{
}

Check warning on line 22 in src/Infrastructure.Dapper/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.Dapper/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs#L19-L22

Added lines #L19 - L22 were not covered by tests

public async Task RegenerateUserAsymmetricKeysAsync(UserAsymmetricKeys userAsymmetricKeys)
{
await using var connection = new SqlConnection(ConnectionString);

Check warning on line 26 in src/Infrastructure.Dapper/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.Dapper/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs#L25-L26

Added lines #L25 - L26 were not covered by tests

await connection.ExecuteAsync("[dbo].[UserAsymmetricKeys_Regenerate]",
new
{
userAsymmetricKeys.UserId,
userAsymmetricKeys.PublicKey,
PrivateKey = userAsymmetricKeys.UserKeyEncryptedPrivateKey
}, commandType: CommandType.StoredProcedure);
}

Check warning on line 35 in src/Infrastructure.Dapper/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.Dapper/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs#L29-L35

Added lines #L29 - L35 were not covered by tests
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -97,6 +99,7 @@ public static void AddPasswordManagerEFRepositories(this IServiceCollection serv
.AddSingleton<IClientOrganizationMigrationRecordRepository, ClientOrganizationMigrationRecordRepository>();
services.AddSingleton<IPasswordHealthReportApplicationRepository, PasswordHealthReportApplicationRepository>();
services.AddSingleton<ISecurityTaskRepository, SecurityTaskRepository>();
services.AddSingleton<IUserAsymmetricKeysRepository, UserAsymmetricKeysRepository>();

if (selfHosted)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -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)
{
}

Check warning on line 16 in src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs#L12-L16

Added lines #L12 - L16 were not covered by tests

public async Task RegenerateUserAsymmetricKeysAsync(UserAsymmetricKeys userAsymmetricKeys)
{
await using var scope = ServiceScopeFactory.CreateAsyncScope();
var dbContext = GetDatabaseContext(scope);

Check warning on line 21 in src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs#L19-L21

Added lines #L19 - L21 were not covered by tests

var entity = await dbContext.Users.FindAsync(userAsymmetricKeys.UserId);

Check warning on line 23 in src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs#L23

Added line #L23 was not covered by tests
if (entity != null)
{
var utcNow = DateTime.UtcNow;
entity.PublicKey = userAsymmetricKeys.PublicKey;
entity.PrivateKey = userAsymmetricKeys.UserKeyEncryptedPrivateKey;
entity.RevisionDate = utcNow;
entity.AccountRevisionDate = utcNow;
await dbContext.SaveChangesAsync();
}
}

Check warning on line 33 in src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserAsymmetricKeysRepository.cs#L25-L33

Added lines #L25 - L33 were not covered by tests
}
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Loading