flow icon indicating copy to clipboard operation
flow copied to clipboard

Nullpointer exception in flow server

Open wegerv opened this issue 3 months ago • 12 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