1
0
mirror of https://github.com/bitwarden/server synced 2026-02-22 20:33:26 +00:00

[PM-31052][PM-32469] Add V2UpgradeToken for key rotation without logout (#6995)

* User V2UpgradeToken for key rotation without logout

* reset old v2 upgrade token on manual key rotation

* sql migration fix

* missing table column

* missing view update

* tests for V2UpgradeToken clearing on manual key rotation

* V2 to V2 rotation causes logout. Updated wrapped key 1 to be a valid V2 encrypted string in tests.

* integration tests failures - increase assert recent for date time type from 2 to 5 seconds (usually for UpdatedAt assertions)

* repository test coverage

* migration script update

* new EF migration scripts

* broken EF migration scripts fixed

* refresh views due to User table alternation
This commit is contained in:
Maciej Zieniuk
2026-02-20 20:19:14 +01:00
committed by GitHub
parent a961626957
commit 6a7b8f5a89
35 changed files with 12395 additions and 242 deletions

View File

@@ -36,6 +36,10 @@ namespace Bit.Api.Test.KeyManagement.Controllers;
[JsonDocumentCustomize]
public class AccountsKeyManagementControllerTests
{
private static readonly string _mockEncryptedType2String =
"2.AOs41Hd8OQiCPXjyJKCiDA==|O6OHgt2U2hJGBSNGnimJmg==|iD33s8B69C8JhYYhSa4V1tArjvLr8eEaGqOV7BRo5Jk=";
private static readonly string _mockEncryptedType7String = "7.AOs41Hd8OQiCPXjyJKCiDA==";
[Theory]
[BitAutoData]
public async Task RegenerateKeysAsync_FeatureFlagOff_Throws(
@@ -109,7 +113,8 @@ public class AccountsKeyManagementControllerTests
[Theory]
[BitAutoData]
public async Task RotateUserAccountKeysSuccess(SutProvider<AccountsKeyManagementController> sutProvider,
public async Task RotateUserAccountKeys_UserCryptoV1_Success(
SutProvider<AccountsKeyManagementController> sutProvider,
RotateUserAccountKeysAndDataRequestModel data, User user)
{
data.AccountKeys.SignatureKeyPair = null;
@@ -236,6 +241,62 @@ public class AccountsKeyManagementControllerTests
}
}
[Theory]
[BitAutoData]
public async Task RotateUserAccountKeys_WithV2UpgradeToken_PassesTokenToCommand(
SutProvider<AccountsKeyManagementController> sutProvider,
RotateUserAccountKeysAndDataRequestModel data,
User user)
{
// Arrange
data.AccountKeys.SignatureKeyPair = null;
data.AccountUnlockData.V2UpgradeToken = new V2UpgradeTokenRequestModel
{
WrappedUserKey1 = _mockEncryptedType7String,
WrappedUserKey2 = _mockEncryptedType2String
};
sutProvider.GetDependency<IUserService>().GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
sutProvider.GetDependency<IRotateUserAccountKeysCommand>()
.RotateUserAccountKeysAsync(Arg.Any<User>(), Arg.Any<RotateUserAccountKeysData>())
.Returns(IdentityResult.Success);
// Act
await sutProvider.Sut.RotateUserAccountKeysAsync(data);
// Assert
await sutProvider.GetDependency<IRotateUserAccountKeysCommand>().Received(1)
.RotateUserAccountKeysAsync(Arg.Is(user), Arg.Is<RotateUserAccountKeysData>(d =>
d.V2UpgradeToken != null &&
d.V2UpgradeToken.WrappedUserKey1 == _mockEncryptedType7String &&
d.V2UpgradeToken.WrappedUserKey2 == _mockEncryptedType2String));
}
[Theory]
[BitAutoData]
public async Task RotateUserAccountKeys_WithoutV2UpgradeToken_PassesNullToCommand(
SutProvider<AccountsKeyManagementController> sutProvider,
RotateUserAccountKeysAndDataRequestModel data,
User user)
{
// Arrange
data.AccountKeys.SignatureKeyPair = null;
data.AccountUnlockData.V2UpgradeToken = null;
sutProvider.GetDependency<IUserService>().GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
sutProvider.GetDependency<IRotateUserAccountKeysCommand>()
.RotateUserAccountKeysAsync(Arg.Any<User>(), Arg.Any<RotateUserAccountKeysData>())
.Returns(IdentityResult.Success);
// Act
await sutProvider.Sut.RotateUserAccountKeysAsync(data);
// Assert
await sutProvider.GetDependency<IRotateUserAccountKeysCommand>().Received(1)
.RotateUserAccountKeysAsync(Arg.Is(user), Arg.Is<RotateUserAccountKeysData>(d =>
d.V2UpgradeToken == null));
}
[Theory]
[BitAutoData]
public async Task PostSetKeyConnectorKeyAsync_V1_UserNull_Throws(