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.