Spring Webflux application multiple SecurityWebFilterChain for the same endpoint?

Viewed 23

My Spring Webflux application provides multiple authentication methods for the APIs, the user either presents a JWT token or he presents a userid and password. I understand that each authentication method is a separate SecurityWebFilterChain. In my security config I defined 2 Beans, one for basic auth and one for JWT. Setting up each one for different endpoints works fine using a SecurityMatcher, but how do I setup both for the same endpoint. I want either basic auth or JWT token to authenticate for a specific endpoint. All my attempts result in the first authentication method failing and returning a 401 unauthorized without attempting to try the second method. How do I get it not to fail but to try the second SecurityWebFilterChain bean?

Here is the code from my security config

@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class SecurityConfig {

  @Autowired private SecurityContextRepository securityContextRepository;

@Bean
  SecurityWebFilterChain webHttpSecurity(
          ServerHttpSecurity http, BasicAuthenticationManager authenticationManager) {
    http.securityMatcher(new PathPatternParserServerWebExchangeMatcher("/api/something/**"))
            .authenticationManager(authenticationManager)
            .authorizeExchange((exchanges) -> exchanges.anyExchange().authenticated())
            .httpBasic()
            .and()
            .csrf()
            .disable();
    return http.build();
  }

  @Bean
  SecurityWebFilterChain springWebFilterChain(
      ServerHttpSecurity http, AuthenticationManager authenticationManager) {
    String[] patterns =
        new String[] {
          "/v2/api-docs",
          "/configuration/ui",
          "/swagger-resources/**",
          "/configuration/**",
          "/swagger-ui/**",
          "/swagger-ui.html",
          "/v3/api-docs/**",
          "/webjars/**",
        };
    return http.cors()
        .disable()
        .exceptionHandling()
        .authenticationEntryPoint(
            (swe, e) ->
                Mono.fromRunnable(() -> swe.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED)))
        .accessDeniedHandler(
            (swe, e) ->
                Mono.fromRunnable(() -> swe.getResponse().setStatusCode(HttpStatus.FORBIDDEN)))
        .and()
        .csrf()
        .disable()
        .authenticationManager(authenticationManager)
        .securityContextRepository(securityContextRepository)
        .authorizeExchange()
        .pathMatchers(patterns)
        .permitAll()
        .pathMatchers(HttpMethod.OPTIONS)
        .permitAll()
        .anyExchange()
        .authenticated()
        .and()
        .build();
  }

The first Bean sets up basic auth for one specific endpoint using a custom authentication manager which veruifies the userid and password, the second bean sets up JWT auth for all other endpoints (with a custom AuthenticationManager that verifies the token etc.) except those that are excluded. Lets say I have the following endpoints

  1. /api/something
  2. /api/whatever
  3. .....

endpoint 1 I want to authenticate with either basic auth or JWT endpoint 2,3 ,n I want only JWT As I have it now endpoint 1 is using only basicAuth and all other endpoints use JWT. How can I add JWT to endpoint 1 as well?

0 Answers
Related