mirror of
https://github.com/bitwarden/server.git
synced 2025-07-04 17:42:49 -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:
@ -1,4 +1,5 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||
using Bit.Api.Tools.Models.Request;
|
||||
using Bit.Api.Vault.Models.Request;
|
||||
|
||||
@ -10,12 +11,13 @@ public class UpdateKeyRequestModel
|
||||
[StringLength(300)]
|
||||
public string MasterPasswordHash { get; set; }
|
||||
[Required]
|
||||
public IEnumerable<CipherWithIdRequestModel> Ciphers { get; set; }
|
||||
[Required]
|
||||
public IEnumerable<FolderWithIdRequestModel> Folders { get; set; }
|
||||
public IEnumerable<SendWithIdRequestModel> Sends { get; set; }
|
||||
public string Key { get; set; }
|
||||
[Required]
|
||||
public string PrivateKey { get; set; }
|
||||
[Required]
|
||||
public string Key { get; set; }
|
||||
public IEnumerable<CipherWithIdRequestModel> Ciphers { get; set; }
|
||||
public IEnumerable<FolderWithIdRequestModel> Folders { get; set; }
|
||||
public IEnumerable<SendWithIdRequestModel> Sends { get; set; }
|
||||
public IEnumerable<EmergencyAccessUpdateRequestModel> EmergencyAccessKeys { get; set; }
|
||||
public IEnumerable<OrganizationUserUpdateRequestModel> ResetPasswordKeys { get; set; }
|
||||
|
||||
}
|
||||
|
@ -9,9 +9,12 @@ using Bit.Core.AdminConsole.Enums.Provider;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Auth.Models.Api.Request.Accounts;
|
||||
using Bit.Core.Auth.Models.Api.Response.Accounts;
|
||||
using Bit.Core.Auth.Models.Data;
|
||||
using Bit.Core.Auth.Services;
|
||||
using Bit.Core.Auth.UserFeatures.UserKey;
|
||||
using Bit.Core.Auth.UserFeatures.UserMasterPassword.Interfaces;
|
||||
using Bit.Core.Auth.Utilities;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Api.Response;
|
||||
@ -27,6 +30,7 @@ using Bit.Core.Utilities;
|
||||
using Bit.Core.Vault.Entities;
|
||||
using Bit.Core.Vault.Repositories;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Bit.Api.Controllers;
|
||||
@ -49,6 +53,9 @@ public class AccountsController : Controller
|
||||
private readonly ICaptchaValidationService _captchaValidationService;
|
||||
private readonly IPolicyService _policyService;
|
||||
private readonly ISetInitialMasterPasswordCommand _setInitialMasterPasswordCommand;
|
||||
private readonly IRotateUserKeyCommand _rotateUserKeyCommand;
|
||||
private readonly IFeatureService _featureService;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
|
||||
|
||||
public AccountsController(
|
||||
@ -65,7 +72,10 @@ public class AccountsController : Controller
|
||||
ISendService sendService,
|
||||
ICaptchaValidationService captchaValidationService,
|
||||
IPolicyService policyService,
|
||||
ISetInitialMasterPasswordCommand setInitialMasterPasswordCommand
|
||||
ISetInitialMasterPasswordCommand setInitialMasterPasswordCommand,
|
||||
IRotateUserKeyCommand rotateUserKeyCommand,
|
||||
IFeatureService featureService,
|
||||
ICurrentContext currentContext
|
||||
)
|
||||
{
|
||||
_cipherRepository = cipherRepository;
|
||||
@ -82,6 +92,9 @@ public class AccountsController : Controller
|
||||
_captchaValidationService = captchaValidationService;
|
||||
_policyService = policyService;
|
||||
_setInitialMasterPasswordCommand = setInitialMasterPasswordCommand;
|
||||
_rotateUserKeyCommand = rotateUserKeyCommand;
|
||||
_featureService = featureService;
|
||||
_currentContext = currentContext;
|
||||
}
|
||||
|
||||
#region DEPRECATED (Moved to Identity Service)
|
||||
@ -379,38 +392,59 @@ public class AccountsController : Controller
|
||||
throw new UnauthorizedAccessException();
|
||||
}
|
||||
|
||||
var ciphers = new List<Cipher>();
|
||||
if (model.Ciphers.Any())
|
||||
IdentityResult result;
|
||||
if (_featureService.IsEnabled(FeatureFlagKeys.KeyRotationImprovements, _currentContext))
|
||||
{
|
||||
var existingCiphers = await _cipherRepository.GetManyByUserIdAsync(user.Id);
|
||||
ciphers.AddRange(existingCiphers
|
||||
.Join(model.Ciphers, c => c.Id, c => c.Id, (existing, c) => c.ToCipher(existing)));
|
||||
var dataModel = new RotateUserKeyData
|
||||
{
|
||||
MasterPasswordHash = model.MasterPasswordHash,
|
||||
Key = model.Key,
|
||||
PrivateKey = model.PrivateKey,
|
||||
// Ciphers = await _cipherValidator.ValidateAsync(user, model.Ciphers),
|
||||
// Folders = await _folderValidator.ValidateAsync(user, model.Folders),
|
||||
// Sends = await _sendValidator.ValidateAsync(user, model.Sends),
|
||||
// EmergencyAccessKeys = await _emergencyAccessValidator.ValidateAsync(user, model.EmergencyAccessKeys),
|
||||
// ResetPasswordKeys = await _accountRecoveryValidator.ValidateAsync(user, model.ResetPasswordKeys),
|
||||
};
|
||||
|
||||
result = await _rotateUserKeyCommand.RotateUserKeyAsync(dataModel);
|
||||
}
|
||||
else
|
||||
{
|
||||
var ciphers = new List<Cipher>();
|
||||
if (model.Ciphers.Any())
|
||||
{
|
||||
var existingCiphers = await _cipherRepository.GetManyByUserIdAsync(user.Id);
|
||||
ciphers.AddRange(existingCiphers
|
||||
.Join(model.Ciphers, c => c.Id, c => c.Id, (existing, c) => c.ToCipher(existing)));
|
||||
}
|
||||
|
||||
var folders = new List<Folder>();
|
||||
if (model.Folders.Any())
|
||||
{
|
||||
var existingFolders = await _folderRepository.GetManyByUserIdAsync(user.Id);
|
||||
folders.AddRange(existingFolders
|
||||
.Join(model.Folders, f => f.Id, f => f.Id, (existing, f) => f.ToFolder(existing)));
|
||||
}
|
||||
|
||||
var sends = new List<Send>();
|
||||
if (model.Sends?.Any() == true)
|
||||
{
|
||||
var existingSends = await _sendRepository.GetManyByUserIdAsync(user.Id);
|
||||
sends.AddRange(existingSends
|
||||
.Join(model.Sends, s => s.Id, s => s.Id, (existing, s) => s.ToSend(existing, _sendService)));
|
||||
}
|
||||
|
||||
result = await _userService.UpdateKeyAsync(
|
||||
user,
|
||||
model.MasterPasswordHash,
|
||||
model.Key,
|
||||
model.PrivateKey,
|
||||
ciphers,
|
||||
folders,
|
||||
sends);
|
||||
}
|
||||
|
||||
var folders = new List<Folder>();
|
||||
if (model.Folders.Any())
|
||||
{
|
||||
var existingFolders = await _folderRepository.GetManyByUserIdAsync(user.Id);
|
||||
folders.AddRange(existingFolders
|
||||
.Join(model.Folders, f => f.Id, f => f.Id, (existing, f) => f.ToFolder(existing)));
|
||||
}
|
||||
|
||||
var sends = new List<Send>();
|
||||
if (model.Sends?.Any() == true)
|
||||
{
|
||||
var existingSends = await _sendRepository.GetManyByUserIdAsync(user.Id);
|
||||
sends.AddRange(existingSends
|
||||
.Join(model.Sends, s => s.Id, s => s.Id, (existing, s) => s.ToSend(existing, _sendService)));
|
||||
}
|
||||
|
||||
var result = await _userService.UpdateKeyAsync(
|
||||
user,
|
||||
model.MasterPasswordHash,
|
||||
model.Key,
|
||||
model.PrivateKey,
|
||||
ciphers,
|
||||
folders,
|
||||
sends);
|
||||
|
||||
if (result.Succeeded)
|
||||
{
|
||||
|
@ -15,6 +15,8 @@ using Bit.SharedWeb.Utilities;
|
||||
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Bit.Core.Auth.Identity;
|
||||
using Bit.Core.Auth.UserFeatures.UserKey;
|
||||
using Bit.Core.Auth.UserFeatures.UserKey.Implementations;
|
||||
using Bit.Core.OrganizationFeatures.OrganizationSubscriptions;
|
||||
|
||||
#if !OSS
|
||||
@ -131,6 +133,9 @@ public class Startup
|
||||
|
||||
services.AddScoped<AuthenticatorTokenProvider>();
|
||||
|
||||
// Key Rotation
|
||||
services.AddScoped<IRotateUserKeyCommand, RotateUserKeyCommand>();
|
||||
|
||||
// Services
|
||||
services.AddBaseServices(globalSettings);
|
||||
services.AddDefaultServices(globalSettings);
|
||||
|
Reference in New Issue
Block a user