I'm working on a server application which uses both REST endpoints and a SockJS websocket. This used to work fine under Spring 5.2 and below.
However, since the 5.3 release, the following method exists within org.springframework.web.cors.CorsConfiguration
:
public void validateAllowCredentials() {
if (this.allowCredentials == Boolean.TRUE &&
this.allowedOrigins != null && this.allowedOrigins.contains(ALL)) {
throw new IllegalArgumentException(
"When allowCredentials is true, allowedOrigins cannot contain the special value \"*\"" +
"since that cannot be set on the \"Access-Control-Allow-Origin\" response header. " +
"To allow credentials to a set of origins, list them explicitly " +
"or consider using \"allowedOriginPatterns\" instead.");
}
}
So far, my socket was configured like this:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
// prefix for the client to send messages to the server
config.setApplicationDestinationPrefixes("/app");
// prefix for the client to receive broadcasted messages from the server
config.enableSimpleBroker("/topic");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// defines the url of the socket so the client can connect to it
registry.addEndpoint("/socketendpoint").setAllowedOrigins("*").withSockJS();
}
}
Now I'm facing a real issue:
setAllowedOrigins("*")
in the WebSocketConfiguration
, then I will face the error thrown in validateAllowCredentials
.setAllowedOrigins("*")
, then the SockJS clients will recieve an Error during WebSocket handshake: Unexpected response code: 403
.I don't know the origin domain at compile time.
I already tried a Cors Filter and a Cors Configuration that use the typical "return the origin
header you find in the request as allow-origin
" pattern that is usually used to circumvent the allow-origin: "*"
, but some SockJS requests don't have an origin
header assigned...
How do I fix this?
Enable CORS in Controller Method We need to set the origins for RESTful web service by using @CrossOrigin annotation for the controller method. This @CrossOrigin annotation supports specific REST API, and not for the entire application.
The WebSocket API enables web applications to handle bidirectional communications whereas STOMP is a simple text-orientated messaging protocol. A Bidirectional WebSocket allows a web server to initiate a new message to a client, rather than wait for the client to request updates.
No. You need to add @CrossOrigin annotation by yourself to get CORS Support in Spring. Why: Enabling CORS (Cross-origin resource sharing) by default will be a serious security issue.
Spring WebSocket is the Spring module that enables WebSocket-style messaging support. As Spring WebSocket’s documentation states, the WebSocket protocol defines an important new capability for web applications: full-duplex, two-way communication between client and server. Well, now that we know what WebSocket, STOMP, SockJS and Spring WebSocket.
If that fails it can use a variety of browser-specific transport protocols and presents them through WebSocket-like abstractions. SockJS is used to enable fallback options for browsers that don’t support WebSocket. Spring provides a server-side implementation of SockJS and we will see how to use the same in this example.
In such a case, CORS enables cross-domain communication. Spring provides first-class support for CORS, offering an easy and powerful way of configuring it in any Spring or Spring Boot web application. A quick and practical guide to working with CORS and Spring Webflux.
Each provided allowed origin must start by "http://", "https://" or be "*" (means that all origins are allowed). By default, only same origin requests are allowed (empty list). Since: 4.1.2 See Also: RFC 6454: The Web Origin Concept , SockJS supported transports by browser
For future reference, with the latest spring updates, there's now a method setAllowedOriginPatterns
that solves this:
registry.addEndpoint("/socketendpoint").setAllowedOriginPatterns("*").withSockJS();
From the documentation
Configure allowed Origin header values. This check is mostly designed for browser clients. There is nothing preventing other types of client to modify the Origin header value. When SockJS is enabled and origins are restricted, transport types that do not allow to check request origin (Iframe based transports) are disabled. As a consequence, IE 6 to 9 are not supported when origins are restricted. Each provided allowed origin must start by "http://", "https://" or be "*" (means that all origins are allowed). By default, only same origin requests are allowed (empty list). Since: 4.1.2 See Also: RFC 6454: The Web Origin Concept , SockJS supported transports by browser
Your code
registry.addEndpoint("/socketendpoint").setAllowedOrigins("*").setAllowedOrigins().withSockJS();
Should be
registry.addEndpoint("/socketendpoint").setAllowedOrigins("*").withSockJS();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With