Search code examples
springspring-bootoauth-2.0basic-authenticationspring-boot-actuator

Separate authentication provider in Spring Boot 2 for Actuator and custom API endpoints


We have a spring boot application (spring boot version 2.1.4) which exposes a Rest API secured with OAuth2.
We need to expose also the health-check (Actuator) endpoints provided by Spring Boot to a legacy monitoring tool which supports only basic authentication.
However, the Actuator, since Spring Boot 2, shares the security config with the regular App security rules, so the only options I can see so far is to protected it with Oauth2 or to leave it not protected (.permitAll()).

I try to use separate WebSecurityConfigurerAdapter(s) to setup the httpBasic authentication provider for the actuator endpoints and oauth2 for the API endpoints, playing around with the execution @Order but the two authentication providers seems to be mutually exclusive.

Bellow the two WebSecurityConfigurerAdapter implementations:

  1. For the Actuator :
@Configuration
@Order(1)
public class ActuatorConfigurationAdapter extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("admin").password("password")
                .roles("ADMIN", "USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
//                requestMatchers(EndpointRequest.to(MetricsEndpoint.class))
        .antMatchers("/actuator/**")
                .hasAnyRole("ADMIN","USER").and().authorizeRequests().and().httpBasic();
    }
}
  1. For the API :
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@Order(10)
public class SecurityConfiguration2 extends WebSecurityConfigurerAdapter {
    @Autowired
    private CorsFilter corsFilter;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .cors()
        .and()
            .addFilterBefore(corsFilter, CsrfFilter.class)
            .exceptionHandling()
            .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
        .and()
            .headers()
        .and()
            .authorizeRequests()
            .antMatchers("/v2/api-docs").permitAll()
            .antMatchers("/authenticate").permitAll()
            .antMatchers("/customer/**").hasAuthority("MARKETING")
            .anyRequest().authenticated()
        .and()
            .oauth2Login() // generates the /login page
            .successHandler(successHandler())
            ...
    }

Any tips how can I make this work much appreciated.


Solution

  • i have the same usecase and this works for me:

    @EnableWebSecurity()
    @EnableGlobalMethodSecurity(
        securedEnabled = true,
        prePostEnabled = true
    )
    public class WebSecurityConfig {
    
    
       @Configuration
       @Order(3)
       public static class ActuatorSecurityAdapter extends WebSecurityConfigurerAdapter {
    
       @Autowired
       private AppProperties prop;
    
       @Override
       protected void configure(HttpSecurity http) throws Exception {
        http
            .requestMatcher(EndpointRequest.toAnyEndpoint())
            .authorizeRequests()
            .requestMatchers(EndpointRequest.to("info","env")).authenticated()
            .requestMatchers(EndpointRequest.to("health")).permitAll()
            .anyRequest().hasRole("ADMIN") // Any other endpoint
            .and()
            .httpBasic();
      }
    
      @Bean
      public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
      }
    
      @Bean
      @Override
      public UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername(prop.getManagement().getUsername())
         .password(prop.getManagement().getPassword()).roles("ACTUATOR").build());
        return manager;
        }
      }
    
    
      [....]
    
      @Configuration
      @Order(1)
      public class OAuthSecurityConfig extends WebSecurityConfigurerAdapter {
    
      [...]
    }
    

    perhaps it helps :)