Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
using Bit.Core.Entities;
using Bit.Core.Exceptions;
using Bit.Core.KeyManagement.Commands.Interfaces;
using Bit.Core.KeyManagement.Models.Data;
using Bit.Core.KeyManagement.Queries.Interfaces;
using Bit.Core.KeyManagement.UserKey;
using Bit.Core.KeyManagement.UserKey.Models.Data;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Tools.Entities;
Expand Down Expand Up @@ -93,33 +93,40 @@ await _regenerateUserAsymmetricKeysCommand.RegenerateKeysAsync(request.ToUserAsy


[HttpPost("key-management/rotate-user-account-keys")]
public async Task RotateUserAccountKeysAsync([FromBody] RotateUserAccountKeysAndDataRequestModel model)
public async Task PasswordChangeAndRotateUserAccountKeysAsync([FromBody] RotateUserAccountKeysAndDataRequestModel model)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

KM team, I've realized changing this method name will effect the SDK name of the generated API bindings. Do we think that is worth it or should I just revert it back to the original name?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm OK with it, it just means we need to fix the breaking API bindings PR. I.e we run the API bindings automation on the SDK repo and do a rename on that branch, and review. Should be fairly low effort?

{
var user = await _userService.GetUserByPrincipalAsync(User);
if (user == null)
{
throw new UnauthorizedAccessException();
}

var dataModel = new RotateUserAccountKeysData
var dataModel = new PasswordChangeAndRotateUserAccountKeysData
{
OldMasterKeyAuthenticationHash = model.OldMasterKeyAuthenticationHash,

AccountKeys = model.AccountKeys.ToAccountKeysData(),

MasterPasswordUnlockData = model.AccountUnlockData.MasterPasswordUnlockData.ToUnlockData(),
EmergencyAccesses = await _emergencyAccessValidator.ValidateAsync(user, model.AccountUnlockData.EmergencyAccessUnlockData),
OrganizationUsers = await _organizationUserValidator.ValidateAsync(user, model.AccountUnlockData.OrganizationAccountRecoveryUnlockData),
WebAuthnKeys = await _webauthnKeyValidator.ValidateAsync(user, model.AccountUnlockData.PasskeyUnlockData),
DeviceKeys = await _deviceValidator.ValidateAsync(user, model.AccountUnlockData.DeviceKeyUnlockData),
V2UpgradeToken = model.AccountUnlockData.V2UpgradeToken?.ToData(),

Ciphers = await _cipherValidator.ValidateAsync(user, model.AccountData.Ciphers),
Folders = await _folderValidator.ValidateAsync(user, model.AccountData.Folders),
Sends = await _sendValidator.ValidateAsync(user, model.AccountData.Sends),
MasterPasswordHint = model.AccountUnlockData.MasterPasswordUnlockData.MasterPasswordHint,
MasterPasswordAuthenticationData = model.AccountUnlockData.MasterPasswordUnlockData.ToAuthenticationData(),
MasterPasswordUnlockData = model.AccountUnlockData.MasterPasswordUnlockData.ToMasterPasswordUnlockData(),
BaseData = new BaseRotateUserAccountKeysData
{
AccountKeys = model.AccountKeys.ToAccountKeysData(),
EmergencyAccesses =
await _emergencyAccessValidator.ValidateAsync(user,
model.AccountUnlockData.EmergencyAccessUnlockData),
OrganizationUsers =
await _organizationUserValidator.ValidateAsync(user,
model.AccountUnlockData.OrganizationAccountRecoveryUnlockData),
WebAuthnKeys =
await _webauthnKeyValidator.ValidateAsync(user, model.AccountUnlockData.PasskeyUnlockData),
DeviceKeys = await _deviceValidator.ValidateAsync(user, model.AccountUnlockData.DeviceKeyUnlockData),
V2UpgradeToken = model.AccountUnlockData.V2UpgradeToken?.ToData(),
Ciphers = await _cipherValidator.ValidateAsync(user, model.AccountData.Ciphers),
Folders = await _folderValidator.ValidateAsync(user, model.AccountData.Folders),
Sends = await _sendValidator.ValidateAsync(user, model.AccountData.Sends)
}
};

var result = await _rotateUserAccountKeysCommand.RotateUserAccountKeysAsync(user, dataModel);
var result = await _rotateUserAccountKeysCommand.PasswordChangeAndRotateUserAccountKeysAsync(user, dataModel);
if (result.Succeeded)
{
return;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
#nullable enable

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Enums;
using Bit.Core.KeyManagement.Models.Data;
using Bit.Core.Utilities;

namespace Bit.Api.Auth.Models.Request.Accounts;
namespace Bit.Api.KeyManagement.Models.Requests;

public class MasterPasswordUnlockAndAuthenticationDataModel : IValidatableObject
{
Expand Down Expand Up @@ -45,22 +43,35 @@ public IEnumerable<ValidationResult> Validate(ValidationContext validationContex
}
}

public MasterPasswordUnlockAndAuthenticationData ToUnlockData()
public MasterPasswordAuthenticationData ToAuthenticationData()
{
var data = new MasterPasswordUnlockAndAuthenticationData
return new MasterPasswordAuthenticationData
{
KdfType = KdfType,
KdfIterations = KdfIterations,
KdfMemory = KdfMemory,
KdfParallelism = KdfParallelism,

Email = Email,

MasterKeyAuthenticationHash = MasterKeyAuthenticationHash,
MasterKeyEncryptedUserKey = MasterKeyEncryptedUserKey,
MasterPasswordHint = MasterPasswordHint
Kdf = new KdfSettings
{
KdfType = KdfType,
Iterations = KdfIterations,
Memory = KdfMemory,
Parallelism = KdfParallelism,
},
Salt = Email,
MasterPasswordAuthenticationHash = MasterKeyAuthenticationHash,
};
return data;
}

public MasterPasswordUnlockData ToMasterPasswordUnlockData()
{
return new MasterPasswordUnlockData
{
Kdf = new KdfSettings
{
KdfType = KdfType,
Iterations = KdfIterations,
Memory = KdfMemory,
Parallelism = KdfParallelism,
},
Salt = Email,
MasterKeyWrappedUserKey = MasterKeyEncryptedUserKey,
};
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using Bit.Api.AdminConsole.Models.Request.Organizations;
using Bit.Api.Auth.Models.Request;
using Bit.Api.Auth.Models.Request.Accounts;
using Bit.Api.Auth.Models.Request.WebAuthn;
using Bit.Core.Auth.Models.Api.Request;

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#nullable disable

using Bit.Core.Entities;
using Bit.Core.KeyManagement.Models.Data;
using Bit.Core.KeyManagement.UserKey.Models.Data;
using Microsoft.AspNetCore.Identity;
using Microsoft.Data.SqlClient;

Expand All @@ -14,13 +14,13 @@ namespace Bit.Core.KeyManagement.UserKey;
public interface IRotateUserAccountKeysCommand
{
/// <summary>
/// Sets a new user key and updates all encrypted data.
/// Sets a new user key and updates all encrypted data and data associated with a password change.
/// </summary>
/// <param name="model">All necessary information for rotation. If data is not included, this will lead to the change being rejected.</param>
/// <param name="model">All necessary information for rotation and password change. If data is not included, this will lead to the change being rejected.</param>
/// <returns>An IdentityResult for verification of the master password hash</returns>
/// <exception cref="ArgumentNullException">User must be provided.</exception>
/// <exception cref="InvalidOperationException">User KDF settings and email must match the model provided settings.</exception>
Task<IdentityResult> RotateUserAccountKeysAsync(User user, RotateUserAccountKeysData model);
Task<IdentityResult> PasswordChangeAndRotateUserAccountKeysAsync(User user, PasswordChangeAndRotateUserAccountKeysData model);
}

/// <summary>
Expand Down
Loading
Loading