1
0
mirror of https://github.com/bitwarden/server synced 2026-01-29 07:43:22 +00:00

fix(register): [PM-27084] Account Register Uses New Data Types - Added new checks for master password authentication data.

This commit is contained in:
Patrick Pimentel
2025-12-29 11:57:25 -05:00
parent 4f81d75292
commit fac1d4bdc2
4 changed files with 37 additions and 33 deletions

View File

@@ -22,7 +22,7 @@ public class RegisterFinishRequestModel : IValidatableObject
public string? EmailVerificationToken { get; set; }
public MasterPasswordAuthenticationData? MasterPasswordAuthentication { get; set; }
public MasterPasswordUnlockData? MasterPasswordUnlockData { get; set; }
public MasterPasswordUnlockData? MasterPasswordUnlock { get; set; }
// PM-28143 - Remove property below (made optional during migration to MasterPasswordUnlockData)
[StringLength(1000)]
@@ -66,25 +66,25 @@ public class RegisterFinishRequestModel : IValidatableObject
// PM-28143 - Remove line below
// When we process this request to a user object, check if the unlock and authentication
// data has been passed through, and if so they should have matching values.
MasterPasswordUnlockData.ThrowIfExistsAndNotMatchingAuthenticationData(MasterPasswordAuthenticationData, MasterPasswordUnlockData);
MasterPasswordUnlockData.ThrowIfExistsAndNotMatchingAuthenticationData(MasterPasswordAuthentication, MasterPasswordUnlock);
// PM-28143 - Remove line below
MasterPasswordAuthenticationData.ThrowIfExistsAndHashIsNotEqual(MasterPasswordAuthenticationData, MasterPasswordHash);
MasterPasswordAuthenticationData.ThrowIfExistsAndHashIsNotEqual(MasterPasswordAuthentication, MasterPasswordHash);
var user = new User
{
Email = Email,
MasterPasswordHint = MasterPasswordHint,
Kdf = MasterPasswordUnlockData?.Kdf.KdfType ?? Kdf
Kdf = MasterPasswordUnlock?.Kdf.KdfType ?? Kdf
?? throw new Exception("KdfType couldn't be found on either the MasterPasswordUnlockData or the Kdf property passed in."),
KdfIterations = MasterPasswordUnlockData?.Kdf.Iterations ?? KdfIterations
KdfIterations = MasterPasswordUnlock?.Kdf.Iterations ?? KdfIterations
?? throw new Exception("KdfIterations couldn't be found on either the MasterPasswordUnlockData or the KdfIterations property passed in."),
// KdfMemory and KdfParallelism are optional (only used for Argon2id)
KdfMemory = MasterPasswordUnlockData?.Kdf.Memory ?? KdfMemory,
KdfParallelism = MasterPasswordUnlockData?.Kdf.Parallelism ?? KdfParallelism,
KdfMemory = MasterPasswordUnlock?.Kdf.Memory ?? KdfMemory,
KdfParallelism = MasterPasswordUnlock?.Kdf.Parallelism ?? KdfParallelism,
// PM-28827 To be added when MasterPasswordSalt is added to the user column
// MasterPasswordSalt = MasterPasswordUnlockData?.Salt ?? Email.ToLower().Trim(),
Key = MasterPasswordUnlockData?.MasterKeyWrappedUserKey ?? UserSymmetricKey ?? throw new Exception("MasterKeyWrappedUserKey couldn't be found on either the MasterPasswordUnlockData or the UserSymmetricKey property passed in."),
Key = MasterPasswordUnlock?.MasterKeyWrappedUserKey ?? UserSymmetricKey ?? throw new Exception("MasterKeyWrappedUserKey couldn't be found on either the MasterPasswordUnlockData or the UserSymmetricKey property passed in."),
};
UserAsymmetricKeys.ToUser(user);
@@ -121,24 +121,28 @@ public class RegisterFinishRequestModel : IValidatableObject
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
MasterPasswordUnlockData.ThrowIfExistsAndNotMatchingAuthenticationData(MasterPasswordAuthenticationData, MasterPasswordUnlockData);
// PM-28143 - Remove line below
MasterPasswordUnlockData.ThrowIfExistsAndNotMatchingAuthenticationData(MasterPasswordAuthentication, MasterPasswordUnlock);
// PM-28143 - Remove line below
var kdf = MasterPasswordUnlockData?.Kdf.KdfType
MasterPasswordAuthenticationData.ThrowIfExistsAndHashIsNotEqual(MasterPasswordAuthentication, MasterPasswordHash);
// PM-28143 - Remove line below
var kdf = MasterPasswordUnlock?.Kdf.KdfType
?? Kdf
?? throw new Exception($"{nameof(Kdf)} not found on RequestModel");
// PM-28143 - Remove line below
var kdfIterations = MasterPasswordUnlockData?.Kdf.Iterations
var kdfIterations = MasterPasswordUnlock?.Kdf.Iterations
?? KdfIterations
?? throw new Exception($"{nameof(KdfIterations)} not found on RequestModel");
// PM-28143 - Remove line below
var kdfMemory = MasterPasswordUnlockData?.Kdf.Memory
var kdfMemory = MasterPasswordUnlock?.Kdf.Memory
?? KdfMemory;
// PM-28143 - Remove line below
var kdfParallelism = MasterPasswordUnlockData?.Kdf.Parallelism
var kdfParallelism = MasterPasswordUnlock?.Kdf.Parallelism
?? KdfParallelism;
// PM-28143 - Remove line below in favor of using the unlock data.

