Skip to content

Benchmark PR 38446 - #17

Open
celmis-codereviewer wants to merge 1 commit into
cr-base-38446from
cr-pr-38446
Open

celmis-codereviewer wants to merge 1 commit into
cr-base-38446from
cr-pr-38446

Conversation

@celmis-codereviewer

Copy link
Copy Markdown

Benchmark reproduction of keycloak#38446

Signed-off-by: rtufisi <rtufisi@phasetwo.io>
celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

celmis-codereviewer

This comment was marked as outdated.

@celmis-codereviewer celmis-codereviewer left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ CHANGES REQUESTED — blocking findings

Full findings and scope are in the review summary comment on this pull request — one persistent comment, updated in place on every run.

public Stream<CredentialModel> getCredentials(RealmModel realm, UserModel user) {
var myUser = getMyUser(user);
RecoveryAuthnCodesCredentialModel model;
List<CredentialModel> credentialModels = new ArrayList<>();

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why: myUser returned by getMyUser(user) on line 232 can be null when the user is not found in storage; dereferenced without a check on line 234, throwing a NullPointerException.

🟠 NullPointerException when user is not present in storage

In getCredentials, getMyUser(user) on line 232 will return null if the user is not managed by this storage provider. Line 234 then accesses myUser.recoveryCodes directly without checking if myUser is null, which will result in a NullPointerException. Other methods in this class (such as isConfiguredFor and isValid) explicitly check if (myUser == null) before accessing user fields.

Suggested change
List<CredentialModel> credentialModels = new ArrayList<>();
var myUser = getMyUser(user);
if (myUser == null) {
return Stream.empty();
}
RecoveryAuthnCodesCredentialModel model;

agent: defect · rule: defect.null-dereference · confidence: 0.95

List<CredentialModel> credentialModels = new ArrayList<>();
if (myUser.recoveryCodes != null) {
try {
model = RecoveryAuthnCodesCredentialModel.createFromValues(

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why: myUser.recoveryCodes.getCredentialData() holds a JSON array of strings, so JsonSerialization.readValue on line 237 returns a List of String objects, causing a ClassCastException when RecoveryAuthnCodesCredentialModel methods expect elements of type RecoveryAuthnCodeRepresentation.

🟠 Incompatible list element type deserialized for RecoveryAuthnCodesCredentialModel

In BackwardsCompatibilityUserStorage.updateCredential, recovery codes credentials are stored by serializing generatedCodes (List<String>) into JSON format. When getCredentials reads this credential data on line 237 using JsonSerialization.readValue(..., List.class), Jackson produces a List<String>. Passing this raw list to RecoveryAuthnCodesCredentialModel.createFromValues(...) succeeds at compile time due to raw type unchecked conversion, but causes a ClassCastException at runtime whenever the model attempts to access elements expecting RecoveryAuthnCodeRepresentation objects.

Suggested change
model = RecoveryAuthnCodesCredentialModel.createFromValues(
List<String> rawCodes = JsonSerialization.readValue(myUser.recoveryCodes.getCredentialData(), List.class);
model = RecoveryAuthnCodesCredentialModel.createFromRawValues(
rawCodes,
myUser.recoveryCodes.getCreatedDate(),
myUser.recoveryCodes.getUserLabel()
);

agent: defect · rule: defect.class-cast · confidence: 0.95


// Authenticate as the user
testAppHelper.startLogin("otp1", "pass");
enterRecoveryCodes(enterRecoveryAuthnCodePage, driver, 0, recoveryKeys);

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why: When testRecoveryKeysSetupAndLogin runs on line 259 with expectedCode 0, getRecoveryAuthnCodeToEnterNumber on line 479 returns 1 for the 1-indexed recovery code, causing the assertion on line 480 to fail.

🟠 Incorrect expected code number passed to enterRecoveryCodes

In Keycloak, recovery code numbers presented on the login screen are 1-indexed (e.g. code #1). Therefore, enterRecoveryAuthnCodePage.getRecoveryAuthnCodeToEnterNumber() on line 479 returns 1 for the first code. Passing 0 as expectedCode on line 259 causes assertEquals("Incorrect code presented to login", 0, 1) on line 480 to fail with an AssertionError during test execution.

Suggested change
enterRecoveryCodes(enterRecoveryAuthnCodePage, driver, 0, recoveryKeys);
enterRecoveryCodes(enterRecoveryAuthnCodePage, driver, 1, recoveryKeys);

agent: defect · rule: defect.assertion-failure · confidence: 0.95

enterRecoveryAuthnCodePage.setDriver(driver);
enterRecoveryAuthnCodePage.assertCurrent();
int requestedCode = enterRecoveryAuthnCodePage.getRecoveryAuthnCodeToEnterNumber();
org.junit.Assert.assertEquals("Incorrect code presented to login", expectedCode, requestedCode);

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why: requestedCode on line 479 holds 1 for the first recovery code; used directly as a 0-based index into generatedRecoveryAuthnCodes on line 481, fetching index 1 (the second code) instead of index 0.

🟠 Off-by-one indexing into generatedRecoveryAuthnCodes list

Recovery code numbers returned by getRecoveryAuthnCodeToEnterNumber() are 1-based (1, 2, ...), while generatedRecoveryAuthnCodes is a zero-indexed List. Line 481 uses requestedCode directly as the index, so when code #1 is requested (requestedCode == 1), generatedRecoveryAuthnCodes.get(1) fetches the second code in the list instead of the first code at index 0.

Suggested change
org.junit.Assert.assertEquals("Incorrect code presented to login", expectedCode, requestedCode);
enterRecoveryAuthnCodePage.enterRecoveryAuthnCode(generatedRecoveryAuthnCodes.get(requestedCode - 1));

agent: defect · rule: defect.off-by-one · confidence: 0.95

@celmis-codereviewer

Copy link
Copy Markdown
Author

🤖 Code Review for PR #17

❌ CHANGES REQUESTED — blocking findings

Findings

  • 🟠 Error: 4

Scope

  • Files changed: 8
  • Lines: +256 / -31

Performance

  • Analysis time: 113.9s · agents: cve, structural, security, contract, defect · tokens: 49,996/30,300

Powered by Code Analyzer · context: tree-sitter graph + cve, structural, security, contract, defect

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.

2 participants