flow icon indicating copy to clipboard operation
flow copied to clipboard

AuthenticationContext.logout() throws NPE if invoked from VaadinSession.access()

Open archiecobbs opened this issue 5 months ago • 3 comments

Description of the bug

I have a "Logout" button and when I press it Vaadin throws an NPE.

Here's the stack trace:

java.util.concurrent.ExecutionException: java.lang.NullPointerException: Cannot invoke "com.vaadin.flow.component.UI.getPushConfiguration()" because "ui" is null
	at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:124) ~[?:?]
	at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:193) ~[?:?]
	at com.vaadin.flow.server.FutureAccess.get(FutureAccess.java:62) [flow-server-24.7.5.jar:24.7.5]
	at com.vaadin.flow.server.VaadinService.runPendingAccessTasks(VaadinService.java:2176) [flow-server-24.7.5.jar:24.7.5]
        [... lots of frames elided...]
Caused by: java.lang.NullPointerException: Cannot invoke "com.vaadin.flow.component.UI.getPushConfiguration()" because "ui" is null
	at com.vaadin.flow.spring.security.AuthenticationContext.logout(AuthenticationContext.java:135) ~[vaadin-spring-24.7.5.jar:?]
	at com.example.MyApp.security.SecurityService.logout(SecurityService.java:78) ~[ccom-1.0.0.jar:1.0.0]
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:545) ~[?:?]
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:328) ~[?:?]
	at com.vaadin.flow.server.VaadinService.runPendingAccessTasks(VaadinService.java:2173) ~[flow-server-24.7.5.jar:24.7.5]
	... 148 more

The problem is that AuthenticationContext.logout() assumes there is a current UI. Obviously this won't be the case if it is invoked from VaadinSession.access().

So which of the following is true?

  1. AuthenticationContext.logout() is only guaranteed to work if there is a current UI
  2. AuthenticationContext.logout() doesn't need a current UI, it only needs a current VaadinSession (but if there is also a current UI then that's OK too)

If 2 is true, then there is a bug here - straightforward.

If 1 is true, then there's an important missing feature here. It should be possible for a background task to invalidate the authentication in any user's session. For example, an admin may need to forcibly logout someone, or an enterprise app may always automatically logout someone after some timeout, whenever their rights & privileges are changed, etc.

Even if you don't agree that this should work, where is it documented that a current UI is required? I only see this:

Initiates the logout process of the current authenticated user by invalidating the local session and then notifying LogoutHandler.

Or as a minimal workaround, if AuthenticationContext.logout() is invoked with only a current VaadinSession then instead of throwing an exception it should just invalidate the session. Throwing an exception means the logout may not actually happen, which is a security hole.

Expected behavior

No NullPointerException and a successful logout.

Minimal reproducible example

Add a button to your app:

final VaadinSession session = VaadinSession.getCurrent();
layout.add(new Button("Logout",
    e -> session.access(this.authenticationContext::logout));

Login, then press the button.

Versions

  • Vaadin / Flow version: vaadin-spring-24.7.5.jar
  • Java version: 25-ea
  • OS version: Mac OS

archiecobbs avatar May 17 '25 22:05 archiecobbs