[PM-27278] add AccountKeysRequestModel to RegisterFinishRequestModel for account encryption v2 support#6798
[PM-27278] add AccountKeysRequestModel to RegisterFinishRequestModel for account encryption v2 support#6798
Conversation
…ed up reference to master password hash
…d more comments and fixed up some long lines.
…unts controller no longer nullish allowed.
…e thrown error messages more appropriate
…tModel.cs Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
…ed comments for tests.
…t additions to make sure properties that were once required are still required.
…ted tests and added comments for the future.
…ed new checks from review.
…tModel.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>
…d new checks for master password authentication data.
…ved invalid check.
…fled around validation checks to the request model instead of the controller.
…Added comments to clarify how these data types should be used.
…Updated docs around the validation
…Removed troublesome null safeguarding.
…Removed debug file.
…Fixed error in register finish model validation.
…ed accounts controller tests.
…essed concerns from reviewer.
…d up tests a little more.
…epts-new-data-types
…ressed more feedback. No longer overriding the master password hash.
…epts-new-data-types-repush
…d constant for feature flag.
64585b7 to
2a7a753
Compare
…for account encryption v2 support
2a7a753 to
c026649
Compare
|
Claude finished @eligrubb's task in 2m 13s —— View job Code Review Summary: PR #6798PM-27278 add AccountKeysRequestModel to RegisterFinishRequestModel for account encryption v2 support OverviewThis PR introduces V2 account encryption support for user registration. The changes allow the Key Changes Reviewed
Review ResultAPPROVED - The implementation is well-structured and maintains backward compatibility. Positive Observations
Test Coverage NoteWhile codecov reports low coverage, the PR includes unit tests in:
Reviewed with Claude Code |
| var result = await CreateAsync(user, registerFinishData.MasterPasswordAuthenticationData.MasterPasswordAuthenticationHash); | ||
| if (result.Succeeded) | ||
| { | ||
| var setRegisterFinishUserDataTask = _userRepository.SetRegisterFinishUserData(user.Id, registerFinishData); |
There was a problem hiding this comment.
Question: SetRegisterFinishUserData sets:
{
- KDF Settings
- MasterKey Protected Userkey
} // masterpassword unlock
and
{
public key
private key
} // keypair
But SetV2AccountCryptographicState already writes the keypair
So essentially we are writing the keypair twice here. Could we remove the key-pair from the registerFinishUserData task / SQL sproc?
| @KdfMemory INT, | ||
| @KdfParallelism INT, | ||
| @Key VARCHAR(MAX), | ||
| @PublicKey VARCHAR(MAX), |
There was a problem hiding this comment.
As per the other comment, we can probably remove this. Maybe it makes sense to just rename to "SetMasterPasswordUnlockData"?
There was a problem hiding this comment.
Done. I went with SetMasterPasswordUnlockUserData
| // Arrange | ||
| // V1 model and fields to be removed with | ||
| // https://bitwarden.atlassian.net/browse/PM-27326 | ||
| var legacyModel = new RegisterFinishRequestModel |
There was a problem hiding this comment.
Nit/quesion (don't have to act on it): I wonder whether these would be better served as separate tests, one legacy one not.
There was a problem hiding this comment.
I'm open to either, whichever is seen as more maintainable. I put the testing the legacy & new models in one test because I wanted to match what Auth had already been doing in the file. So if Auth feels strongly one way or the other I'd like to go with that.
| // all should be default/unset, with the exception of email and masterPasswordHint | ||
| Assert.Equal(email, newResult.Email); | ||
| Assert.Equal(masterPasswordHint, newResult.MasterPasswordHint); | ||
| Assert.Equal(KdfType.PBKDF2_SHA256, newResult.Kdf); |
There was a problem hiding this comment.
Question: Don't e expect argon2 for v2? Subsequently memory and praallelism should also be set?
There was a problem hiding this comment.
This test in particular is checking the return of the ToUser function, which I changed for v2 users to only set the email and MasterPasswordHint. All others values in the User entity will be the default value, which for Kdf settings means PBKDF2 for type & iterations, and null for memory & parallelism
| var kdfModel = new KdfRequestModel | ||
| { | ||
| KdfType = KdfType.Argon2id, | ||
| Iterations = AuthConstants.ARGON2_ITERATIONS.Default |
There was a problem hiding this comment.
Missing memory / parallelism?
| var kdfModel = new KdfRequestModel | ||
| { | ||
| KdfType = KdfType.Argon2id, | ||
| Iterations = AuthConstants.ARGON2_ITERATIONS.Default |
There was a problem hiding this comment.
Missing Memory / parallelism
| var user = model.ToUser(); | ||
| var kdfModel = new KdfRequestModel | ||
| { | ||
| KdfType = KdfType.Argon2id, |
| KdfMemory = kdfData.Memory, | ||
| KdfParallelism = kdfData.Parallelism, | ||
| UserSymmetricKey = masterKeyWrappedUserKey, | ||
| UserAsymmetricKeys = new KeysRequestModel |
There was a problem hiding this comment.
Which user is this in the test? A V1 user should use PBKDF2, a V2 User Argon2 but a v2 user should also have the other required values, not just public key / encrypted private key?
There was a problem hiding this comment.
Good catch, this should be a v1 user. Changed the values to PBKDF2.
|



🎟️ Tracking
https://bitwarden.atlassian.net/browse/PM-27278
Stacks on top of #6855.
📔 Objective
Deprecating V1 User Asymmetric Key information in favor of new V2 User Asymmetric Account Keys structure.
This PR adds support for the new
AccountKeysstructure while maintaining support for the legacyUserAsymmetricKey-based flow. Validation is updated to check eitherAccountKeysorUserAsymmetricKeysare updated. Tests include modeling for both scenarios.📸 Screenshots
⏰ Reminders before review
🦮 Reviewer guidelines
:+1:) or similar for great changes:memo:) or ℹ️ (:information_source:) for notes or general info:question:) for questions:thinking:) or 💭 (:thought_balloon:) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion:art:) for suggestions / improvements:x:) or:warning:) for more significant problems or concerns needing attention:seedling:) or ♻️ (:recycle:) for future improvements or indications of technical debt:pick:) for minor or nitpick changes