How to handle CORS origins with Stomp and SockJS in Spring 5.3 and newer?

Viewed 7687

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?

2 Answers

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();
Related