Skip to content

Fail fast when UserDetailsService returns null in onLoginSuccess - #19552

Open
skdas20 wants to merge 1 commit into
spring-projects:mainfrom
skdas20:gh-19535-remember-me-null-userdetails
Open

Fail fast when UserDetailsService returns null in onLoginSuccess#19552
skdas20 wants to merge 1 commit into
spring-projects:mainfrom
skdas20:gh-19535-remember-me-null-userdetails

Conversation

@skdas20

@skdas20 skdas20 commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

When the successful Authentication carries no credentials, onLoginSuccess falls back to looking the password up through the configured UserDetailsService, but dereferences the result without checking it:

UserDetails user = getUserDetailsService().loadUserByUsername(username);
password = user.getPassword();

A UserDetailsService that returns null rather than throwing UsernameNotFoundException therefore shows up as a bare NullPointerException from inside the remember-me filter, with nothing in the stack trace pointing at the service that is actually misconfigured.

processAutoLoginCookie in this same class already guards the identical call, and is explicit about what a null return means:

UserDetails userDetails = getUserDetailsService().loadUserByUsername(cookieTokens[0]);
Assert.notNull(userDetails, () -> "UserDetailsService " + getUserDetailsService()
        + " returned null for username " + cookieTokens[0] + ". "
        + "This is an interface contract violation");

autoLoginClearsCookieIfUserServiceMisconfigured pins that behaviour in the tests. This change applies the same guard to onLoginSuccess so both lookups report the misconfiguration the same way, and adds loginSuccessFailsIfUserServiceMisconfigured alongside the existing loginSuccess tests. Without the production change that test fails with the reported NullPointerException.

One note on the approach: gh-19535 suggests skipping cookie generation instead, with

password = (user == null) ? password : user.getPassword();

I went with the existing in-class precedent rather than that, because silently continuing would quietly swallow a misconfiguration that the class elsewhere treats as a contract violation — and the user would get no remember-me cookie with no indication why. Happy to switch to the lenient form if you'd rather keep onLoginSuccess tolerant; it's a small change either way.

Closes gh-19535

onLoginSuccess dereferenced the result of loadUserByUsername without a
null check, so a UserDetailsService returning null instead of throwing
UsernameNotFoundException surfaced as a bare NullPointerException from
inside the remember-me filter.

processAutoLoginCookie already guards the same call and treats a null
return as an interface contract violation. Apply the same guard to
onLoginSuccess so both lookups report the misconfiguration consistently.

Closes spring-projectsgh-19535

Signed-off-by: skdas20 <skdas5405@gmail.com>
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: waiting-for-triage An issue we've not yet triaged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TokenBasedRememberMeServices::onLoginSuccess can throw a NPE when UserDetailsService::loadUserByUsername returns null.

2 participants