Spring Security -- Server connection lost, trying to reconnect...

https://stackoverflow.com/questions/56036571/vaadin-8-spring-boot-server-connection-lost-trying-to-reconnect

In a nutshell:
Trying to get an index page to be displayed to all (including unauthenticated) users.

The page gets displayed but immediately loses connection, displaying the “trying to reconnect” message ad perpetuum.

This is my configuration:

@Configuration
@EnableWebSecurity
class AnyRequestConfiguration : WebSecurityConfigurerAdapter(){

    override fun configure(http: HttpSecurity) {
        http
            .csrf().disable()
            .authorizeRequests()
                .antMatchers("/").permitAll()
                .anyRequest().authenticated()
    }

    override fun configure(web: WebSecurity){
        web
            .ignoring().antMatchers(
                "/VAADIN/**",
                "/frontend/**",
                "/webjars/**",
                "/images/**",
                "/frontend-es5/**", "/frontend-es6/**"
            )
    }
}

How do I get my app to not lose the connection?

hi, did you resolve your problem?

Станислав Ланг:
hi, did you resolve your problem?

Sorry about the late reply.
Yes I did.
Had to open up

.antMatchers("/vaadinServlet/UIDL/**").permitAll()
.antMatchers("/vaadinServlet/HEARTBEAT/**").permitAll()

We have the same problem using vaadin 14.1.6 and keycloak. The problem is the following:

  1. When we first login browser redirects us to keyckoak
  2. When keycloak token expires, we get this connection lost and a request is being done with ajax to keycloak and so can’t be followed. It should be done from browser instaed of ajax.

Any idea how to solve this?

I am getting the same error and then vaadinServlet is being attached at my url and as a result logout is not successful.
For example, url becomes /vaadinServlet/logout instead of /logout.

Hi,
This is my code in the SecurityConfig.java…


package com.mywork.myapp.security;

import javax.servlet.http.HttpServletRequest;

import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
import org.keycloak.adapters.springsecurity.client.KeycloakClientRequestFactory;
import org.keycloak.adapters.springsecurity.client.KeycloakRestTemplate;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter;
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
import org.keycloak.representations.AccessToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(jsr250Enabled = true)
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

	@Autowired
	public KeycloakLogoutHandler keycloakLogoutHandler;
	public KeycloakClientRequestFactory keycloakClientRequestFactory;

	@Override
	protected void configure (HttpSecurity http) throws Exception {
		http
			.csrf()
			.disable()
			.anonymous()
			.disable()
			.requestCache()
			.requestCache(requestCache())
			.and()
			.sessionManagement()
			.sessionAuthenticationStrategy(sessionAuthenticationStrategy())
			.and()
			.addFilterBefore(keycloakPreAuthActionsFilter(), LogoutFilter.class)
			.addFilterBefore(keycloakAuthenticationProcessingFilter(), LogoutFilter.class)
			.addFilterAfter(keycloakSecurityContextRequestFilter(), SecurityContextHolderAwareRequestFilter.class)
			.addFilterAfter(keycloakAuthenticatedActionsRequestFilter(), KeycloakSecurityContextRequestFilter.class)
			.exceptionHandling()
			.authenticationEntryPoint(authenticationEntryPoint())
			.and()
			.logout()
			.addLogoutHandler(keycloakLogoutHandler)
			.logoutUrl("/sso/logout")
			.logoutSuccessUrl("/")
			.and()
			.authorizeRequests()
			.antMatchers("/vaadinServlet/**")
			.permitAll()
			.antMatchers("/vaadinServlet/UIDL/**")
			.permitAll()
			.antMatchers("/vaadinServlet/HEARTBEAT/**")
			.permitAll()
			.antMatchers("/VAADIN/**")
			.permitAll()
			.antMatchers("/favicon.ico")
			.permitAll()
			.antMatchers("/robots.txt")
			.permitAll()
			.antMatchers("/manifest.webmanifest")
			.permitAll()
			.antMatchers("/sw.js")
			.permitAll()
			.antMatchers("/offline.html")
			.permitAll()
			.antMatchers("/icons/**")
			.permitAll()
			.antMatchers("/images/**")
			.permitAll()
			.antMatchers("/styles/**")
			.permitAll()
			.antMatchers("/h2-console/**")
			.permitAll()
			.requestMatchers(SecurityUtils::isFrameworkInternalRequest)
			.permitAll()
			.anyRequest()
			.authenticated();
	}

	// With or without commented in / out code, logout / login (vaadinServlet) issues persists and reconnect does not work
	//	@Override
	//	public void configure (WebSecurity web) {
	//		web
	//			.ignoring()
	//			.antMatchers(
	//				"/VAADIN/**",
	//				"/vaadinServlet/UIDL/**",
	//				"/vaadinServlet/HEARTBEAT/**",
	//				"/favicon.ico",
	//				"/robots.txt",
	//				"/manifest.webmanifest",
	//				"/sw.js",
	//				"/offline.html",
	//				"/icons/**",
	//				"/images/**",
	//				"/styles/**",
	//				"/h2-console/**");
	//	}

	@Autowired
	public void configureGlobal (AuthenticationManagerBuilder auth) {
		KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
		keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
		auth.authenticationProvider(keycloakAuthenticationProvider());
	}

	@Bean
	public RequestCache requestCache () {
		return new CustomRequestCache();
	}

	@Bean
	@Override
	protected SessionAuthenticationStrategy sessionAuthenticationStrategy () {
		return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
	}

	@Bean
	@Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
	public AccessToken accessToken () {
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
		return ((KeycloakSecurityContext) ((KeycloakAuthenticationToken) request.getUserPrincipal()).getCredentials()).getToken();
	}

	@Bean
	@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
	public KeycloakRestTemplate keycloakRestTemplate () {
		return new KeycloakRestTemplate(keycloakClientRequestFactory);
	}
}

