Skip to content

Conversation

@akshayutture-augment
Copy link
Contributor

mposolda and others added 2 commits July 22, 2025 10:00
closes #41242
closes #41008

Signed-off-by: mposolda <[email protected]>
This change modifies the method signature to require a UserModel parameter
for proper user context validation during conditional passkey checks.
@akshayutture-augment
Copy link
Contributor Author

@claude review this PR

1 similar comment
@akshayutture-augment
Copy link
Contributor Author

@claude review this PR

@claude
Copy link

claude bot commented Nov 20, 2025

Claude finished @akshayutture-augment's task —— View job


Code Review Complete ✓

Overview

This PR fixes re-authentication with passkeys (issues #41242 and #41008) by ensuring that passkey authentication remains available during re-authentication flows (e.g., when using OIDC prompt=login). The changes span 9 files with significant improvements to authentication logic and comprehensive test coverage.

Summary of Changes

Core Authentication Changes

  1. AbstractUsernameFormAuthenticator.java - Refactored error handling

    • Changed USER_SET_BEFORE_USERNAME_PASSWORD_AUTH from protected to public for wider accessibility
    • Extracted re-authentication form setup logic into AuthenticatorUtils.setupReauthenticationInUsernamePasswordFormError()
  2. UsernameForm.java - Fixed passkey skip logic

    • Added condition !isConditionalPasskeysEnabled() to prevent skipping form when passkeys are enabled (line 47)
  3. UsernamePasswordForm.java - Improved passkey availability during re-authentication

    • Moved passkey setup outside the context.getUser() == null block (lines 114-117)
    • New helper method isConditionalPasskeysEnabled(UserModel user) checks if passkeys should be enabled
    • Ensures passkeys are available both when user is set and when not set
  4. WebAuthnAuthenticator.java - Better encapsulation

    • Extracted user check into new method shouldShowWebAuthnAuthenticators()
    • Improved code readability and maintainability
  5. WebAuthnConditionalUIAuthenticator.java - Enhanced error handling

    • Added AuthenticatorUtils.setupReauthenticationInUsernamePasswordFormError() call in error response (line 52)
    • Overrides shouldShowWebAuthnAuthenticators() to return false (conditional UI doesn't show authenticator list)
  6. AuthenticatorUtils.java - New utility method

    • Added setupReauthenticationInUsernamePasswordFormError() method to centralize form setup logic
    • Sets USERNAME_HIDDEN and REGISTRATION_DISABLED attributes during re-authentication

Test Coverage

Excellent test coverage across 3 test files with new re-authentication scenarios:

  • PasskeysOrganizationAuthenticationTest.java - Added re-authentication test
  • PasskeysUsernameFormTest.java - Added re-authentication test
  • PasskeysUsernamePasswordFormTest.java - Added multiple re-authentication tests

Code Quality Assessment

✅ Strengths

  1. Good Refactoring - Extracted repeated code into AuthenticatorUtils.setupReauthenticationInUsernamePasswordFormError() following DRY principle

  2. Comprehensive Test Coverage - Added multiple test scenarios covering re-authentication flows with prompt=login

  3. Minimal Impact - Changes are surgical and focused on the specific bug without unnecessary refactoring

  4. Better Encapsulation - New shouldShowWebAuthnAuthenticators() method improves code organization

  5. Documentation - Added helpful JavaDoc comment for shouldShowWebAuthnAuthenticators() method

⚠️ Issues & Concerns

1. Logic Inconsistency in isConditionalPasskeysEnabled()

Severity: Medium | UsernamePasswordForm.java:160-162

protected boolean isConditionalPasskeysEnabled(UserModel user) {
    return webauthnAuth != null && webauthnAuth.isPasskeysEnabled() && user != null;
}

Problem: The method requires user != null, but it's called in contexts where user can be null (line 115 and 137). This means passkeys won't be enabled when user is null, which may be intentional but seems contradictory to the fix purpose.

Impact: In authenticate() at line 115, when context.getUser() returns null, passkeys won't be set up, potentially limiting the fix's effectiveness.

Suggestion: Consider whether the user null check is correct for the intended behavior. The method name suggests it should check if conditional passkeys are enabled for the system, not necessarily for a specific user.

2. Potential Null Pointer in UsernameForm

Severity: Low | UsernameForm.java:47

if (context.getUser() != null && !isConditionalPasskeysEnabled()) {

Problem: The method isConditionalPasskeysEnabled() takes no parameters here, but in the parent class UsernamePasswordForm it requires a UserModel parameter. This suggests UsernameForm overrides this method (not visible in diff), but the relationship isn't clear.

Suggestion: Verify that UsernameForm properly overrides isConditionalPasskeysEnabled() or uses a different signature.

3. Visibility Change Rationale

Severity: Very Low | AbstractUsernameFormAuthenticator.java:58

The constant USER_SET_BEFORE_USERNAME_PASSWORD_AUTH changed from protected to public. While this is needed for AuthenticatorUtils, consider if package-private would be more appropriate to limit exposure.

4. Test Assertion Changes

Severity: Low | PasskeysOrganizationAuthenticationTest.java:197, 210

The test expectations changed from asserting passkeys form is absent to asserting it's present:

// Changed from:
Assert.assertThrows(NoSuchElementException.class, () -> driver.findElement(...));
// To:
MatcherAssert.assertThat(driver.findElement(By.xpath("//form[@id='webauth']")), Matchers.notNullValue());

Issue: This is a behavior change, not just a fix. The comment says "Passkeys still enabled" was added to clarify, but this represents a significant UX change during re-authentication error states. Ensure this is the intended behavior.

5. Missing Null Check in Challenge Override

Severity: Low | UsernamePasswordForm.java:136-141

@Override
protected Response challenge(AuthenticationFlowContext context, String error, String field) {
    if (isConditionalPasskeysEnabled(context.getUser())) {
        // setup webauthn data when possible
        webauthnAuth.fillContextForm(context);
    }
    return super.challenge(context, error, field);
}

Problem: No explicit null check on webauthnAuth before calling fillContextForm(), though it's checked in isConditionalPasskeysEnabled(). This creates implicit dependency.

Suggestion: Add explicit null check or document the assumption.


Security Considerations

No security vulnerabilities detected

  • No SQL injection risks
  • No XSS vulnerabilities
  • No authentication bypass issues
  • No credential exposure
  • Proper error handling maintained
  • Re-authentication flow correctly validates user identity

Performance & Best Practices

✅ Good Practices

  • Method extraction for reusability
  • Consistent error handling
  • Proper use of helper methods

💡 Minor Improvements

  1. Consider using Optional - For the webauthnAuth field to make nullability explicit
  2. Add more JavaDoc - Methods like isConditionalPasskeysEnabled() could benefit from documentation explaining the user parameter requirement
  3. Test naming - Consider more descriptive test names like testWebauthnReauthenticationWithPromptLogin() vs webauthnLoginWithDiscoverableKey_reauthentication()

Recommendations

Required

  1. Clarify isConditionalPasskeysEnabled() logic - Document why user must be non-null and ensure it aligns with intended behavior

Suggested

  1. 💡 Review visibility change of USER_SET_BEFORE_USERNAME_PASSWORD_AUTH - Consider package-private access
  2. 💡 Add JavaDoc to isConditionalPasskeysEnabled() explaining the user parameter requirement
  3. 💡 Verify test expectation changes align with product requirements

Conclusion

Overall Assessment: ✅ Approve with minor concerns

This is a well-implemented fix that addresses the core issue of passkeys not being available during re-authentication. The code changes are focused and surgical, with excellent test coverage. The main concern is the isConditionalPasskeysEnabled() method logic that requires a non-null user, which may limit the fix in some scenarios. This should be verified to ensure it aligns with the intended behavior.

The refactoring to extract common code into AuthenticatorUtils is a good improvement, and the test coverage gives confidence that the fix works as intended.


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants