Describe the bug
Context: Spring Boot application with two or more REST endpoints that mapped to the same path but different HTTP methods, permissions for endpoints are different. It is possible that endpoint's response may be wrong ("access denied") if previously another endpoint was called (same path, another HTTP method).
To Reproduce
Example application: https://github.com/astr2k/spring-security-issue-demo
May be reproduced using JUnit tests and Spring's MockMvc, Postman, etc.
Application has two REST endpoints, one mapped to GET method, another to PUT, paths are the same.
Permissions configuration: PUT endpoint may be executed only by user having "ADMIN" role, GET endpoint is permitted for all.
After application starts, call all endpoints as anonymous user, do not login.
First call GET endpoint - returns OK (expected).
Call PUT endpoint - returns Unauthorized (expected).
Call again GET endpoint - now returns Unauthorized, same response as in previous call.
Expected behavior
Calling GET endpoint should not return Unauthorized status as it is permitted for all.
Possible root cause
Traced the execution flow in debugger and, as of my understanding, the root cause is flawed logic in DefaultSavedRequest class when matching current request to saved (cached) request:
https://github.com/spring-projects/spring-security/blob/1631cac1506d7fdda1f3864357075af4965a78cd/web/src/main/java/org/springframework/security/web/savedrequest/DefaultSavedRequest.java#L235
if (!"GET".equals(request.getMethod()) && "GET".equals(this.method)) {
// A save GET should not match an incoming non-GET method
return false;
}
Means that in most cases requests with different HTTP methods will be considered the same.
Environment
Java 17, Spring Boot 3.0.6, Spring Security 6.0.3. Reproducible with earlier versions too, also Spring Boot 2.x.x