And I continue receiving the error: “Server connection lost, trying to reconnect…”
Then, after a logout and login, the vaadinServlet is attached to the url and my URL becomes: http://localhost:8080/myapp/vaadinServlet/

My SecurityUtils class:



public final class SecurityUtils {

	private SecurityUtils () {
		// Util methods only
	}

	public static boolean isFrameworkInternalRequest (HttpServletRequest request) {
		final String parameterValue = request.getParameter(ApplicationConstants.REQUEST_TYPE_PARAMETER);
		final String servletPath = request.getServletPath();
		return (parameterValue != null && Stream
			.of(HandlerHelper.RequestType.values())
			.anyMatch(r -> r.getIdentifier().equalsIgnoreCase(parameterValue))) ||
			servletPath.contains("/actuator/");
	}

	public static boolean isUserLoggedIn () {
		return !SecurityContextHolder.getContext().getAuthentication().getPrincipal().equals("anonymousUser")
			&& !((KeycloakPrincipal) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getKeycloakSecurityContext().getIdToken().isExpired();
	}
	
	omitted code...
}

And this is my CustomRequestCache…


public class CustomRequestCache extends HttpSessionRequestCache {

	@Override
	public void saveRequest (HttpServletRequest request, HttpServletResponse response) {
		if (!SecurityUtils.isFrameworkInternalRequest(request) && !isAtmosphereTransport(request) && !isError(request)) {
			super.saveRequest(request, response);
		}
	}

	private boolean isAtmosphereTransport (HttpServletRequest request) {
		String parameter = request.getParameter("X-Atmosphere-Transport");
		return parameter != null && parameter.equalsIgnoreCase("close");
	}

	private boolean isError (HttpServletRequest request) {
		return request.getServletPath() != null && request.getServletPath().contains("error");
	}
}

What I’m missing?

Cheers.

Hi all,

I know I wrote a few minutes ago, but please believe me when I tell you that I have been working on this bug (Server connection lost, trying to reconnect… / Handshake failure, Unexpected Redirect 302) for 2 months. Finally, I was able to fix it.

Just for information, we use Vaadin 14.4.7, Spring Boot 2.3.4, Spring Boot Starter Security and keycloak 12.0.1. It was a mess at the beginning, configuring keycloak and vaadin. But at the end, with this configuration I was able to let it run together.
The other code that are not present here, has not been changed.



	@Override
	protected void configure (HttpSecurity http) throws Exception {
		http
			.csrf()
			.disable()
			.anonymous()
			.disable()
			.requestCache()
			.requestCache(requestCache())
			.and()
			.sessionManagement()
			.sessionAuthenticationStrategy(sessionAuthenticationStrategy())
			.and()
			.addFilterBefore(keycloakPreAuthActionsFilter(), LogoutFilter.class)
			.addFilterBefore(keycloakAuthenticationProcessingFilter(), LogoutFilter.class)
			.addFilterAfter(keycloakSecurityContextRequestFilter(), SecurityContextHolderAwareRequestFilter.class)
			.addFilterAfter(keycloakAuthenticatedActionsRequestFilter(), KeycloakSecurityContextRequestFilter.class)
			.exceptionHandling()
			.authenticationEntryPoint(authenticationEntryPoint())
			.and()
			.logout()
			.addLogoutHandler(keycloakLogoutHandler)
			.logoutUrl("/sso/logout")
			.logoutSuccessUrl("/")
			.and()
			.authorizeRequests()
			.requestMatchers(SecurityUtils::isFrameworkInternalRequest)
			.permitAll()
			.anyRequest()
			.authenticated();
	}

	@Override
	public void configure (WebSecurity web) {
		web
			.ignoring()
			.antMatchers(
				"/VAADIN/**",
				"/vaadinServlet/**",
				"/vaadinServlet/UIDL/**",
				"/vaadinServlet/HEARTBEAT/**",
				"/favicon.ico",
				"/robots.txt",
				"/manifest.webmanifest",
				"/sw.js",
				"/offline.html",
				"/icons/**",
				"/images/**",
				"/styles/**",
				"/h2-console/**");
	}

I commented in the configure (WebSecurity web) method that holds all ignoring paths for the authentication and added /vaadinServlet/** to it. Then I removed from the method configure (HttpSecurity http) the whole stack of the antMatcher().permitAll() that I have set in the configure (WebSecurity web) method.

In keycloak I have enabled the Service Accounts. See the attachment. However, I have no idea if this also helped to fix the error. :-).

That’s it.

Regarding the /vaadinServlet addition to the path after a re-login, I have to test if with this fix this issue also has been resolved.
For the moment on the local environment it seems like that, But I have to test it on our test environment. I will keep you up to date.

I hope I could help someone with this experience.

Best Regards
Simone
18535671.png