CORS error when accessing static resource - spring

Despite having the following config, accessing http://localhost:8080/rooms/rooms.json gives me a CORS error - No 'Access-Control-Allow-Origin' header is present on the requested resource.
I have no problem to request any other path which is mapped by controller. What is the problem with static resources? How to allow cors request or exclude the resource paths without spring security?
Spring Boot 2.0.5
Spring Boot Web Starter 2.0.5
#Configuration
#EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/rooms/**")
.addResourceLocations("classpath:/rooms/")
.setCachePeriod(3600)
.resourceChain(true)
.addResolver(new PathResourceResolver());
}
#Override
public void addCorsMappings(final CorsRegistry registry) {
registry.addMapping("/**");
}
}

I got it working with the following configuration bean:
#Configuration
public class StaticResourcesCorsConfig
{
#Bean
public WebMvcConfigurer corsConfigurer()
{
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*");
}
};
}
}
Note, that Spring Boot will only send the Access-Control-Allow-Origin header back on a GET request, if the Origin-header is present on the request.

Update addCorsMappings like below it could work
#Configuration
#EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/rooms/**")
.addResourceLocations("classpath:/rooms/")
.setCachePeriod(3600)
.resourceChain(true)
.addResolver(new PathResourceResolver());
}
#Override
public void addCorsMappings(final CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8080")
.allowedMethods("POST", "GET")
//.allowedHeaders("header1", "header2", "header3")
//.exposedHeaders("header1", "header2")
.allowCredentials(true).maxAge(3600);
}
}

Add #CrossOrigin(value = "*") to your controller class. You can replace * with any particular URL in case to allow that origin only.

#CrossOrigin(origins = "http://localhost")
#GetMapping("/rooms/")
public Object rooms() {
// your implementation
}
You can do in this way.

https://www.viator.com/orion/nova/public/mmblite/styles-53929dcb.css
Experienced the same problem actually, but found the root cause and a solution.
Your request was most probably cached by intermediary: load balancer, CDN or caching HTTP server in front of your application as regular non-CORS request. Then you have sent request with Origin:, but the intermediary returned you the same cached response because from point of view of the cache responses by default are identified by /path + METHOD + Host:-header which were the same. To tell caches that the request with Origin: and the regular request (without Origin: need to be cached as independent entries in any cache we need Vary: Origin header in both responses. This was fixed/implemented in Spring 5.2.x (in my case it was Spring 5.1.9), in your case it was 5.0.9 (as dependency of Spring Boot 2.0.5.). Once I upgraded to Spring 5.2.0 all was fixed once caches on the intermediary had expired. I recommend to upgrade beyond 5.2.6 (cause there were further changes in CORS handling, which are nice to have).
here is the line (which made the difference) they (Pivotal) commited into Spring: https://github.com/spring-projects/spring-framework/commit/d27b5d0ab6e8b91a77e272ad57ae83c7d81d810b#r36264428
and their bug description: https://github.com/spring-projects/spring-framework/issues/22273

Related

Spring Boot 2 WebSockets connection lost unexpectedly

I have a Spring boot 1.5 + Angular5 application utilizing Websockets via SockJS, and was recently forced to upgrade to Spring boot 2.2.
Following the upgrade, my websocket is being closed after either a random period of time, or when a write to the websocket happens. When using Spring Boot 1.5, everything works perfectly.
Below is the configuration in Spring, using spring-boot-starter-websocket version: '2.2.4.RELEASE'
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfiguration extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/api/socket")
.setAllowedOrigins("*")
.withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app")
.enableSimpleBroker("/nightly");
}
}
I've also added the following security rules:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/socket/**")
.cors().and()
.headers().frameOptions().disable().and()
.csrf().disable()
.authorizeRequests()
.anyRequest().permitAll();
}
Client code:
initWebSocket() {
const ws = new SockJS('/api/socket');
this.stompClient = Stomp.over(ws);
const that = this;
this.stompClient.connect({}, () => {
that.stompClient.subscribe('/nightly', (message) => {
this._rootStore.dispatch(new UpdateNightlyAction(message));
});
});
}
When the connection is lost, the client logs the following:
POST https://<url>/api/socket/231/i0rsgjlx/xhr?t=1600673163228 404
Whoops! Lost connection to https://<url>/api/socket
I went through different scenarios of Websockets not working in Spring Boot 2 and nothing seemed to help. In 1.5 it works just fine. What am I missing here?
beacuse of springboot2.0^ is not allow cors param allowedOrigins = "*" , you can overwrite AllowedOriginPatterns equals "*"
boot1.5 ->
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
StompWebSocketEndpointRegistration registration = registry.addEndpoint("/webSocket");
registration.setAllowedOrigins("*");
registration.withSockJS();
}
boot2.0^->
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
StompWebSocketEndpointRegistration registration = registry.addEndpoint("/webSocket");
// boot2.0^ AllowedOrigins = * is not allown
registration.setAllowedOriginPatterns("*");
registration.withSockJS();
}
I had a same error with yours, even search for a long time ,but there is no
answers,so i check the debug log find this problem,i fixed it with this method,it works!

Spring - Sock.js - websockets: blocked by CORS policy

