1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-04 09:32:48 -05:00

[PM-3797 Part 1] Layout new key rotation methods (#3425)

* layout new key rotation methods
- add endpoint with request model
- add command with data model
- add repository method

* layout new key rotation methods
- add endpoint with request model
- add command with data model
- add repository method

* formatting

* rename account recovery to reset password

* fix tests

* remove extra endpoint

* rename account recovery to reset password

* fix tests and formatting

* register db calls in command, removing list from user repo

* formatting
This commit is contained in:
Jake Fink
2023-11-09 14:56:08 -05:00
committed by GitHub
parent 4cf2142b68
commit b716a925f8
12 changed files with 340 additions and 38 deletions

View File

@ -0,0 +1,18 @@
using Bit.Core.Auth.Models.Data;
using Microsoft.AspNetCore.Identity;
using Microsoft.Data.SqlClient;
namespace Bit.Core.Auth.UserFeatures.UserKey;
public interface IRotateUserKeyCommand
{
/// <summary>
/// Sets a new user key and updates all encrypted data.
/// </summary>
/// <param name="model">All necessary information for rotation. Warning: Any encrypted data not included will be lost.</param>
/// <returns>An IdentityResult for verification of the master password hash</returns>
/// <exception cref="ArgumentNullException">User must be provided.</exception>
Task<IdentityResult> RotateUserKeyAsync(RotateUserKeyData model);
}
public delegate Task UpdateEncryptedDataForKeyRotation(SqlTransaction transaction = null);

View File

@ -0,0 +1,61 @@
using Bit.Core.Auth.Models.Data;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Microsoft.AspNetCore.Identity;
namespace Bit.Core.Auth.UserFeatures.UserKey.Implementations;
public class RotateUserKeyCommand : IRotateUserKeyCommand
{
private readonly IUserService _userService;
private readonly IUserRepository _userRepository;
private readonly IPushNotificationService _pushService;
private readonly IdentityErrorDescriber _identityErrorDescriber;
public RotateUserKeyCommand(IUserService userService, IUserRepository userRepository,
IPushNotificationService pushService, IdentityErrorDescriber errors)
{
_userService = userService;
_userRepository = userRepository;
_pushService = pushService;
_identityErrorDescriber = errors;
}
/// <inheritdoc />
public async Task<IdentityResult> RotateUserKeyAsync(RotateUserKeyData model)
{
if (model.User == null)
{
throw new ArgumentNullException(nameof(model.User));
}
if (!await _userService.CheckPasswordAsync(model.User, model.MasterPasswordHash))
{
return IdentityResult.Failed(_identityErrorDescriber.PasswordMismatch());
}
var now = DateTime.UtcNow;
model.User.RevisionDate = model.User.AccountRevisionDate = now;
model.User.LastKeyRotationDate = now;
model.User.SecurityStamp = Guid.NewGuid().ToString();
model.User.Key = model.Key;
model.User.PrivateKey = model.PrivateKey;
if (model.Ciphers.Any() || model.Folders.Any() || model.Sends.Any() || model.EmergencyAccessKeys.Any() ||
model.ResetPasswordKeys.Any())
{
List<UpdateEncryptedDataForKeyRotation> saveEncryptedDataActions = new();
// if (model.Ciphers.Any())
// {
// saveEncryptedDataActions.Add(_cipherRepository.SaveRotatedData);
// }
await _userRepository.UpdateUserKeyAndEncryptedDataAsync(model.User, saveEncryptedDataActions);
}
else
{
await _userRepository.ReplaceAsync(model.User);
}
await _pushService.PushLogOutAsync(model.User.Id, excludeCurrentContextFromPush: true);
return IdentityResult.Success;
}
}