30 votes

Spring Security bloque les requêtes POST malgré SecurityConfig

Je suis en train de développer une API REST basée sur Spring Boot ( spring-boot-starter-web ) où j'utilise Spring Security ( spring-security-core e spring-security-config ) pour protéger les différents points d'accès.

L'authentification est effectuée en utilisant une base de données locale qui contient des utilisateurs avec deux ensembles de rôles différents : ADMIN et USER . USER devrait être en mesure de GET tous les points d'accès à l'API et POST aux points de terminaison basés sur routeA . ADMIN devrait être en mesure de faire la même chose que USER plus POST et DELETE vers des points de terminaison basés sur `routeB'.

Cependant, le comportement que j'obtiens est que je peux faire GET à n'importe quel point d'accès mais POST les demandes retournent toujours HTTP 403 Forbidden pour chaque type d'utilisateur - ADMIN y USER - ce qui n'est pas ce à quoi je m'attendais en me basant sur mon SecurityConfiguration .

Une idée de ce que j'ai manqué ?


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();
    }
}

40voto

Tiago Leite Points 410

Il y avait 2 numéros dans SecurityConfiguration.java qui l'a fait mal se comporter.

Bien que le 403 Forbidden ne contenait pas de message indiquant la raison de l'échec (voir l'exemple ci-dessous), il s'avère que c'était dû au fait que l'on avait CSRF activé. En le désactivant, on peut POST y DELETE les demandes à traiter.

{
    "timestamp": "2018-06-26T09:17:19.672+0000",
    "status": 403,
    "error": "Forbidden",
    "message": "Forbidden",
    "path": "/routeB"
}

De même, l'expression utilisée dans antMatched(HttpMethod, String) para RouteB était incorrecte car /routeB/* s'attend à ce qu'il ait quelque chose après / . La configuration correcte est /routeB/** car plus de chemins peut être présent ( ou non ).


El corrigé SecurityConfiguration.java est

@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().and().
        csrf().disable();
}

Source : StackOverflow en portugais

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X