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

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;
@@ -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;
@@ -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

Codecov / codecov/patch

src/Infrastructure.Dapper/DapperServiceCollectionExtensions.cs#L65

Added line #L65 was not covered by tests

if (selfHosted)
{
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

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

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

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

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
@@ -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;
@@ -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)
{
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

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

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

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

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