Reputation: 1
I have problems implementing CORS in my project. Maybe someone here can help me. Problem: I receive the response "Invalid CORS Request" with my implementation of CORS.
What does my implementation look like? This is my SecurityFilterChain:
@Bean
public SecurityFilterChain oidcFilterChain(final HttpSecurity http) throws Exception {
return http
.cors(withDefaults())
.securityMatcher(new OrRequestMatcher(
new AntPathRequestMatcher(ApplicationConfig.BASE_PATH + "/**")))
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated())
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
.build();
}
and this is my corsConfigurationSource():
@Bean
public UrlBasedCorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// Create a new CORS configuration
CorsConfiguration config = new CorsConfiguration() {
{
setAllowedMethods(List.of(
HttpMethod.GET.name(),
HttpMethod.HEAD.name(),
HttpMethod.POST.name(),
HttpMethod.PUT.name(),
HttpMethod.DELETE.name(),
HttpMethod.OPTIONS.name()));
}
// Check if the request origin is allowed
@Override
public String checkOrigin(String requestOrigin) {
if (requestOrigin == null || requestOrigin.isEmpty()) {
return null;
}
String originToCheck = trimTrailingSlash(requestOrigin);
try {
// Get the current Jwt user
Jwt jwtUser = SecurityContextUtil.getCurrentUser();
// Get the allowed origins from the Jwt user
List<String> allowedOrigins = jwtUser.getClaimAsStringList(ALLOWED_ORIGINS);
if (allowedOrigins != null) {
for (String allowedOrigin : allowedOrigins) {
if (originToCheck.equalsIgnoreCase(trimTrailingSlash(allowedOrigin))) {
return requestOrigin;
}
}
}
} catch (SecurityException e) {
log.error("SecurityException in CORS Configuration: {}", e.getMessage());
}
// Return null if the request origin is not allowed
return null;
}
};
// Add the CORS configuration to the source
source.registerCorsConfiguration(ApplicationConfig.BASE_PATH + "/**", config);
return source;
}
The SecurityConfig.class is annotated with @EnableWebSecurity and @Configuration. Running this test:
@Test
@WithJwtTestUser(user = JwtTestUser.PUK_11)
void testPreflightRequest() throws Exception {
mockMvc.perform(options("/cadastertask/cadasters/" + CADASTER_ID_101_PREMIUM1 + "/regulations/10/tasks")
.header("Origin", "http://localhost:8081")
.header("Access-Control-Request-Method", "GET"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(header().string("Access-Control-Allow-Origin", "http://localhost:8081"))
.andExpect(header().string("Access-Control-Allow-Methods", "GET"))
.andExpect(header().string("Access-Control-Max-Age", "3600"));
}
is responding the "Invalid CORS Request" error. This is the response:
MockHttpServletRequest:
HTTP Method = OPTIONS
Request URI = /cadastertask/cadasters/97190101/regulations/10/tasks
Parameters = {}
Headers = [Origin:"http://localhost:8081", Access-Control-Request-Method:"GET"]
Body = <no character encoding set>
Session Attrs = {}
Handler:
Type = org.springframework.web.servlet.handler.AbstractHandlerMapping$PreFlightHandler
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 403
Error message = null
Headers = [Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", Allow:"GET, HEAD, POST, PUT, DELETE, OPTIONS, TRACE, PATCH"]
Content type = null
Body = Invalid CORS request
Forwarded URL = null
Redirected URL = null
Cookies = []
java.lang.AssertionError: Status expected:<200> but was:<403>
Expected :200
Actual :403
While debugging I can see that the corsConfigurationSource seems to be fine, because allowed methods and origins and so on is set. But in the AbstractHandlerMapping.java class the corsInterceptor method is called and there is the config null. So it seems that my own configuration is overwritten by some other methods and I have no idea how to fix that.
Same problem exist if I change the response of my corsConfigurationSource() to the interface CorsConfigurationSource. If I use a CorsFilter it is working, but I shell use the corsConfigurationSource and not the filter.
Has anyone an idea how to fix that? It is really frustrating...
Thanks in advance.
Upvotes: 0
Views: 330
Reputation: 63
My answer is in respect to spring security 6 (specifically 6.1.4).
Your spring security configuration class defining beans for SecurityWebFilterChain
in your case SecurityFilterChain
should have the cors configuration set as below:
http.cors(corsSpec -> corsSpec.configurationSource(getCorsConfigurationSource()));
where the method getCorsConfigurationSource() will look like below:
@Bean
CorsConfigurationSource getCorsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(List.of(*your origings*));
configuration.setAllowedMethods(List.of("GET", "DELETE", "PUT", "POST"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(List.of("Authorization", "Cache-Control", "Content-Type"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
The allowed headers, credentials and methods are set in such a way that it appeals to a general app's CORS config, please change accordingly.
Upvotes: 0