Roddy of the Frozen Peas
Roddy of the Frozen Peas

Reputation: 15180

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.

Upvotes: 0

Views: 1673

Answers (1)

Dag Fort
Dag Fort

Reputation: 58

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);
    }
}

Upvotes: 4

Related Questions