View File

@@ -156,7 +156,7 @@ public class AccountsController : Controller
IdentityResult? identityResult = null;
// PM-28143 - Just use the MasterPasswordAuthenticationData.MasterPasswordAuthenticationHash
string masterPasswordHash = model.MasterPasswordAuthenticationData?.MasterPasswordAuthenticationHash
string masterPasswordHash = model.MasterPasswordAuthentication?.MasterPasswordAuthenticationHash
?? model.MasterPasswordHash ?? throw new BadRequestException("MasterPasswordHash couldn't be found on either the MasterPasswordAuthenticationData or the MasterPasswordHash property passed in.");
switch (model.GetTokenType())

View File

@@ -607,7 +607,7 @@ public class AccountsControllerTests : IDisposable
{
Email = email,
EmailVerificationToken = emailVerificationToken,
MasterPasswordAuthenticationData = new MasterPasswordAuthenticationData
MasterPasswordAuthentication = new MasterPasswordAuthenticationData
{
Kdf = new KdfSettings
{
@@ -619,7 +619,7 @@ public class AccountsControllerTests : IDisposable
MasterPasswordAuthenticationHash = masterPasswordHash,
Salt = email // salt choice is not validated here during registration
},
MasterPasswordUnlockData = new MasterPasswordUnlockData
MasterPasswordUnlock = new MasterPasswordUnlockData
{
Kdf = new KdfSettings
{
@@ -725,7 +725,7 @@ public class AccountsControllerTests : IDisposable
Email = email,
OrgInviteToken = orgInviteToken,
OrganizationUserId = organizationUserId,
MasterPasswordAuthenticationData = new MasterPasswordAuthenticationData
MasterPasswordAuthentication = new MasterPasswordAuthenticationData
{
Kdf = new KdfSettings
{
@@ -735,7 +735,7 @@ public class AccountsControllerTests : IDisposable
MasterPasswordAuthenticationHash = masterPasswordHash,
Salt = email
},
MasterPasswordUnlockData = new MasterPasswordUnlockData
MasterPasswordUnlock = new MasterPasswordUnlockData
{
Kdf = new KdfSettings
{
@@ -842,14 +842,14 @@ public class AccountsControllerTests : IDisposable
{
Email = email,
EmailVerificationToken = emailVerificationToken,
MasterPasswordAuthenticationData = new MasterPasswordAuthenticationData
MasterPasswordAuthentication = new MasterPasswordAuthenticationData
{
// present but not used by ToUser for KDF/Key
Kdf = new KdfSettings { KdfType = KdfType.Argon2id, Iterations = iterations },
MasterPasswordAuthenticationHash = masterPasswordHash,
Salt = email
},
MasterPasswordUnlockData = new MasterPasswordUnlockData
MasterPasswordUnlock = new MasterPasswordUnlockData
{
Kdf = unlockKdf,
MasterKeyWrappedUserKey = masterKeyWrappedUserKey,
@@ -901,7 +901,7 @@ public class AccountsControllerTests : IDisposable
Kdf = KdfType.PBKDF2_SHA256,
KdfIterations = AuthConstants.PBKDF2_ITERATIONS.Default,
UserSymmetricKey = legacyKey,
MasterPasswordUnlockData = null,
MasterPasswordUnlock = null,
UserAsymmetricKeys = new KeysRequestModel
{
PublicKey = publicKey,
@@ -942,14 +942,14 @@ public class AccountsControllerTests : IDisposable
{
Email = email,
EmailVerificationToken = emailVerificationToken,
MasterPasswordAuthenticationData = new MasterPasswordAuthenticationData
MasterPasswordAuthentication = new MasterPasswordAuthenticationData
{
// present but ToUser does not source KDF from here
Kdf = new KdfSettings { KdfType = KdfType.Argon2id, Iterations = iterations },
MasterPasswordAuthenticationHash = masterPasswordHash,
Salt = email
},
MasterPasswordUnlockData = null,
MasterPasswordUnlock = null,
Kdf = null,
KdfIterations = iterations,
UserSymmetricKey = masterKeyWrappedUserKey,
@@ -980,14 +980,14 @@ public class AccountsControllerTests : IDisposable
{
Email = email,
EmailVerificationToken = emailVerificationToken,
MasterPasswordAuthenticationData = new MasterPasswordAuthenticationData
MasterPasswordAuthentication = new MasterPasswordAuthenticationData
{
// present but ToUser does not source iterations from here
Kdf = new KdfSettings { KdfType = kdfType, Iterations = AuthConstants.PBKDF2_ITERATIONS.Default },
MasterPasswordAuthenticationHash = masterPasswordHash,
Salt = email
},
MasterPasswordUnlockData = null,
MasterPasswordUnlock = null,
Kdf = kdfType,
KdfIterations = null,
UserSymmetricKey = masterKeyWrappedUserKey,
@@ -1018,13 +1018,13 @@ public class AccountsControllerTests : IDisposable
{
Email = email,
EmailVerificationToken = emailVerificationToken,
MasterPasswordAuthenticationData = new MasterPasswordAuthenticationData
MasterPasswordAuthentication = new MasterPasswordAuthenticationData
{
Kdf = new KdfSettings { KdfType = kdfType, Iterations = iterations },
MasterPasswordAuthenticationHash = masterPasswordHash,
Salt = email
},
MasterPasswordUnlockData = null,
MasterPasswordUnlock = null,
Kdf = kdfType,
KdfIterations = iterations,
UserSymmetricKey = null,

View File

@@ -206,7 +206,7 @@ public class IdentityApplicationFactory : WebApplicationFactoryBase<Startup>
requestModel.KdfIterations ??= AuthConstants.PBKDF2_ITERATIONS.Default;
// Ensure a symmetric key is provided when no unlock data is present
// PM-28143 - When MasterPasswordUnlockData is required, delete the UserSymmetricKey fallback block below.
if (requestModel.MasterPasswordUnlockData == null && string.IsNullOrWhiteSpace(requestModel.UserSymmetricKey))
if (requestModel.MasterPasswordUnlock == null && string.IsNullOrWhiteSpace(requestModel.UserSymmetricKey))
{
requestModel.UserSymmetricKey = "user_symmetric_key";
}
@@ -234,14 +234,14 @@ public class IdentityApplicationFactory : WebApplicationFactoryBase<Startup>
Parallelism = effectiveParallelism
};
if (requestModel.MasterPasswordUnlockData != null)
if (requestModel.MasterPasswordUnlock != null)
{
var unlock = requestModel.MasterPasswordUnlockData;
var unlock = requestModel.MasterPasswordUnlock;
// PM-28143 - Once UserSymmetricKey is removed and UnlockData is required, delete the fallback to UserSymmetricKey below.
var masterKeyWrappedUserKey = !string.IsNullOrWhiteSpace(unlock.MasterKeyWrappedUserKey)
? unlock.MasterKeyWrappedUserKey
: (string.IsNullOrWhiteSpace(requestModel.UserSymmetricKey) ? "user_symmetric_key" : requestModel.UserSymmetricKey);
requestModel.MasterPasswordUnlockData = new MasterPasswordUnlockData
requestModel.MasterPasswordUnlock = new MasterPasswordUnlockData
{
Kdf = alignedKdf,
MasterKeyWrappedUserKey = masterKeyWrappedUserKey,
@@ -249,12 +249,12 @@ public class IdentityApplicationFactory : WebApplicationFactoryBase<Startup>
};
}
if (requestModel.MasterPasswordAuthenticationData != null)
if (requestModel.MasterPasswordAuthentication != null)
{
// Ensure registration uses the same hash the tests will provide at login.
// PM-28143 - When MasterPasswordAuthenticationData is the only source of the auth hash,
// stop overriding it from MasterPasswordHash and delete this whole reassignment block.
requestModel.MasterPasswordAuthenticationData = new MasterPasswordAuthenticationData
requestModel.MasterPasswordAuthentication = new MasterPasswordAuthenticationData
{
Kdf = alignedKdf,
MasterPasswordAuthenticationHash = requestModel.MasterPasswordHash,