Skip to content

NPE in InfinispanOrganizationProvider if userCache is disabled #34603

@mduchrow

Description

@mduchrow

Before reporting an issue

  • I have read and understood the above terms for submitting issues, and I understand that my issue may be closed without action if I do not follow them.

Area

authentication

Describe the bug

The following exception occurs at the login attempt for the admin console of master realm, when the user cache is disabled (spi-user-cache-default-enabled=false).
2024-11-04 08:32:43,879 +0100 WARN [org.keycloak.services] (executor-thread-1) KC-SERVICES0013: Failed authentication: java.lang.NullPointerException: Cannot invoke "org.keycloak.models.cache.infinispan.UserCacheSession.isInvalid(String)" because "this.userCache" is null at org.keycloak.models.cache.infinispan.organization.InfinispanOrganizationProvider.isInvalid(InfinispanOrganizationProvider.java:364) at org.keycloak.models.cache.infinispan.organization.InfinispanOrganizationProvider.count(InfinispanOrganizationProvider.java:293) at org.keycloak.storage.UserStorageManager.isReadOnlyOrganizationMember(UserStorageManager.java:943) at org.keycloak.storage.UserStorageManager.importValidation(UserStorageManager.java:117) at org.keycloak.storage.UserStorageManager.getUserById(UserStorageManager.java:389) at org.keycloak.models.sessions.infinispan.AuthenticationSessionAdapter.getAuthenticatedUser(AuthenticationSessionAdapter.java:310) at org.keycloak.authentication.AuthenticationProcessor$Result.getUser(AuthenticationProcessor.java:455) at org.keycloak.authentication.authenticators.conditional.ConditionalUserConfiguredAuthenticator.isConfiguredFor(ConditionalUserConfiguredAuthenticator.java:61) at org.keycloak.authentication.authenticators.conditional.ConditionalUserConfiguredAuthenticator.lambda$matchConditionInFlow$3(ConditionalUserConfiguredAuthenticator.java:38) at java.base/java.util.stream.MatchOps$1MatchSink.accept(Unknown Source) at java.base/java.util.LinkedList$LLSpliterator.tryAdvance(Unknown Source) at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(Unknown Source) at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(Unknown Source) at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source) at java.base/java.util.stream.MatchOps$MatchOp.evaluateSequential(Unknown Source) at java.base/java.util.stream.MatchOps$MatchOp.evaluateSequential(Unknown Source) at java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source) at java.base/java.util.stream.ReferencePipeline.allMatch(Unknown Source) at org.keycloak.authentication.authenticators.conditional.ConditionalUserConfiguredAuthenticator.matchConditionInFlow(ConditionalUserConfiguredAuthenticator.java:38) at org.keycloak.authentication.authenticators.conditional.ConditionalUserConfiguredAuthenticator.matchCondition(ConditionalUserConfiguredAuthenticator.java:20) at org.keycloak.authentication.DefaultAuthenticationFlow.conditionalNotMatched(DefaultAuthenticationFlow.java:378) at org.keycloak.authentication.DefaultAuthenticationFlow.lambda$isConditionalSubflowDisabled$5(DefaultAuthenticationFlow.java:354) at java.base/java.util.stream.MatchOps$1MatchSink.accept(Unknown Source) at java.base/java.util.ArrayList$ArrayListSpliterator.tryAdvance(Unknown Source) at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(Unknown Source) at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(Unknown Source) at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source) at java.base/java.util.stream.MatchOps$MatchOp.evaluateSequential(Unknown Source) at java.base/java.util.stream.MatchOps$MatchOp.evaluateSequential(Unknown Source) at java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source) at java.base/java.util.stream.ReferencePipeline.anyMatch(Unknown Source) at org.keycloak.authentication.DefaultAuthenticationFlow.isConditionalSubflowDisabled(DefaultAuthenticationFlow.java:354) at org.keycloak.authentication.DefaultAuthenticationFlow.processFlow(DefaultAuthenticationFlow.java:265) at org.keycloak.authentication.DefaultAuthenticationFlow.processSingleFlowExecutionModel(DefaultAuthenticationFlow.java:400) at org.keycloak.authentication.DefaultAuthenticationFlow.continueAuthenticationAfterSuccessfulAction(DefaultAuthenticationFlow.java:176) at org.keycloak.authentication.DefaultAuthenticationFlow.processAction(DefaultAuthenticationFlow.java:152) at org.keycloak.authentication.AuthenticationProcessor.authenticationAction(AuthenticationProcessor.java:1034) at org.keycloak.services.resources.LoginActionsService.processFlow(LoginActionsService.java:378) at org.keycloak.services.resources.LoginActionsService.processAuthentication(LoginActionsService.java:349) at org.keycloak.services.resources.LoginActionsService.authenticate(LoginActionsService.java:341) at org.keycloak.services.resources.LoginActionsService.authenticateForm(LoginActionsService.java:407) ...

The whole implementation of class InfinispanOrganizationProvider assumes that userCache (and realmCache) are enabled and available (no null check anywhere).
Even worse, it expects them to be instances of **UserCacheSession** (and RealmCacheSession). Therefore, it is not possible to implement and use a custom org.keycloak.models.cache.UserCache (or org.keycloak.models.cache.CacheRealmProvider).

Version

26.0.5

Regression

  • The issue is a regression

Expected behavior

Keycloak must work correctly with a disabled userCache (spi-user-cache-default-enabled=false).

Actual behavior

NullPointerException at login.
WARN [org.keycloak.services] (executor-thread-1) KC-SERVICES0013: Failed authentication: java.lang.NullPointerException: Cannot invoke "org.keycloak.models.cache.infinispan.UserCacheSession.isInvalid(String)" because "this.userCache" is null at org.keycloak.models.cache.infinispan.organization.InfinispanOrganizationProvider.isInvalid(InfinispanOrganizationProvider.java:364) at ...

How to Reproduce?

  1. Configure spi-user-cache-default-enabled=false
  2. Rebuild and start Keycloak
  3. Try to login to master realm admin console

Anything else?

Workaround: Build Keycloak server with features-disabled=organization

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions