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

[PM-4371] Implement PRF key rotation (#4157)

* Send rotateable keyset on list webauthn keys

* Implement basic prf key rotation

* Add validator for webauthn rotation

* Fix accounts controller tests

* Add webauthn rotation validator tests

* Introduce separate request model

* Fix tests

* Remove extra empty line

* Remove filtering in validator

* Don't send encrypted private key

* Fix tests

* Implement delegated webauthn db transactions

* Add backward compatibility

* Fix query not working

* Update migration sql

* Update dapper query

* Remove unused helper

* Rename webauthn to WebAuthnLogin

* Fix linter errors

* Fix tests

* Fix tests
This commit is contained in:
Bernd Schoolmann
2024-06-17 20:46:57 +02:00
committed by GitHub
parent a556462685
commit 3ad4bc1cab
19 changed files with 347 additions and 11 deletions

View File

@ -15,4 +15,5 @@ public class RotateUserKeyData
public IReadOnlyList<Send> Sends { get; set; }
public IEnumerable<EmergencyAccess> EmergencyAccesses { get; set; }
public IReadOnlyList<OrganizationUser> OrganizationUsers { get; set; }
public IEnumerable<WebAuthnLoginRotateKeyData> WebAuthnKeys { get; set; }
}

View File

@ -0,0 +1,21 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Utilities;
namespace Bit.Core.Auth.Models.Data;
public class WebAuthnLoginRotateKeyData
{
[Required]
public Guid Id { get; set; }
[Required]
[EncryptedString]
[EncryptedStringLength(2000)]
public string EncryptedUserKey { get; set; }
[Required]
[EncryptedString]
[EncryptedStringLength(2000)]
public string EncryptedPublicKey { get; set; }
}

View File

@ -1,4 +1,6 @@
using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Models.Data;
using Bit.Core.Auth.UserFeatures.UserKey;
using Bit.Core.Repositories;
namespace Bit.Core.Auth.Repositories;
@ -8,4 +10,5 @@ public interface IWebAuthnCredentialRepository : IRepository<WebAuthnCredential,
Task<WebAuthnCredential> GetByIdAsync(Guid id, Guid userId);
Task<ICollection<WebAuthnCredential>> GetManyByUserIdAsync(Guid userId);
Task<bool> UpdateAsync(WebAuthnCredential credential);
UpdateEncryptedDataForKeyRotation UpdateKeysForRotationAsync(Guid userId, IEnumerable<WebAuthnLoginRotateKeyData> credentials);
}

View File

@ -1,4 +1,5 @@
using Bit.Core.Auth.Models.Data;
using Bit.Core.Auth.Repositories;
using Bit.Core.Entities;
using Bit.Core.Repositories;
using Bit.Core.Services;
@ -20,6 +21,7 @@ public class RotateUserKeyCommand : IRotateUserKeyCommand
private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly IPushNotificationService _pushService;
private readonly IdentityErrorDescriber _identityErrorDescriber;
private readonly IWebAuthnCredentialRepository _credentialRepository;
/// <summary>
/// Instantiates a new <see cref="RotateUserKeyCommand"/>
@ -35,7 +37,7 @@ public class RotateUserKeyCommand : IRotateUserKeyCommand
public RotateUserKeyCommand(IUserService userService, IUserRepository userRepository,
ICipherRepository cipherRepository, IFolderRepository folderRepository, ISendRepository sendRepository,
IEmergencyAccessRepository emergencyAccessRepository, IOrganizationUserRepository organizationUserRepository,
IPushNotificationService pushService, IdentityErrorDescriber errors)
IPushNotificationService pushService, IdentityErrorDescriber errors, IWebAuthnCredentialRepository credentialRepository)
{
_userService = userService;
_userRepository = userRepository;
@ -46,6 +48,7 @@ public class RotateUserKeyCommand : IRotateUserKeyCommand
_organizationUserRepository = organizationUserRepository;
_pushService = pushService;
_identityErrorDescriber = errors;
_credentialRepository = credentialRepository;
}
/// <inheritdoc />
@ -68,7 +71,7 @@ public class RotateUserKeyCommand : IRotateUserKeyCommand
user.Key = model.Key;
user.PrivateKey = model.PrivateKey;
if (model.Ciphers.Any() || model.Folders.Any() || model.Sends.Any() || model.EmergencyAccesses.Any() ||
model.OrganizationUsers.Any())
model.OrganizationUsers.Any() || model.WebAuthnKeys.Any())
{
List<UpdateEncryptedDataForKeyRotation> saveEncryptedDataActions = new();
@ -99,6 +102,11 @@ public class RotateUserKeyCommand : IRotateUserKeyCommand
_organizationUserRepository.UpdateForKeyRotation(user.Id, model.OrganizationUsers));
}
if (model.WebAuthnKeys.Any())
{
saveEncryptedDataActions.Add(_credentialRepository.UpdateKeysForRotationAsync(user.Id, model.WebAuthnKeys));
}
await _userRepository.UpdateUserKeyAndEncryptedDataAsync(user, saveEncryptedDataActions);
}
else