flow
flow copied to clipboard
Nullpointer exception in flow server
Description
In my logs I see a nullpointerexception after logging out (I think session expiration):
13 mei 2024 10:33:33,490 ERROR com.vaadin.flow.server.DefaultErrorHandler:105 - java.lang.NullPointerException: Cannot invoke "com.vaadin.flow.server.VaadinSession.getState()" because the return value of "com.vaadin.flow.component.UI.getSession()" is null at com.vaadin.flow.server.communication.MetadataWriter.createMetadata(MetadataWriter.java:69) ~[flow-server-24.3.2.jar:24.3.2] at com.vaadin.flow.server.communication.UidlWriter.createUidl(UidlWriter.java:162) ~[flow-server-24.3.2.jar:24.3.2] at com.vaadin.flow.server.communication.UidlRequestHandler.createUidl(UidlRequestHandler.java:155) ~[flow-server-24.3.2.jar:24.3.2] at com.vaadin.flow.server.communication.UidlRequestHandler.writeUidl(UidlRequestHandler.java:145) ~[flow-server-24.3.2.jar:24.3.2] at com.vaadin.flow.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:115) ~[flow-server-24.3.2.jar:24.3.2] at com.vaadin.flow.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:40) ~[flow-server-24.3.2.jar:24.3.2] at com.vaadin.flow.server.VaadinService.handleRequest(VaadinService.java:1573) ~[flow-server-24.3.2.jar:24.3.2] at com.vaadin.flow.server.VaadinServlet.service(VaadinServlet.java:398) ~[flow-server-24.3.2.jar:24.3.2] at com.vaadin.flow.spring.SpringServlet.service(SpringServlet.java:106) ~[vaadin-spring-24.3.2.jar:?] at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614) ~[jakarta.servlet-api-6.0.0.jar!/:6.0.0] at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) ~[undertow-core-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:257) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.handlers.ServletInitialHandler.dispatchToServlet(ServletInitialHandler.java:192) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.spec.RequestDispatcherImpl.forwardImpl(RequestDispatcherImpl.java:223) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.spec.RequestDispatcherImpl.forwardImplSetup(RequestDispatcherImpl.java:147) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.spec.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:110) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at org.springframework.web.servlet.mvc.ServletForwardingController.handleRequestInternal(ServletForwardingController.java:141) ~[spring-webmvc-6.1.5.jar:6.1.5] at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:178) ~[spring-webmvc-6.1.5.jar:6.1.5] at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:51) ~[spring-webmvc-6.1.5.jar:6.1.5] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) ~[spring-webmvc-6.1.5.jar:6.1.5] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) ~[spring-webmvc-6.1.5.jar:6.1.5] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) ~[spring-webmvc-6.1.5.jar:6.1.5] at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914) ~[spring-webmvc-6.1.5.jar:6.1.5] at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:547) ~[jakarta.servlet-api-6.0.0.jar!/:6.0.0] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) ~[spring-webmvc-6.1.5.jar:6.1.5] at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614) ~[jakarta.servlet-api-6.0.0.jar!/:6.0.0] at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.websockets.jsr.JsrWebSocketFilter.doFilter(JsrWebSocketFilter.java:172) ~[undertow-websockets-jsr-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.smallrye.opentracing.contrib.jaxrs2.server.SpanFinishingFilter.doFilter(SpanFinishingFilter.java:69) ~[smallrye-opentracing-contrib-3.0.0.jar!/:?] at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:108) ~[spring-web-6.1.5.jar:6.1.5] at org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:365) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:117) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:227) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:221) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) ~[spring-web-6.1.5.jar:6.1.5] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.5.jar:6.1.5] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.5.jar:6.1.5] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:82) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:69) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.5.jar:6.1.5] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.5.jar:6.1.5] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113) ~[spring-web-6.1.5.jar:6.1.5] at org.springframework.web.servlet.handler.HandlerMappingIntrospector.lambda$createCacheFilter$3(HandlerMappingIntrospector.java:195) ~[spring-webmvc-6.1.5.jar:6.1.5] at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113) ~[spring-web-6.1.5.jar:6.1.5] at org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:74) ~[spring-web-6.1.5.jar:6.1.5] at org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration$CompositeFilterChainProxy.doFilter(WebMvcSecurityConfiguration.java:230) ~[spring-security-config-6.2.2.jar:6.2.2] at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:352) ~[spring-web-6.1.5.jar:6.1.5] at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:268) ~[spring-web-6.1.5.jar:6.1.5] at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-6.1.5.jar:6.1.5] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.5.jar:6.1.5] at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-6.1.5.jar:6.1.5] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.5.jar:6.1.5] at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at org.springframework.boot.web.servlet.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:124) ~[spring-boot-3.1.2.jar:3.1.2] at org.springframework.boot.web.servlet.support.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:99) ~[spring-boot-3.1.2.jar:3.1.2] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.5.jar:6.1.5] at org.springframework.boot.web.servlet.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:117) ~[spring-boot-3.1.2.jar:3.1.2] at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-6.1.5.jar:6.1.5] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.5.jar:6.1.5] at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68) ~[?:?] at io.undertow.servlet.handlers.SendErrorPageHandler.handleRequest(SendErrorPageHandler.java:52) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) ~[undertow-core-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:275) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:134) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:131) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1435) ~[?:?] at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1435) ~[?:?] at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1435) ~[?:?] at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1435) ~[?:?] at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1435) ~[?:?] at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:255) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:100) ~[undertow-servlet-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.server.Connectors.executeRootHandler(Connectors.java:391) ~[undertow-core-2.3.0.Final.jar!/:2.3.0.Final] at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:859) ~[undertow-core-2.3.0.Final.jar!/:2.3.0.Final] at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35) ~[?:?] at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1990) ~[?:?] at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486) ~[?:?] at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377) ~[?:?] at org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1282) ~[?:?] at java.lang.Thread.run(Thread.java:1583) [?:?]
Expected outcome
I would like the null pointer be handled.
Minimal reproducible example
None
Steps to reproduce
None (sorry)
Environment
Vaadin version(s): 24.3.2 OS: Windows
Browsers
No response
Hi, thanks for reporting the issue.
Could you please provide more information about your application?
Are you using VaadinWebSecurity
for Spring Security configuration?
How do you perform logout? Are you using Vaadin AuthenticationContext.logout()
utility?
To handle logout I'm registering a SessionDestroyListener on the ServiceInitEvent in the serviceInit method of the VaadinServiceInitListener. In the destroylistener event handler I do some system logging to register the logout. That seems to be executed well.
Somewhere after that -- so after my destroylistener is called -- the nullpointer exception happens.
I'm using SpringFramework security (through @EnableWebSecurity), but not the AuthenticationContext utility. After login I use SecurityContextHolder.getContext().setAuthentication(authentication), however I never set that to null again.
Hope this helps...
So you are not using VaadinWebSecurity class? Could you share the code you use to trigger the logout and your destroy listener implementation and registration?
Also sharing your Spring security configuration may help to understand the problem
No, my SecurityConfig doesn't extend VaadinWebSecurity (yet).
Destroy listener implementation:
event.getSource().addSessionDestroyListener(sessionEvent -> {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); //
if (authentication != null) {
trafficSenseSessionService.doHandleSessionDestroyed(authentication);
// register logout
if (trafficSenseAuthorizationService!= null) {
trafficSenseAuthorizationService.logout(authentication);
}
}
});
where doHandleSessionDestroyed() writes a log message to a database and Service.logout() does nothing.
In this case I think the logout is triggered by expiration of the session, but if the user logs out it is triggered by
VaadinSession.getCurrent().getSession().invalidate();
UiSupport.getCurrentUI().getPage().reload();
@Configuration
@EnableWebSecurity
@Order(ConfigurationOrder.secondBatch)
public class SecurityConfiguration {
final private Logger log = LoggerFactory.getLogger(getClass());
// --- login
public static final String LOGIN_ROUTE = "login";
public static final String LOGIN_PROCESSING_URL = "/" + LOGIN_ROUTE;
public static final String LOGIN_FAILURE_URL = "/" + LOGIN_ROUTE + "?error";
// --- logout
public static final String LOGOUT_ROUTE = "logout";
public static final String LOGOUT_SUCCESS_URL = "/" + LOGOUT_ROUTE;
// --- run
public static final String MAIN_ROUTE = ""; // always empty
public static boolean enableSecurity = true; // secure is the default
private final PasswordEncoder passwordEncoder;
@Autowired
private TrafficViewerAuthenticationProvider authenticationProvider;
@Autowired
public SecurityConfiguration(
final PasswordEncoder passwordEncoder
) {
this.passwordEncoder = passwordEncoder;
}
/**
* Publish a SecurityFilterChain Bean.
*/
@Bean
public SecurityFilterChain filterChain(final HttpSecurity http) throws Exception {
if (SecurityConfiguration.enableSecurity) {
// disable caching
http.headers().cacheControl();
final AuthenticationSuccessHandler authenticationSuccessHandler = new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(final HttpServletRequest request, final HttpServletResponse response,
final Authentication authentication) throws IOException, ServletException {
log.info("Succesfull login: " + authentication.getName());
final HttpSession session = request.getSession(false);
if (session != null) {
final User user = new User();
user.setUserName(authentication.getName()); //, activeUserStore);
session.setAttribute("user", user);
}
}
};
// Not using Spring built-in CSRF (Cross-Site Request Forgery) protection
// here to be able to use plain HTML for the login page
final HttpSecurity security = http.csrf().disable();
//final AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry authorizeHttpRequestsConfigurer = http.authorizeHttpRequests();
final ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry reg =
http.authorizeRequests();
// Register our CustomRequestCache that saves unauthorized access attempts, so
// the user is redirected after login.
security.requestCache().requestCache(new CustomRequestCache())
// Restrict access to our application.
.and().authorizeRequests()
// Allow all flow internal requests.
.requestMatchers(SecurityUtils::isFrameworkInternalRequest).permitAll()
// Allow all requests by logged in users.
.anyRequest().authenticated()
// Configure the login page.
.and().formLogin().loginPage("/" + SecurityConfiguration.LOGIN_ROUTE).permitAll()
.loginProcessingUrl(SecurityConfiguration.LOGIN_PROCESSING_URL)
// failure
.failureUrl(SecurityConfiguration.LOGIN_FAILURE_URL)
// succes
.successHandler(authenticationSuccessHandler)
// Configure logout
.and().logout().logoutSuccessUrl(SecurityConfiguration.LOGOUT_SUCCESS_URL)
// exceptions
.and().exceptionHandling().accessDeniedPage("/page_403");
} else {
log.warn("Security has been disabled.");
http.authorizeRequests().anyRequest().permitAll();
}
return http.build();
}
@Autowired
public void configureGlobalSecurity(final AuthenticationManagerBuilder auth) throws Exception {
// nothing
}
private String encodedPassword(final String string) {
//return string;
return this.passwordEncoder.encode(string);
}
/**
* Register an application specific WebSecurityCustomizer.
*/
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> {
web.ignoring().requestMatchers(
// ... not copied in this example for security reasons
};
}
@Bean
AuthenticationManager authenticationManager(
final AuthenticationConfiguration authenticationConfiguration) throws Exception {
log.info("Setting AuthenticationManager.");
return authenticationConfiguration.getAuthenticationManager();
}
@Autowired
void registerProvider(final AuthenticationManagerBuilder auth) {
// set our own authentication provider
auth.authenticationProvider(authenticationProvider);
//auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}
}
The error is weird because looking at the code, the VaadinSession
is taken from UI and used, a couple of lines before the one the exception is thrown. And there is nothing between that is nullifying the session.
And the error happens during a UIDL request, so it seems not related to session expiration.
I wonder if there's something that is closing the UI without a proper VaadinSession lock.
A first suggestion is to update Vaadin to the latest version (24.3.12). Currently, I don't recall changes that can be related to this kind of issue, but the version you are using is a bit outdated.
Side note: based on the online documentation (see SecurityService.logout()
in https://vaadin.com/docs/latest/security/enabling-security#log-out-capability and SecurityUtils.logout()
in https://vaadin.com/docs/latest/security/advanced-topics/securing-plain-java-app#handling-user-log-in-out) I suggest moving the page reload code before the session invalidation.
We sometimes experience timeouts between client and server. Would it be possible that happened here?
Unfortunately, I can't say whether it could be related or not. Still, having the UI.session
nullified while processing an UIDL request should not happen if changes to the UI are applied holding the VaadinSession
lock.
And it is difficult to guess what's the cause, without being able to reproduce the issue.
Okay, thanks for the support! I'll upgrade and leave it with that.
I reported this also here https://github.com/vaadin/flow/issues/18796 . There was some investigation done on this, see the linked discord discussion.