19

I want to check for different authentication methods for different endpoints. Methods i want to use are x509 and jwt. I need to use only x509 for certain endpoint and use JWT for all other requests.

Here's my web security configuration:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    @Configuration
    @Order(1)
    public static class ApiWebSecurityConfig extends WebSecurityConfigurerAdapter{

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .authorizeRequests()
                .antMatchers("/api/transaction/testf").authenticated().and()
                .x509()
                .subjectPrincipalRegex("CN=(.*?)(?:,|$)")
                .userDetailsService(new X509UserDetailsService())
                ;
        }
    }

    @Configuration
    @Order(2)
    public static class ApiTokenSecurityConfig extends WebSecurityConfigurerAdapter{

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                .antMatchers("/oauth/token", "/api/dealer/login").permitAll()
                .and()
                .authorizeRequests()
                .anyRequest()
                .authenticated()
                ;
        }

    }
}

This configuration only checks /api/transaction/testf endpoint for x509 certificate and allows all other endpoints to respond. I need other endpoints to return 503 without a jwt token.

Çağdaş Salur
  • 1,360
  • 3
  • 14
  • 24
  • For each filter chain, you must specify the ant pattern for that chain. `http.antMatcher` (not http.authorizeRequests as the first call) This post describes what you need: https://stackoverflow.com/questions/54657163/springsecurity-make-restful-api-basic-auth-authentication-possible-via-only-a-s/54658476#54658476 – Filip Hanik VMware Feb 15 '19 at 19:32

2 Answers2

19

You have two filter chains. Neither of them have an entry point pattern properly configured http.antMatcher. That means they are configured to use /** as their entry point pattern.

For example

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest().fullyAuthenticated()

is the same thing as saying:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .antMatcher("/**")
            .authorizeRequests()
                .anyRequest().fullyAuthenticated()

What we are saying here is

  1. http - the security filter chain
  2. http.antMatcher - the entry point to the security filter chain
  3. http.authorizeRequests - start of my endpoint access restrictions
  4. http.authorizeRequests.antMatchers - list of URLs with specific access

So what you need to do is change your @Order(1) filter chain to narrow down the pattern. For example: http.antMatcher("/api/transaction/**")

Your configuration will now look like


    @Configuration
    @Order(1)
    public static class ApiWebSecurityConfig extends WebSecurityConfigurerAdapter{

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .antMatcher("/api/transaction/**") //customized entry point
                .authorizeRequests()
                .antMatchers("/api/transaction/testf").authenticated().and()
                .x509()
                .subjectPrincipalRegex("CN=(.*?)(?:,|$)")
                .userDetailsService(new X509UserDetailsService())
                ;
        }
    }

    @Configuration
    @Order(2)
    public static class ApiTokenSecurityConfig extends WebSecurityConfigurerAdapter{

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .antMatcher("/**") //this is default
                .authorizeRequests()
                .antMatchers("/oauth/token", "/api/dealer/login").permitAll()
                .and()
                .authorizeRequests()
                .anyRequest()
                .authenticated()
                ;
        }

With your existing configuration the filter chain named ApiWebSecurityConfig will trap all calls. The other filter chain, ApiTokenSecurityConfig, is never used.

Tristan
  • 8,733
  • 7
  • 48
  • 96
Filip Hanik VMware
  • 1,484
  • 6
  • 8
3

Since WebSecurityConfigurerAdapter is @Deprecated, preferable use multiple SecurityFilterChain (see updated Multiple HttpSecurity):

@Bean
    @Order(1)                                                        
    public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
        http
            .antMatcher("/api/**")                                   
            .authorizeHttpRequests(authorize -> authorize
                .anyRequest().hasRole("ADMIN")
            )
            .httpBasic(withDefaults());
        return http.build();
    }

    @Bean                                                            
    public SecurityFilterChain formLoginFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(authorize -> authorize
                .anyRequest().authenticated()
            )
            .formLogin(withDefaults());
        return http.build();
    }
Grigory Kislin
  • 16,647
  • 10
  • 125
  • 197