How to avoid redirecting to login form for some URL with Spring Security?

Viewed 4495

This is the Spring Security configuration of my webapp

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .antMatchers("/", LOGIN, "/webjars/**").permitAll()
            .antMatchers(CONFIGURATION).hasAuthority(Authorities.AUTHORITY_SOLMAN72_EXPORT_ENABLED.getKey())
            .antMatchers("/api/**").hasAuthority(Authorities.AUTHORITY_SOLMAN72_EXPORT_ENABLED.getKey())
            .and()
        .formLogin()
            .loginPage(LOGIN)
            .and()
        .addFilterBefore(oAuth2ClientAuthenticationProcessingFilter, BasicAuthenticationFilter.class);
}

Currently the server is redirecting to the LOGIN page every request that does not have the right credentials.

I want to redirect to the LOGIN page only the unauthorized requests to CONFIGURATION, while the unauthorized requests to /api/** should answer with 403.

What's a good way of achieving that?

3 Answers

I went to implement dur's answer but noticed there's a ExceptionHandlingConfigurer.defaultAuthenticationEntryPointFor(...) (available from around Spring Security 3.2.x) which does effectively the same thing with much less dependent code:

http.exceptionHandling()
        .defaultAuthenticationEntryPointFor(new Http403ForbiddenEntryPoint(), new AntPathRequestMatcher("/api/**"));

Moreover, I noticed specifying any defaultAuthenticationEntryPointFor() sets the first up as the default entry point.

By default, FormLoginConfigurer, OAuth2LoginConfigurer, Saml2LoginConfigurer, etc. adds their own during SecurityConfigurer.init() and, unless we've specified one, the first among those becomes the default entry point.

This may or may not be useful, but because the AuthenticationEntryPoint provided by FormLoginConfigurer, OAuth2LoginConfigurer, Saml2LoginConfigurer, etc. avoids requests containing the header X-Requested-With: XMLHttpRequest, the entry point we've specified with defaultAuthenticationEntryPointFor() will end up being used for AJAX, regardless of what we've specified for the request matcher argument.

Related