I am implementing websockets to Spring App with sock.js + stomp.js on the client app.
When trying to connect I am getting the error:
Access to XMLHttpRequest at 'http://localhost:8080/ws/tracker/info?t=...' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
And in my WebsocketConfiguration :
#Configuration
#EnableWebSocketMessageBroker
#Order(Ordered.HIGHEST_PRECEDENCE + 99)
public class WebsocketConfiguration implements WebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws")
.setAllowedOrigins("*")
.withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic/", "/queue/");
registry.setApplicationDestinationPrefixes("/app");
}
}
Client libraries:
<script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.4.0/sockjs.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.js"></script>
Client connection:
var socket = new SockJS('http://localhost:8080/websocket/tracker');
I have already implemented websockets in one of the earlier projects, so this is all copied from it, though I can't remember (nor find) how to solve this error.
Check if you have ClientForwardController, mapping should be like this:
#GetMapping(value = {"/{path:[^\\.]*}", "/{path:^(?!websocket).*}/**/{path:[^\\.]*}"})
public String forward() {
return "forward:/";
}

How to enable cross origin on wildfly?

I deployed my spring boot app by using wild fly.
But when I inspect my application there it is given that
Access-Control-Allow-Origin: *
I just want to allow my domain for example like:-
Access-Control-Allow-Origin: '192.10.0.1:9991'
How do I achieve it or implement it.
You can configure this while providing a bean of type WebMvcConfigurer:
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("192.10.0.1:9991")
.allowedMethods("GET", "PUT", "DELETE");
// Add more mappings...
}
}
The Spring documentation provides more detailed information about how to configure CORS.

Spring websocket message broker adding extra Access-Control-Allow-Origin header to respose

I have an application that includes a Spring cloud gateway that sits in front of an app which (among other things) supports web socket connections (sockJS). The gateway does a simple url rewrite when it forwards to the app. The two are currently running Spring-Boot 2.0.5.RELEASE and Spring-Cloud Finchley.RELEASE. According to the source I pulled down, this should be using spring-websockets-5.0.9.
When I try to upgrade to 2.1.2.RELEASE and Greenwich.RELEASE for Spring-Boot and Spring-Cloud respectively, my websocket connections start failing because an extra Access-Cloud-Allow-Origin is being injected into the response.
My gateway has a simple CORS filter like this (the values are constants and not relevant):
#Bean
public WebFilter corsFilter() {
return (ServerWebExchange ctx, WebFilterChain chain) -> {
Mono<Void> result;
ServerHttpRequest request = ctx.getRequest();
if (CorsUtils.isCorsRequest(request)) {
ServerHttpResponse response = ctx.getResponse();
HttpHeaders headers = response.getHeaders();
headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
headers.add("Access-Control-Max-Age", MAX_AGE);
headers.add("Access-Control-Allow-Headers",ALLOWED_HEADERS);
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
result = Mono.empty();
} else {
result = chain.filter(ctx);
}
} else {
result = chain.filter(ctx);
}
return result;
};
}
And my web socket config on the downstream app is simply this:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws")
.setAllowedOrigins("*")
.withSockJS();
}
}
If I comment out the .setAllowedOrigins("*") in the registerStompEndpoints method, I correctly get 403 access denied responses, and the response only has the Access-Control-Allow-Origin header as injected by the gateway.
With the method in place as shown here, the websocket response completes as expected with a success response to the caller, but the response header contains both the access control header injected by the gateway plus another Access-Control-Allow-Origin header which is set to the value of the caller (in my case, http://localhost:4200 for the front-end application.) None of the other access control headers are duplicated.
How can I configure the Spring websocket message broker to not inject the Access-Control-Allow-Origin header? This was working, and still works if I roll back to 2.0.5/Finchley.
I faced this issue recently and I was able to resolve it by calling setSupressCors method. The documentation says that
This option can be used to disable automatic addition of CORS headers for SockJS requests.
Here is a code sample:
#Configuration
#EnableWebSocketMessageBroker
public class WebsocketMessageBrokerConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/websocket/handshake")
.setAllowedOrigins("*")
.withSockJS()
.setSupressCors(true);
}
}

spring security permit static assets not working

I understand #EnableWebSecurity disables all spring security defaults, therefore I have overridden the required methods in WebSecurityConfigurerAdapter. However, no matter what I do css and all other static assets get a 403 or 405.
Using spring boot 2.0.0.M7 with spring security created from https://start.spring.io/
Folder structure is the normal
- resources
- static
- css
styles.css
web.ignoring() doesn't do anything for some reason, yet when I enable debugging it does mention that the below paths have been bypassed but I still get a 405.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/css/**", "/webjars/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.
authorizeRequests()
.antMatchers("/register").permitAll()
.anyRequest().authenticated();
}
}
For further debugging I have even tried to permit everything by doing the below, but every url is still denied which is extremely confusing and makes me think there is some key concept I am not grasping.
http.authorizeRequests().antMatchers("/**").permitAll()
Finally, I have also tried to implement WebMvcConfigurer with various combinations of locations which don't work either.
#Configuration
public class WebMvcConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("/webjars/");
}
Can anyone help me?
All the above security configuration is actually correct. You don't have to implement WebMvcConfigurer, only extend WebSecurityConfigurerAdapter.
Turns out to be a very hard bug to track down. I had a controller that served up a registration form like this.
#Controller
public class RegistrationController {
#GetMapping("/register")
public String getRegisterView(Model model) {
model.addAttribute("registerDto", new RegisterDto());
return "register";
}
#PostMapping
public String register(#Valid #ModelAttribute("registerDto") RegisterDto registerDto, BindingResult result) {
// business logic...
return "register";
}
}
The bug is the in the #PostMapping where I forgot to include the path!! which causes spring all sorts of issues when mapping paths. It would be nice if these annotations threw exceptions if no path was provided.
To fix this I updated it to #PostMapping("/register") and now all paths inside
web.ignoring().antMatchers("/css/**", "/js/**", "/webjars/**"); are allowed through.
So ensure all your contoller route annotations have paths in them!

Resources