I am trying to adopt Spring Boot Security for Vaadin Flow with vaadin-secur

I am trying to adopt Spring Boot Security for Vaadin Flow with vaadin-security-spring-boot-starter. Java 11, Vaadin 23, spring boot 2.6.4, vaadin-security-spring-boot-starter 3.0.2 . After login form submit the KeycloakAuthenticationProvider get the request is class class can support UsernamePasswordAuthenticationToken (of cause not, because need KeycloakAuthenticationToken). Reason looks like incorrect filters order.
The stack is attached.
Any ideas are welcome why it goes in this way.


supports:65, KeycloakAuthenticationProvider (org.keycloak.adapters.springsecurity.authentication)

authenticate:174, ProviderManager (org.springframework.security.authentication)
authenticate:201, ProviderManager (org.springframework.security.authentication)
attemptAuthentication:85, UsernamePasswordAuthenticationFilter (org.springframework.security.web.authentication)
doFilter:223, AbstractAuthenticationProcessingFilter (org.springframework.security.web.authentication)
doFilter:213, AbstractAuthenticationProcessingFilter (org.springframework.security.web.authentication)
doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilter:103, LogoutFilter (org.springframework.security.web.authentication.logout)
doFilter:89, LogoutFilter (org.springframework.security.web.authentication.logout)
doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilter:219, AbstractAuthenticationProcessingFilter (org.springframework.security.web.authentication)
doFilter:213, AbstractAuthenticationProcessingFilter (org.springframework.security.web.authentication)
doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)

doFilter:96, KeycloakPreAuthActionsFilter (org.keycloak.adapters.springsecurity.filter)

doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilterInternal:117, CsrfFilter (org.springframework.security.web.csrf)
doFilter:117, OncePerRequestFilter (org.springframework.web.filter)
doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doHeadersAfter:90, HeaderWriterFilter (org.springframework.security.web.header)
doFilterInternal:75, HeaderWriterFilter (org.springframework.security.web.header)
doFilter:117, OncePerRequestFilter (org.springframework.web.filter)
doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilter:110, SecurityContextPersistenceFilter (org.springframework.security.web.context)
doFilter:80, SecurityContextPersistenceFilter (org.springframework.security.web.context)
doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilterInternal:55, WebAsyncManagerIntegrationFilter (org.springframework.security.web.context.request.async)
doFilter:117, OncePerRequestFilter (org.springframework.web.filter)
doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilterInternal:211, FilterChainProxy (org.springframework.security.web)
doFilter:183, FilterChainProxy (org.springframework.security.web)
invokeDelegate:354, DelegatingFilterProxy (org.springframework.web.filter)
doFilter:267, DelegatingFilterProxy (org.springframework.web.filter)
internalDoFilter:189, ApplicationFilterChain (org.apache.catalina.core)

Hard to say without seeing any code; especially the security configuration. But since you didn’t mention it: Did you take a look at the [Keycloak example in the demo application]
(https://gitlab.com/codecamp-de/vaadin-security-spring-demo/-/tree/keycloak)? It doesn’t use the latest versions, but it should still show how to integrate Keycloak.

Hi Patrick.

The code for adoption was taken from your demo project. Sec config provided below. The KeycloakSpringBootConfigResolver was moved into separate config file to avoid circular dependency.


@KeycloakConfiguration
public class WebSecurityConfig
  extends KeycloakWebSecurityConfigurerAdapter {

  @Bean
  public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
  }

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

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

  @Override
  protected void configure(HttpSecurity http)
    throws Exception
  {
    super.configure(http);

    new VaadinSecurityConfigurer().configure(http);

    http.requestMatchers() //
        .antMatchers("/sso/login", "/sso/logout");

    /*
     * Spring Boot's CSRF protection is no longer completely disabled by VaadinSecurityConfigurer,
     * only selectively for Vaadin-related requests.
     */
    // http.csrf().disable();
    // http.csrf().ignoringAntMatchers("/sso/logout");

    http.authorizeRequests();
  }

  @Bean
  public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher()
  {
    return new ServletListenerRegistrationBean<>(new HttpSessionEventPublisher());
  }

}

I don’t really use Keycloak (since testing my demo) so I don’t know if they have changed something in the meantime. That circular dependency you mentioned seems odd; not sure where that suddenly comes from.

Anyway, what is this login form you mentioned? If the UsernamePasswordAuthenticationFilter creates a UsernamePasswordAuthenticationToken and tries to authenticate it, that means someone sent a username and password to its URL; this seems wrong when you want to use Keycloak. The UsernamePasswordAuthenticationFilter shouldn’t be active in the first place when you want to use Keycloak for authentication. Maybe you forgot to set codecamp.vaadin.security.standard-auth.enabled = false?

The basic flow is like this: When the user isn’t authenticated yet, they are redirected to Keycloak (this is what the KeycloakRouteAccessDeniedHandler does). When the user is authenticated with Keycloak they are redirected back to your application, where the KeycloakAuthenticationProvider gets its KeycloakAuthenticationToken.