mirror of
https://github.com/bitwarden/server.git
synced 2025-07-04 09:32:48 -05:00
[PM-3797 Part 3] Add vault domains to key rotation (#3436)
## Type of change <!-- (mark with an `X`) --> ``` - [ ] Bug fix - [ ] New feature development - [x] Tech debt (refactoring, code cleanup, dependency upgrades, etc) - [ ] Build/deploy pipeline (DevOps) - [ ] Other ``` ## Objective <!--Describe what the purpose of this PR is. For example: what bug you're fixing or what new feature you're adding--> Previous PR: #3434 Adds ciphers and folders to the new key rotation. ## Code changes <!--Explain the changes you've made to each file or major component. This should help the reviewer understand your changes--> <!--Also refer to any related changes or PRs in other repositories--> * **file.ext:** Description of what was changed and why ## Before you submit - Please check for formatting errors (`dotnet format --verify-no-changes`) (required) - If making database changes - make sure you also update Entity Framework queries and/or migrations - Please add **unit tests** where it makes sense to do so (encouraged but not required) - If this change requires a **documentation update** - notify the documentation team - If this change has particular **deployment requirements** - notify the DevOps team
This commit is contained in:
@ -6,6 +6,7 @@ using Bit.Api.Models.Request;
|
||||
using Bit.Api.Models.Request.Accounts;
|
||||
using Bit.Api.Models.Response;
|
||||
using Bit.Api.Utilities;
|
||||
using Bit.Api.Vault.Models.Request;
|
||||
using Bit.Core;
|
||||
using Bit.Core.AdminConsole.Enums.Provider;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
@ -65,6 +66,8 @@ public class AccountsController : Controller
|
||||
private bool UseFlexibleCollections =>
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections, _currentContext);
|
||||
|
||||
private readonly IRotationValidator<IEnumerable<CipherWithIdRequestModel>, IEnumerable<Cipher>> _cipherValidator;
|
||||
private readonly IRotationValidator<IEnumerable<FolderWithIdRequestModel>, IEnumerable<Folder>> _folderValidator;
|
||||
private readonly IRotationValidator<IEnumerable<EmergencyAccessWithIdRequestModel>, IEnumerable<EmergencyAccess>>
|
||||
_emergencyAccessValidator;
|
||||
|
||||
@ -87,6 +90,8 @@ public class AccountsController : Controller
|
||||
IRotateUserKeyCommand rotateUserKeyCommand,
|
||||
IFeatureService featureService,
|
||||
ICurrentContext currentContext,
|
||||
IRotationValidator<IEnumerable<CipherWithIdRequestModel>, IEnumerable<Cipher>> cipherValidator,
|
||||
IRotationValidator<IEnumerable<FolderWithIdRequestModel>, IEnumerable<Folder>> folderValidator,
|
||||
IRotationValidator<IEnumerable<EmergencyAccessWithIdRequestModel>, IEnumerable<EmergencyAccess>>
|
||||
emergencyAccessValidator
|
||||
)
|
||||
@ -108,6 +113,8 @@ public class AccountsController : Controller
|
||||
_rotateUserKeyCommand = rotateUserKeyCommand;
|
||||
_featureService = featureService;
|
||||
_currentContext = currentContext;
|
||||
_cipherValidator = cipherValidator;
|
||||
_folderValidator = folderValidator;
|
||||
_emergencyAccessValidator = emergencyAccessValidator;
|
||||
}
|
||||
|
||||
@ -414,8 +421,8 @@ public class AccountsController : Controller
|
||||
MasterPasswordHash = model.MasterPasswordHash,
|
||||
Key = model.Key,
|
||||
PrivateKey = model.PrivateKey,
|
||||
Ciphers = new List<Cipher>(),
|
||||
Folders = new List<Folder>(),
|
||||
Ciphers = await _cipherValidator.ValidateAsync(user, model.Ciphers),
|
||||
Folders = await _folderValidator.ValidateAsync(user, model.Folders),
|
||||
Sends = new List<Send>(),
|
||||
EmergencyAccessKeys = await _emergencyAccessValidator.ValidateAsync(user, model.EmergencyAccessKeys),
|
||||
ResetPasswordKeys = new List<OrganizationUser>(),
|
||||
|
@ -9,6 +9,8 @@ using IdentityModel;
|
||||
using System.Globalization;
|
||||
using Bit.Api.Auth.Models.Request;
|
||||
using Bit.Api.Auth.Validators;
|
||||
using Bit.Api.Vault.Models.Request;
|
||||
using Bit.Api.Vault.Validators;
|
||||
using Bit.Core.Auth.Entities;
|
||||
using Bit.Core.IdentityServer;
|
||||
using Bit.SharedWeb.Health;
|
||||
@ -21,6 +23,7 @@ using Bit.Core.Auth.Identity;
|
||||
using Bit.Core.Auth.UserFeatures.UserKey;
|
||||
using Bit.Core.Auth.UserFeatures.UserKey.Implementations;
|
||||
using Bit.Core.OrganizationFeatures.OrganizationSubscriptions;
|
||||
using Bit.Core.Vault.Entities;
|
||||
|
||||
#if !OSS
|
||||
using Bit.Commercial.Core.SecretsManager;
|
||||
@ -141,6 +144,12 @@ public class Startup
|
||||
services
|
||||
.AddScoped<IRotationValidator<IEnumerable<EmergencyAccessWithIdRequestModel>, IEnumerable<EmergencyAccess>>,
|
||||
EmergencyAccessRotationValidator>();
|
||||
services
|
||||
.AddScoped<IRotationValidator<IEnumerable<CipherWithIdRequestModel>, IEnumerable<Cipher>>,
|
||||
CipherRotationValidator>();
|
||||
services
|
||||
.AddScoped<IRotationValidator<IEnumerable<FolderWithIdRequestModel>, IEnumerable<Folder>>,
|
||||
FolderRotationValidator>();
|
||||
|
||||
// Services
|
||||
services.AddBaseServices(globalSettings);
|
||||
|
56
src/Api/Vault/Validators/CipherRotationValidator.cs
Normal file
56
src/Api/Vault/Validators/CipherRotationValidator.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using Bit.Api.Auth.Validators;
|
||||
using Bit.Api.Vault.Models.Request;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Vault.Entities;
|
||||
using Bit.Core.Vault.Repositories;
|
||||
|
||||
namespace Bit.Api.Vault.Validators;
|
||||
|
||||
public class CipherRotationValidator : IRotationValidator<IEnumerable<CipherWithIdRequestModel>, IEnumerable<Cipher>>
|
||||
{
|
||||
private readonly ICipherRepository _cipherRepository;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly IFeatureService _featureService;
|
||||
|
||||
private bool UseFlexibleCollections =>
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections, _currentContext);
|
||||
|
||||
public CipherRotationValidator(ICipherRepository cipherRepository, ICurrentContext currentContext,
|
||||
IFeatureService featureService)
|
||||
{
|
||||
_cipherRepository = cipherRepository;
|
||||
_currentContext = currentContext;
|
||||
_featureService = featureService;
|
||||
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Cipher>> ValidateAsync(User user, IEnumerable<CipherWithIdRequestModel> ciphers)
|
||||
{
|
||||
var result = new List<Cipher>();
|
||||
if (ciphers == null || !ciphers.Any())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var existingCiphers = await _cipherRepository.GetManyByUserIdAsync(user.Id, UseFlexibleCollections);
|
||||
if (existingCiphers == null || !existingCiphers.Any())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
foreach (var existing in existingCiphers)
|
||||
{
|
||||
var cipher = ciphers.FirstOrDefault(c => c.Id == existing.Id);
|
||||
if (cipher == null)
|
||||
{
|
||||
throw new BadRequestException("All existing ciphers must be included in the rotation.");
|
||||
}
|
||||
result.Add(cipher.ToCipher(existing));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
44
src/Api/Vault/Validators/FolderRotationValidator.cs
Normal file
44
src/Api/Vault/Validators/FolderRotationValidator.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using Bit.Api.Auth.Validators;
|
||||
using Bit.Api.Vault.Models.Request;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Vault.Entities;
|
||||
using Bit.Core.Vault.Repositories;
|
||||
|
||||
namespace Bit.Api.Vault.Validators;
|
||||
|
||||
public class FolderRotationValidator : IRotationValidator<IEnumerable<FolderWithIdRequestModel>, IEnumerable<Folder>>
|
||||
{
|
||||
private readonly IFolderRepository _folderRepository;
|
||||
|
||||
public FolderRotationValidator(IFolderRepository folderRepository)
|
||||
{
|
||||
_folderRepository = folderRepository;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Folder>> ValidateAsync(User user, IEnumerable<FolderWithIdRequestModel> folders)
|
||||
{
|
||||
var result = new List<Folder>();
|
||||
if (folders == null || !folders.Any())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var existingFolders = await _folderRepository.GetManyByUserIdAsync(user.Id);
|
||||
if (existingFolders == null || !existingFolders.Any())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
foreach (var existing in existingFolders)
|
||||
{
|
||||
var folder = folders.FirstOrDefault(c => c.Id == existing.Id);
|
||||
if (folder == null)
|
||||
{
|
||||
throw new BadRequestException("All existing folders must be included in the rotation.");
|
||||
}
|
||||
result.Add(folder.ToFolder(existing));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user