1
0
mirror of https://github.com/bitwarden/server synced 2025-12-14 15:23:42 +00:00
Files
server/src/Api/Auth/Validators/EmergencyAccessRotationValidator.cs
Bernd Schoolmann 0189952e1f [PM-5938] Prevent permanent vault coruption on key-rotation with desycned vault (#4098)
* Add check to verify the vault state for rotation is not obviously desynced (empty)

* Add unit test for key rotation guardrail

* Move de-synced vault detection to validators

* Add tests
2024-05-30 11:08:26 +02:00

55 lines
1.9 KiB
C#

using Bit.Api.Auth.Models.Request;
using Bit.Core.Auth.Entities;
using Bit.Core.Entities;
using Bit.Core.Exceptions;
using Bit.Core.Repositories;
using Bit.Core.Services;
namespace Bit.Api.Auth.Validators;
public class EmergencyAccessRotationValidator : IRotationValidator<IEnumerable<EmergencyAccessWithIdRequestModel>,
IEnumerable<EmergencyAccess>>
{
private readonly IEmergencyAccessRepository _emergencyAccessRepository;
private readonly IUserService _userService;
public EmergencyAccessRotationValidator(IEmergencyAccessRepository emergencyAccessRepository,
IUserService userService)
{
_emergencyAccessRepository = emergencyAccessRepository;
_userService = userService;
}
public async Task<IEnumerable<EmergencyAccess>> ValidateAsync(User user,
IEnumerable<EmergencyAccessWithIdRequestModel> emergencyAccessKeys)
{
var result = new List<EmergencyAccess>();
var existing = await _emergencyAccessRepository.GetManyDetailsByGrantorIdAsync(user.Id);
if (existing == null || existing.Count == 0)
{
return result;
}
// Exclude any emergency access that has not been confirmed yet.
existing = existing.Where(ea => ea.KeyEncrypted != null).ToList();
foreach (var ea in existing)
{
var emergencyAccess = emergencyAccessKeys.FirstOrDefault(c => c.Id == ea.Id);
if (emergencyAccess == null)
{
throw new BadRequestException("All existing emergency access keys must be included in the rotation.");
}
if (emergencyAccess.KeyEncrypted == null)
{
throw new BadRequestException("Emergency access keys cannot be set to null during rotation.");
}
result.Add(emergencyAccess.ToEmergencyAccess(ea));
}
return result;
}
}