java – Spring Security blocks POST requests despite settings

Question:

I'm developing a REST API based on Spring Boot ( spring-boot-starter-web ) where I use Spring Security ( spring-security-core and spring-security-config ) to configure the protection of different endpoints .

Authentication is based on a local database where users with two different roles are registered: ADMIN and USER . USER should be able to GET all API points and POST to endpoints based on routeA . ADMIN should be able to do the same as USER and still POST and DELETE endpoints based on routeB .

But the behavior I'm having is that I can GET to any endpoint but POST results in HTTP 403 Forbidden either with users who have the ADMIN or USER role , which is not expected based on my SecurityConfiguration .

Any idea what I'm missing?


SecurityConfiguration.java

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    private static final Logger logger = LoggerFactory.getLogger(SecurityConfiguration.class);

    @Autowired
    private RESTAuthenticationEntryPoint authenticationEntryPoint;

    @Autowired
    private DataSource dataSource;

    @Override
    public void configure(AuthenticationManagerBuilder builder) throws Exception {
        logger.info("Using database as the authentication provider.");
        builder.jdbcAuthentication().dataSource(dataSource).passwordEncoder(new BCryptPasswordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().
            authorizeRequests().antMatchers(HttpMethod.GET, "/**").hasAnyRole("ADMIN", "USER")
                               .antMatchers(HttpMethod.POST, "/routeA/*").hasAnyRole("ADMIN", "USER")
                               .antMatchers(HttpMethod.POST, "/routeB/*").hasRole("ADMIN")
                               .antMatchers(HttpMethod.DELETE, "/routeB/*").hasRole("ADMIN").and().
            requestCache().requestCache(new NullRequestCache()).and().
            httpBasic().authenticationEntryPoint(authenticationEntryPoint).and().
            cors();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        final CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH"));
        configuration.setAllowCredentials(true);
        configuration.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "Content-Type"));
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

RouteBController .java

@RestController
public class RouteBController {

    static final Logger logger = LoggerFactory.getLogger(RouteBController.class);

    public RouteBController() { }

    @RequestMapping(value = "routeB", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.GET)
    public String getStuff() {
        return "Got a hello world!";
    }

    @RequestMapping(value = "routeB", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.POST)
    public String postStuff() {
        return "Posted a hello world!";
    }

}

RESTAuthenticationEntryPoint.java

@Component
public class RESTAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {

    @Override
    public void afterPropertiesSet() throws Exception {
        setRealmName("AppNameHere");
        super.afterPropertiesSet();
    }
}

Answer:

You must disable CSRF:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        // ...
        .csrf().disable();
}
Scroll to Top