-
Notifications
You must be signed in to change notification settings - Fork 1.5k
feat(auth-validator): [Auth/PM-22975] Client Version Validator #6588
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat(auth-validator): [Auth/PM-22975] Client Version Validator #6588
Conversation
|
Great job! No new security vulnerabilities introduced in this pull request |
…hups to baserequest validator.
…e white spaces as well as the renaming of a file
…ixing the rename to the correct file.
| // 1.5 Now check the version number of the client. Do this after ValidateContextAsync so that | ||
| // we prevent account enumeration. If we were to do this before ValidateContextAsync, then attackers | ||
| // could use a known invalid client version and make a request for a user (before we know if they have | ||
| // demonstrated ownership of the account via correct credentials) and identify if they exist by getting | ||
| // an error response back from the validator saying the user is not compatible with the client. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💭 Could someone double check my explanation here?
…ng a little to be more clear.
|
Claude finished @Patrick-Pimentel-Bitwarden's task —— View job Code Review CompleteI've completed a comprehensive review of this PR. The implementation adds a client version validator to prevent v2 encryption users from logging in with older client versions. Overall, the approach is sound, but I've identified several findings that require attention. Summary of ChangesWhat Changed:
Status: The critical bug at BaseRequestValidator.cs:131 was already fixed in commit Critical FindingsFinding 1: Hardcoded version requires code changes for updates
|
| public static EncryptionType GetEncryptionType(string encString) | ||
| { | ||
| var parts = encString.Split('.'); | ||
| if (parts.Length == 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (parts.Length == 1)
{
throw new ArgumentException("Encryption type string must contain a type prefix and data separated by '.'");
}And for the second case:
throw new ArgumentException($"Unrecognized encryption type: '{parts[0]}'");There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is code copied from KM, I'm hesitant to make more changes to their work.
src/Identity/IdentityServer/RequestValidators/BaseRequestValidator.cs
Outdated
Show resolved
Hide resolved
| { | ||
| private static readonly string UpgradeMessage = "Please update your app to continue using Bitwarden"; | ||
|
|
||
| public async Task<bool> ValidateAsync(User? user, CustomValidatorRequestContext requestContext) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💭 The null check for user returns true (allowing authentication to proceed). Consider whether this is the correct behavior:
- Current behavior: If
useris null (shouldn't happen in practice), validation passes - Alternative: Fail validation if user is null since we can't determine their encryption version
Which behavior is intentional here? If the current fail-open behavior is intentional for defense-in-depth, consider adding a comment explaining the reasoning.
| true when isPrivateKeyEncryptionV2 => true, | ||
| // Valid v1 user | ||
| false when !isPrivateKeyEncryptionV2 => false, | ||
| _ => throw new InvalidOperationException( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ Cryptographic state validation error lacks detail - The exception message doesn't specify which invalid state was detected, making debugging difficult. Consider:
_ => throw new InvalidOperationException(
$"User {user.Id} is in an invalid encryption state: " +
$"HasSignatureKeyPair={hasSignatureKeyPair}, " +
$"IsPrivateKeyV2={isPrivateKeyEncryptionV2}. " +
"Expected both true (v2) or both false (v1).")This provides actionable information for support/debugging without exposing sensitive data.
| return null; | ||
| } | ||
|
|
||
| if (await isV2EncryptionUserQuery.Run(user)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💭 Error handling consideration - If isV2EncryptionUserQuery.Run(user) throws an exception (e.g., invalid encryption state from line 27 of IsV2EncryptionUserQuery), should that:
- Propagate and fail the login attempt (current behavior)
- Be caught here and fail-open (return
nullallowing login) - Be caught and fail-closed (return the minimum version, blocking login)
The current behavior (1) seems reasonable for detecting corruption, but consider whether it could be weaponized. If a user's account gets into an invalid state, they'll be locked out until support fixes it.
|
I am seeing 100 failures in tests, double checking what is going on, consider holding off on approving. |

NEEDS TESTING ON FEATURE BRANCH
🎟️ Tracking
https://bitwarden.atlassian.net/browse/PM-22975
📔 Objective
The objective of this ticket is to create a client version validator that checks the header data on a token request and prevent users who have migrated to v2 from logging in with older client versions.
📸 Screenshots
Validator.Working.mov
Non.Rotated.Key.Working.Fine.mov
⏰ 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