flow icon indicating copy to clipboard operation
flow copied to clipboard

Nullpointer exception in flow server

Open wegerv opened this issue 1 year ago • 18 comments

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

wegerv avatar May 13 '24 13:05 wegerv

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?

mcollovati avatar May 13 '24 14:05 mcollovati

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...

wegerv avatar May 13 '24 16:05 wegerv

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?

mcollovati avatar May 13 '24 17:05 mcollovati

Also sharing your Spring security configuration may help to understand the problem

mcollovati avatar May 13 '24 17:05 mcollovati

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();					

wegerv avatar May 14 '24 05:05 wegerv


@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);
	}

}

wegerv avatar May 14 '24 06:05 wegerv

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.

mcollovati avatar May 14 '24 06:05 mcollovati

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.

mcollovati avatar May 14 '24 06:05 mcollovati

We sometimes experience timeouts between client and server. Would it be possible that happened here?

wegerv avatar May 14 '24 06:05 wegerv

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.

mcollovati avatar May 14 '24 06:05 mcollovati

Okay, thanks for the support! I'll upgrade and leave it with that.

wegerv avatar May 14 '24 06:05 wegerv

I reported this also here https://github.com/vaadin/flow/issues/18796 . There was some investigation done on this, see the linked discord discussion.

jorgheymans avatar May 14 '24 08:05 jorgheymans

this is still happening every now and then, suspecting this request handler has something to do with it ?


  @Override
  public boolean handleRequest(
      VaadinSession session, VaadinRequest request, VaadinResponse response) throws IOException {
    final Optional<String> preferredLanguage =
        Arrays.stream(Optional.ofNullable(request.getCookies()).orElse(new Cookie[] {}))
            .filter(cookie -> "lang.pref".equals(cookie.getName()))
            .map(Cookie::getValue)
            .findFirst();
    preferredLanguage.ifPresent(
        lang -> {
          final Locale localeFromRequest = Locale.forLanguageTag(lang);
          session.accessSynchronously(
              () -> {
                if (!Objects.equals(session.getLocale(), localeFromRequest)) {
                  session.setLocale(localeFromRequest);
                }
              });
        });
    return false; // Return false to let other request handlers do their job
  }
}

Is it safe to access the session from a request handler ?

jorgheymans avatar Sep 04 '24 14:09 jorgheymans

Request handler that needs to access the VaadinSession can extend SynchronizedRequestHandler that handles the session lock.

mcollovati avatar Sep 04 '24 14:09 mcollovati

Thanks, using that one now but still getting the exception.

jorgheymans avatar Sep 04 '24 15:09 jorgheymans

I'm not sure the request handler may be the cause of the exception. Looking at the stack trace, it could seem that the UI.session gets nullified by some pending task executed when building the UIDL response, potentially enqueued by session.access(). Maybe something invalidating the session or closing the UI?

mcollovati avatar Sep 04 '24 15:09 mcollovati

Assumptions aside what could be causing it, should Vaadin internally guard against this ? It seems like a strongly assumed invariant is being violated or am i mistaken?

The result of it towards the browser is that you have to close the window or open a new private tab to get the application to load again.

jorgheymans avatar Sep 05 '24 09:09 jorgheymans

Taking in mind that we need to understand the cause of the problem to provide a valuable fix, the question is: What should Flow do in this situation? The first that comes to mind would be to trigger a resynchronization, so that the browser page should be reloaded, but I'm not sure if this is a proper solution.

mcollovati avatar Sep 05 '24 10:09 mcollovati