23

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.

1
  • 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: stackoverflow.com/questions/54657163/… Commented Feb 15, 2019 at 19:32

2 Answers 2

21

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.

Sign up to request clarification or add additional context in comments.

2 Comments

the last link for "spring security: make restful api.." is broken.
what I have to change if I need only jwt for one endpoint and only x509 for the other ?
4

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();
    }

2 Comments

This is not working for me. The second filter chain is not running.. If I change the @Order to the other it runs so the filter is correct. Any idea why it might not be running the second filter?
Found it. It was the .antMatcher("/api/**") in the first one that was missing

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.