VelNaga
VelNaga

Reputation: 3953

Issue with having multiple WebSecurityConfigurerAdapter in spring-boot

I am using spring-boot-1.5.10 and spring-boot-starter-security. In my microservice, I am exposing API's to the external world and internal microservices. so I would like to 2-kind of security. one for external calls and other for internal calls.

I have referred this URL and tried to implement multiple security adapters in my application. But no luck it's always picking the internal one instead of external one,

Please find the security adapter for your reference,

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired(required = false)
    ServiceWebSecurityConfigurer serviceWebSecurityConfigurer;

//    @Override
//    public void configure(WebSecurity web) throws Exception {
//        web
//                .ignoring()
//                .antMatchers(HttpMethod.PUT,"/v1/emp/**")
//                .antMatchers(HttpMethod.DELETE,"/v1/emp/**");
//    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authenticationProvider(new ExternalApiAuthenticationProvider())
                .securityContext()
                .securityContextRepository(new ExternalApiSecurityContextRepository())
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(new ApiAuthenticationEntrypoint())
                .and()
                .httpBasic().disable()
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/v1/**").fullyAuthenticated();
        if(serviceWebSecurityConfigurer != null)
            serviceWebSecurityConfigurer.configure(http);
        http.authenticationProvider(new InternalApiAuthenticationProvider())
            .securityContext()
            .securityContextRepository(new InternalApiSecurityContextRepository())
            .and()
            .exceptionHandling()
            .authenticationEntryPoint(new ApiAuthenticationEntrypoint())
            .and()
            .httpBasic().disable()
            .csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .authorizeRequests()
            .antMatchers(HttpMethod.PUT,"/v1/emp/**").fullyAuthenticated()
            .antMatchers(HttpMethod.DELETE,"/v1/emp/**").fullyAuthenticated();
    }
}

It always picks the "InternalApiSecurityContextRepository" even the external API's using internal security. It seems the later is overriding the former.

UPDATE-1(as per Gaurav Srivastav answer)

External API call security adapter :

@EnableWebSecurity
public class WebSecurityConfig {

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

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authenticationProvider(new InternalApiAuthenticationProvider())
                .securityContext()
                .securityContextRepository(new InternalApiSecurityContextRepository())
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(new InternalApiAuthenticationEntrypoint())
                .and()
                .httpBasic().disable()
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers(HttpMethod.PUT,"/v1/emp/**").fullyAuthenticated()
                .antMatchers(HttpMethod.DELETE,"/v1/emp/**").fullyAuthenticated();
        }
    }

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

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authenticationProvider(new ExternalApiAuthenticationProvider())
                .securityContext()
                .securityContextRepository(new ExternalApiSecurityContextRepository())
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(new ApiAuthenticationEntrypoint())
                .and()
                .httpBasic().disable()
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/v1/**").fullyAuthenticated();
        }
    }
}

It works for External(Since the order is 1) but for internal we are getting the following exception and it is using the External configuration security context,

An internal server error occurred.Message:An Authentication object was not found in the SecurityContext

I think the problem here is, we cannot use 2-security context it seems.Is there anyway to use different security context?

Any hint would be really appreciable to solve the issue. Thanks in Advance.

Upvotes: 3

Views: 7778

Answers (1)

Gaurav Srivastav
Gaurav Srivastav

Reputation: 2551

You have define more than one configuration and specify the order using @Order annotation.

Internal Configuration with its own authentication provider and url pattern.

@EnableWebSecurity
public class MultiHttpSecurityConfig {

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

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/internal/**")
                .authorizeRequests().anyRequest().hasRole("ADMIN")
                .and().httpBasic().authenticationEntryPoint(authenticationEntryPoint());
        }
    }

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

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/external/**")
                .authorizeRequests().anyRequest().hasRole("ADMIN")
                .and().httpBasic().authenticationEntryPoint(authenticationEntryPoint());
        }
    }

Get more detail through using below article. https://www.baeldung.com/spring-security-multiple-entry-points

Upvotes: 3

Related Questions