mirror of
https://github.com/bitwarden/server.git
synced 2025-07-17 07:30:59 -05:00
[PM-16603] Add userkey rotation v2 (#5204)
* Implement userkey rotation v2 * Update request models * Cleanup * Update tests * Improve test * Add tests * Fix formatting * Fix test * Remove whitespace * Fix namespace * Enable nullable on models * Fix build * Add tests and enable nullable on masterpasswordunlockdatamodel * Fix test * Remove rollback * Add tests * Make masterpassword hint optional * Update user query * Add EF test * Improve test * Cleanup * Set masterpassword hint * Remove connection close * Add tests for invalid kdf types * Update test/Core.Test/KeyManagement/UserKey/RotateUserAccountKeysCommandTests.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Fix formatting * Update src/Api/KeyManagement/Models/Requests/RotateAccountKeysAndDataRequestModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/Auth/Models/Request/Accounts/MasterPasswordUnlockDataModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/Auth/Models/Request/Accounts/MasterPasswordUnlockDataModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Models/Requests/AccountKeysRequestModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Fix imports * Fix tests * Remove null check * Add rollback --------- Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>
This commit is contained in:
@ -254,6 +254,42 @@ public class UserRepository : Repository<User, Guid>, IUserRepository
|
||||
}
|
||||
|
||||
|
||||
public async Task UpdateUserKeyAndEncryptedDataV2Async(
|
||||
User user,
|
||||
IEnumerable<UpdateEncryptedDataForKeyRotation> updateDataActions)
|
||||
{
|
||||
await using var connection = new SqlConnection(ConnectionString);
|
||||
connection.Open();
|
||||
|
||||
await using var transaction = connection.BeginTransaction();
|
||||
try
|
||||
{
|
||||
user.AccountRevisionDate = user.RevisionDate;
|
||||
|
||||
ProtectData(user);
|
||||
await connection.ExecuteAsync(
|
||||
$"[{Schema}].[{Table}_Update]",
|
||||
user,
|
||||
transaction: transaction,
|
||||
commandType: CommandType.StoredProcedure);
|
||||
|
||||
// Update re-encrypted data
|
||||
foreach (var action in updateDataActions)
|
||||
{
|
||||
await action(connection, transaction);
|
||||
}
|
||||
transaction.Commit();
|
||||
}
|
||||
catch
|
||||
{
|
||||
transaction.Rollback();
|
||||
UnprotectData(user);
|
||||
throw;
|
||||
}
|
||||
UnprotectData(user);
|
||||
}
|
||||
|
||||
|
||||
public async Task<IEnumerable<User>> GetManyAsync(IEnumerable<Guid> ids)
|
||||
{
|
||||
using (var connection = new SqlConnection(ReadOnlyConnectionString))
|
||||
@ -295,6 +331,18 @@ public class UserRepository : Repository<User, Guid>, IUserRepository
|
||||
var originalKey = user.Key;
|
||||
|
||||
// Protect values
|
||||
ProtectData(user);
|
||||
|
||||
// Save
|
||||
await saveTask();
|
||||
|
||||
// Restore original values
|
||||
user.MasterPassword = originalMasterPassword;
|
||||
user.Key = originalKey;
|
||||
}
|
||||
|
||||
private void ProtectData(User user)
|
||||
{
|
||||
if (!user.MasterPassword?.StartsWith(Constants.DatabaseFieldProtectedPrefix) ?? false)
|
||||
{
|
||||
user.MasterPassword = string.Concat(Constants.DatabaseFieldProtectedPrefix,
|
||||
@ -306,13 +354,6 @@ public class UserRepository : Repository<User, Guid>, IUserRepository
|
||||
user.Key = string.Concat(Constants.DatabaseFieldProtectedPrefix,
|
||||
_dataProtector.Protect(user.Key!));
|
||||
}
|
||||
|
||||
// Save
|
||||
await saveTask();
|
||||
|
||||
// Restore original values
|
||||
user.MasterPassword = originalMasterPassword;
|
||||
user.Key = originalKey;
|
||||
}
|
||||
|
||||
private void UnprotectData(User? user)
|
||||
|
Reference in New Issue
Block a user