Home > Mobile >  SecurityFilterChain .anyRequest().permitAll() doesn't allow POST requests
SecurityFilterChain .anyRequest().permitAll() doesn't allow POST requests

Time:06-04

Using Spring Boot 2.7 (Spring Security 5.7.1) and trying to configure an API as a resource server and OAuth2 client I find a behavior I don't get to understand:

@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests((authorize) -> authorize
                        .mvcMatchers("/swagger-ui/**", "/api-docs/**").permitAll()
                        .anyRequest().permitAll())

                // register OAuth2 resource server
                .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)

                // register OAuth2 client
                .oauth2Client(withDefaults());

        return http.build();
    }
}

Checking the logs, all this filters apply

o.s.s.web.DefaultSecurityFilterChain     : Will secure any request with 

org.springframework.security.web.session.DisableEncodeUrlFilter@320ca97c,
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@3c592c0c,
org.springframework.security.web.context.SecurityContextPersistenceFilter@2b33e616,
org.springframework.security.web.header.HeaderWriterFilter@2e9bff08,
org.springframework.security.web.csrf.CsrfFilter@7926d092,
org.springframework.security.web.authentication.logout.LogoutFilter@37227aa7,
org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter@6f18445b,
org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter@42af2977,
org.springframework.security.web.savedrequest.RequestCacheAwareFilter@79e3f444, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@1252d480,
org.springframework.security.web.authentication.AnonymousAuthenticationFilter@3979c6e8,
org.springframework.security.oauth2.client.web.OAuth2AuthorizationCodeGrantFilter@19faa9dc,
org.springframework.security.web.session.SessionManagementFilter@7d3b4646,
org.springframework.security.web.access.ExceptionTranslationFilter@6cb2d5ea,

So far, this configuration works as expected in the other APIs I'm protecting. However, in this particular one, AND not having protected any endpoint I see that:

I can access any GET endpoint but any POST endpoint returns a 403 FORBIDDEN. However, I can access them if I add a token to the request EVEN if its an expired token

This alone I can't understand as .anyRequest().permitAll() should unprotect anything, if I'm not wrong.

If I comment out the line configuring the oauth2 ResourceServer

`// .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)`

this filter dissapears

org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter

And can't use POST endpoints anymore, even with the expired token

Logically, I want the API to be oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt) so

How it is I can't access POST endpoints when using .anyRequest().permitAll())?

DISCLAIMER: I know it makes no sense to declare the API as resource server if all endpoints must be public. Endpoints will be accessed by Discord callbacks and I have to figure out if I can protect them with OAuth

EDIT:

server.servlet.context-path = /api

Controller

@RestController
@RequestMapping("/slack")
public class SlackBotController {
    @PostMapping("/test")
    public String test(@RequestBody String a) {
        return a;
    }

    @GetMapping("/test")
    public String testGet() {
        return "OK";
    }
}

Request

GET/POST http://localhost:8081/api/slack/test

Request headers

User-Agent: PostmanRuntime/7.29.0
Accept: */*
Postman-Token: f20ba7a6-26e5-47c4-a827-0596afec27b8
Host: localhost:8081
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 3
Cookie: JSESSIONID=D1C2B2668DC130C63DDE03F30574ED5F; JSESSIONID=823D79956CFBF14F3C77C96E29F4131C

Response headers

X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: application/json
Transfer-Encoding: chunked
Date: Fri, 03 Jun 2022 12:03:00 GMT
Keep-Alive: timeout=60
Connection: keep-alive

CodePudding user response:

The reason why the POST endpoint or the POST returns a 403 FORBIDDEN because the CSRF protection is enabled by default in spring.

That means that every modifying request (POST, PUT, DELETE, PATCH) requires a CSRF token. Otherwise the request gets denied to prevent CSRF attacks.

To disable the CSRF protection:

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

CodePudding user response:

The problem here is the CSRF protection. When you use http.oauth2ResourceServer() Spring Security configures CSRF to ignore requests that contains the header Authorization: Bearer whatever, note that it has to contain the Bearer prefix.

In the request sample that you shared, you are not including the Authorization header.

Take a look at the code in Spring Security.

  • Related