Reputation: 234
Controller
@GetMapping("/api/data")
String response(){
}
application.properties
server.servlet.context-path=/v1
Spring secuity
http.authorizeRequests().anyMatcher("/v1/**").authenicated()
Here authentication is not happening. I believe, spring-security is ignoring the context-path thats been configured in the application.properties. Why is spring-security ignoring the context path. How to fix this?
For the above image, I expected a 401 since the v1/** is supposed to be authorised
This is working fine,
http.authorizeRequests().anyMatcher("/**").authenicated()
Upvotes: 2
Views: 2969
Reputation: 940
In my case, I'm working with Spring Security 6 + Spring Boot 3. In the application.yml
I set this configuration to set the root path for the API:
spring.mvc.servlet.path=/api/v1
I have a very simple class to check CORS policy before starting to work with anything else in the API, which is:
@Controller
public class AliveController {
@GetMapping("/alive")
public ResponseEntity<Object> getAlive() {
return ResponseEntity.status(200).body("Everything OK!");
}
}
And in my class SecurityConfiguration
, which is annotated with @Configuration
and @EnableWebSecurity
, I put these two methods annotated with @Bean
:
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf().disable()
.cors(Customizer.withDefaults())
.headers().frameOptions().disable().and()
.authorizeHttpRequests()
.requestMatchers("/alive").permitAll()
.anyRequest().authenticated().and()
.securityMatcher("/**")
.build();
}
Note that I put this /alive
endpoint to bypass authentication requirement, also I referenced it without root path (/api/v1
). Also, note that I have in the cors method a parameter Customizer.withDefaults()
, that is invoking the default method to configure cors named in Spring by default as corsConfigurationSource()
. So, Spring will search for a method with that name and I named that way. Then, I set my own ruled cors in that method in the same class, something like:
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
// corsOrigins, allowedHeaders, allowedMethods, exposedHeaders
// are String arrays set as private final in the class
config.setAllowedOrigins(List.of(corsOrigins));
config.setAllowedHeaders(List.of(allowedHeaders));
config.setAllowedMethods(List.of(allowedMethods));
config.setExposedHeaders(List.of(exposedHeaders));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
Also, I'm noticed something about paths (something that's got me all over the place). If you set in the spring.mvc.servlet.path
property the value /api/v1
, cors policy supposes you'll set that policy within /api/v1, so you don't need to set again in the rules in securityMatcher("/**")
or in source.registerCorsConfiguration("/**", config);
. The policy will get those /**
considering there's a root preceding /api/v1
.
Trying in the terminal with cors origin http://localhost:3000
...
~ http get :8080/api/alive Origin:http://localhost:3000
HTTP/1.1 200
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Expose-Headers: Allow, X-Get-Header
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Connection: keep-alive
Content-Length: 14
Content-Type: text/plain;charset=UTF-8
Date: Sat, 11 Mar 2023 08:07:11 GMT
Expires: 0
Keep-Alive: timeout=60
Pragma: no-cache
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Response:
Everything OK!
Trying with another port...
~ http get :8080/api/alive Origin:http://localhost:3001
HTTP/1.1 403
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Connection: keep-alive
Date: Sat, 11 Mar 2023 08:09:14 GMT
Expires: 0
Keep-Alive: timeout=60
Pragma: no-cache
Transfer-Encoding: chunked
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Response:
Invalid CORS request
Please, be aware of the List.of(corsOrigins)
, List.of(allowedHeaders)
, List.of(allowedMethods)
and List.of(exposedHeaders)
, which are Lists coming from something like:
private final String corsOrigins = "http://localhost:3000";
private final String[] allowedMethods = {"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"};
private final String[] allowedHeaders = {"Authorization", "Accept", "Accept-Language", "content-type", "Requestor-Type", "X-Requested-With"};
private final String[] exposedHeaders = {"Allow", "X-Get-Header"};
It's been hours of my life I won't get back with this thing hehe.
Hope it helps.
Upvotes: 1
Reputation: 667
Turn ON the debug for Spring Security, then you would understand what's happening.
@EnableWebSecurity(debug = true)
When,
server.servlet.context-path=/v1
Generated Request:
Request received for GET '/api/data':
servletPath:/api/data
pathInfo:null
When,
spring.mvc.servlet.path=/v1
Generated Request:
Request received for GET '/v1/api/data':
servletPath:/v1
pathInfo:/api/data
Go with servlet-path for what you are trying to implement...
Upvotes: 6