Implement recovery key support for user storage providers - #9
Conversation
closes #38445 Signed-off-by: rtufisi <rtufisi@phasetwo.io>
1 similar comment
|
Claude finished @ShashankFC's task in 11m 48s —— View job Code Review CompleteI've reviewed the PR that adds recovery key support for user storage providers. Here are my findings: OverviewThis PR extends the recovery authentication codes feature to work with custom user storage providers, following the same pattern as OTP credentials. The implementation allows recovery codes to be stored either in user storage or local Keycloak storage. Critical Issues1. Potential NullPointerException in RecoveryAuthnCodeInputLoginBean (High Severity)File: RecoveryAuthnCodesCredentialModel recoveryCodeCredentialModel =
RecoveryAuthnCodesCredentialModel.createFromCredentialModel(credentialModelOpt.get());This code calls Fix: Add null/empty check: if (credentialModelOpt.isEmpty()) {
throw new IllegalStateException("Recovery codes credential not found");
}
RecoveryAuthnCodesCredentialModel recoveryCodeCredentialModel =
RecoveryAuthnCodesCredentialModel.createFromCredentialModel(credentialModelOpt.get());2. Missing Null Check on getNextRecoveryAuthnCode() (High Severity)File: this.codeNumber = recoveryCodeCredentialModel.getNextRecoveryAuthnCode().get().getNumber();Double Fix: Add proper Optional handling: this.codeNumber = recoveryCodeCredentialModel.getNextRecoveryAuthnCode()
.orElseThrow(() -> new IllegalStateException("No recovery codes available"))
.getNumber();3. Inconsistent Error Handling in User Storage Provider (Medium Severity)File: } catch (IOException e) {
log.error("Could not deserialize credential of type: recovery-codes");
}The exception is logged but swallowed. The method continues as if nothing happened, which could lead to silent failures. Fix: Either rethrow as a runtime exception or return an error indicator: } catch (IOException e) {
log.error("Could not deserialize credential of type: recovery-codes", e);
throw new RuntimeException("Failed to deserialize recovery codes credential", e);
}Security Concerns4. Weak Hashing Algorithm Choice (Medium Severity)File: public static final String NOM_ALGORITHM_TO_HASH = Algorithm.RS512;Using RS512 (an RSA signature algorithm) for hashing recovery codes is unusual and potentially inappropriate. RS512 is an asymmetric signature algorithm, not a hashing algorithm. This should use a proper hashing algorithm like SHA-256 or SHA-512. Additionally: The variable name has a typo: Recommendation: Use a proper cryptographic hash algorithm. Consider using the same approach as password hashing with salt and iterations. 5. Only One Hash Iteration (Low-Medium Severity)File: public static final int NUM_HASH_ITERATIONS = 1;Single iteration hashing makes the codes more vulnerable to brute-force attacks if the hashed values are compromised. While recovery codes are typically single-use, multiple iterations would provide better security. Recommendation: Increase to at least 10,000+ iterations or align with Keycloak's password hashing policy. Code Quality Issues6. Unnecessary Local Variable (Low Severity)File: var recoveryCodeCredentialProvider = session.getProvider(CredentialProvider.class, "keycloak-recovery-authn-codes");The 7. Inconsistent Credential Removal Logic (Medium Severity)File: if (recoveryCodeCredentialModel.allCodesUsed()) {
authenticatedUser.credentialManager().removeStoredCredentialById(
recoveryCodeCredentialModel.getId());
}This only removes credentials from local storage ( Issue: If credentials are in user storage, they won't be removed, leading to inconsistent behavior. 8. Missing Input Validation (Low Severity)File: The
Recommendation: Add input validation with meaningful error messages. Test Coverage Observations9. Good Test Coverage ✓The test file
Positive: The test properly validates that recovery codes work in user storage, following the same pattern as OTP tests. 10. Test Cleanup ConsiderationFile: // Revert copy of browser flow to original to keep clean slate after this test
BrowserFlowTest.revertFlows(testRealm(), BROWSER_FLOW_WITH_RECOVERY_AUTHN_CODES);This cleanup is in a Positive Aspects ✓
Recommendations SummaryMust Fix (High Priority):
Should Fix (Medium Priority): Nice to Have (Low Priority): |
Test 9nn---nReplicated from ai-code-review-evaluation/keycloak-greptile#9