1

I have a Spring Boot app where I have custom pre authentication filter. I want to ignore security for health URL but I am not able to do it. Below is my configuration.

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(1000)
public class UserSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> userDetailsService;

    @Autowired
    private IUserIdentityService iUserIdentityService;

    @Value("${spring.profiles.active}")
    private String profileType;
    
    @Autowired
    @Qualifier("publicEndpoints")
    private Map<String, String> publicEndpoints;
    
    @Autowired
    private GenericDataService genericDataService;

    @Bean(name = "preAuthProvider")
    PreAuthenticatedAuthenticationProvider preauthAuthProvider() {
        PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
        provider.setPreAuthenticatedUserDetailsService(userDetailsService);
        return provider;
    }

    @Bean
    AppPreAuthenticatedProcessingFilter appPreAuthenticatedProcessingFilter() throws Exception {
        appPreAuthenticatedProcessingFilter filter = new appPreAuthenticatedProcessingFilter(iUserIdentityService, genericDataService);
        filter.setAuthenticationManager(super.authenticationManagerBean());
        filter.setContinueFilterChainOnUnsuccessfulAuthentication(false);
        filter.setCheckForPrincipalChanges(true);
        return filter;
    }

    /**
     * Uses JEE pre-authentication filter, that assumes that the user has been
     * pre-authenticated into the container.
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/health/e2e").permitAll()
                .and()
            .addFilter(appPreAuthenticatedProcessingFilter())
            .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .authenticationProvider(preauthAuthProvider())
            .csrf()
                .csrfTokenRepository(this.csrfTokenRepository())
                .and()
            .httpBasic().disable();
        // Disabling the CSRF implementation, if "csrf.disabled" property set to "true"
        // in System Properties.
        if (!StringUtils.isEmpty(profileType) && profileType.equals("local")) {
            http.csrf().disable();
        }
    }
    
    /**
     * Method to ignore web security for urls
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web
           .ignoring()
               .antMatchers("*/api-docs", "/configuration/ui", "/swagger-resources/**", "/configuration/**", "/swagger-ui.html", "/webjars/**", "/health/e2e", "*/health/e2e", "**/health/e2e");

    }

    /**
     * Method to to return CsrfTokenRepository
     */
    private CsrfTokenRepository csrfTokenRepository() {
        CookieCsrfTokenRepository tokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse();
        tokenRepository.setCookiePath("/");
        return tokenRepository;
    }

}

Custom authentication filter looks like

@Slf4j
public class AppPreAuthenticatedProcessingFilter extends AbstractPreAuthenticatedProcessingFilter {

    private IUserIdentityService iUserIdentityService;
    
    private GenericDataService genericDataService;

    public AppPreAuthenticatedProcessingFilter(IUserIdentityService iUserIdentityService, GenericDataService genericDataService) {
        this.iUserIdentityService = iUserIdentityService;
        this.genericDataService = genericDataService;
    }

    @Override
    protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
        RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request));
        return iUserIdentityService.getUserName();
    }

    @Override
    protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
        return AppConst.DEFAULT_CREDENTIAL;
    }
}

I am not sure why /health/e2e is secured?

P.S. I tried removing @Bean from pre auth filter but in that case, filter never gets called for any request.

dur
  • 15,689
  • 25
  • 79
  • 125
Aditya Ekbote
  • 1,493
  • 3
  • 15
  • 29
  • Does this answer your question? [Spring Security add filter to all Endpoint EXCEPT one](https://stackoverflow.com/questions/52039388/spring-security-add-filter-to-all-endpoint-except-one) – madteapot Mar 25 '21 at 11:25
  • No this does not. I tried with FilterRegistrationBean approach as well. – Aditya Ekbote Mar 25 '21 at 11:28
  • @AdityaEkbote *That what I am wondering why execution flow goes inside filter for permitted urls* That's as it should work. All added filters are applied for all URLs, because your configuration is applied to all URLs, you didn't restrict the URLs for your configuration. – dur Mar 25 '21 at 13:17
  • @AdityaEkbote To understand the difference between restricting security filter chain and restricting authorization, see also https://stackoverflow.com/questions/35890540/when-to-use-spring-securitys-antmatcher – dur Mar 25 '21 at 13:27

1 Answers1

1

The problem is two fold

  1. Your security setup contains an error
  2. The filter is added to the regular filter bean as well.

With your current security setup the AppPreAuthenticatedProcessingFilter is added only to the /health/e2d URL. Your attempt to fix something has actually broken things instead.

Your configuration should be something along the lines of

http.authorizeRequests().anyRequest().authenticated()
    .and().httpBasic()
    .and().authenticationProvider(preauthAuthProvider())
    .csrf().csrfTokenRepository(this.csrfTokenRepository())
    .and().addFilterBefore(appPreAuthenticatedProcessingFilter(), UsernamePasswordAuthenticationFilter.class);

    // in System Properties.
if (!StringUtils.isEmpty(profileType) && profileType.equals("local")) {
    http.csrf().disable();
}

Spring Boot will by default register an javax.servlet.Filter in the normal filter chain, to disable this you need to add a FilterRegistrationBean to disable this.

@Bean
public FilterRegistrationBean<AppPreAuthenticatedProcessingFilter> preAuthenticationFilterRegistrationBean(AppPreAuthenticatedProcessingFilter filter) {
  FilterRegistrationBean<AppPreAuthenticatedProcessingFilter> frb = new FilterRegistrationBean<>(filter);
  frb.setEnabled(false);
  return frb;
}
M. Deinum
  • 115,695
  • 22
  • 220
  • 224