10

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:

  • If I keep the setAllowedOrigins("*") in the WebSocketConfiguration, then I will face the error thrown in validateAllowCredentials.
  • If I remove the 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?

Martin Häusler
  • 6,544
  • 8
  • 39
  • 66
  • For the requests that don't have an Origin request header, just don’t send an Access-Control-Allow-Origin header in the response—because, wherever those requests are coming from, they’re not coming from a browser that’ll be looking for an Access-Control-Allow-Origin header in the response. The only user agents that have any use for the Access-Control-Allow-Origin header, and even browsers only care about it only for responses to requests to which the browser itself added the Origin header. So any request that lacks an Origin header doesn’t need Access-Control-Allow-Origin in the response. – sideshowbarker Dec 03 '20 at 16:20
  • Were you able to find a solution to this? – Piotr Dec 29 '20 at 19:59
  • We chose to delay the dependency upgrade. There has been a commit on the spring repository regarding this problem recently, it should be included in one of the upcoming releases; not sure if it's out already or not. – Martin Häusler Dec 29 '20 at 23:22

2 Answers2

25

For future reference, with the latest spring updates, there's now a method setAllowedOriginPatterns that solves this:

 registry.addEndpoint("/socketendpoint").setAllowedOriginPatterns("*").withSockJS();
Martin Häusler
  • 6,544
  • 8
  • 39
  • 66
  • 2
    For me, it fixes the error but I simply don't receive any message of my other Spring application anymore. It sends a message but nothing is received. And it worked with earlier Spring Boot versions (2.2 and earlier) – CptDayDreamer Jun 18 '21 at 12:03
  • Hi, I am trying to access "/websocket" endpoint with a corsfilter (in spring security) and "setAllowedOriginPatterns("*")" (in websocketconfig )in place. But by keeping both it gives "Multiple values in 'Access-Control-Allow-Origin'" and by removing from one of them, it says "No Access-Control-Allow-Origin header" or 403 error. How can I access the websocket endpoint? – Manoj Majumdar Dec 23 '21 at 12:14
4

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();
Dirk Deyne
  • 6,048
  • 1
  • 15
  • 32
  • Sorry that was an error in the original question; must have snuck into the code snippet somewhere along the lines of copy-pasting and trimming it back to the relevant parts. It's fixed now. – Martin Häusler Feb 11 '21 at 19:39