How to enable cross-origin requests in Grails websocket plugin

1.7k views Asked by At

I tried to override the default configuration of the spring websocket plugin for Grails, like this :

@Configuration
@EnableWebSocketMessageBroker
class CorsWebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    void configureMessageBroker(MessageBrokerRegistry messageBrokerRegistry) {
        messageBrokerRegistry.enableSimpleBroker "/queue", "/topic"
        messageBrokerRegistry.setApplicationDestinationPrefixes "/app"
    }

    @Override
    void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
        StompWebSocketEndpointRegistration registration = stompEndpointRegistry.addEndpoint("/stomp")
        registration.setAllowedOrigins('http://localhost', 'http://localhost:8080')
        registration.withSockJS().setSupressCors(false)
    }

   // [...]
}

I also tried by doing a .setAllowedOrigins('*'), but it still won't work.

However, when I register my client, the "Access-Control-Allow-Origin" header is never set on the /stomp/info endpoint. I always get "XMLHttpRequest cannot load http://localhost:8080/app/stomp/info. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access."

2

There are 2 answers

2
zyro On

i pushed a grails-3.0.2/grails-spring-websocket-2.0.0 sample app to https://github.com/zyro23/so-30891198 which shows that it should be working.

curl -H "Origin: http://localhost:8080" --verbose http://localhost:8080/stomp/info
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://localhost:8080

curl -H "Origin: http://localhost" --verbose http://localhost:8080/stomp/info
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://localhost

and the second sample using grails-2.5.0/spring-websocket-1.3.0: https://github.com/zyro23/so-30891198-2

curl -H "Origin: http://localhost:8080" --verbose http://localhost:8080/so-30891198-2/stomp/info
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://localhost:8080

curl -H "Origin: http://localhost" --verbose http://localhost:8080/so-30891198-2/stomp/info
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://localhost
1
Hlib Barylskyi On

I solved this issue using info from https://github.com/davidtinker/grails-cors. Grails-cors plugin is not working for grails 3.x, but there is some info in the repo readme. I'll copy/paste it here:

This plugin does not work with Grails 3. To handle CORS in a Grails 3 project you can just create a servlet filter somewhere under src/main/java:

@Priority(Integer.MIN_VALUE)
public class CorsFilter extends OncePerRequestFilter {

    public CorsFilter() { }

    @Override
    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse resp, FilterChain chain)
            throws ServletException, IOException {

        String origin = req.getHeader("Origin");

        boolean options = "OPTIONS".equals(req.getMethod());
        if (options) {
            if (origin == null) return;
            resp.addHeader("Access-Control-Allow-Headers", "origin,     authorization, accept, content-type, x-requested-with");
            resp.addHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS");
            resp.addHeader("Access-Control-Max-Age", "3600");
        }

        resp.addHeader("Access-Control-Allow-Origin", origin == null ? "*" : origin);
        resp.addHeader("Access-Control-Allow-Credentials", "true");

        if (!options) chain.doFilter(req, resp);
    }
}

Reference the filter in grails-app/conf/spring/resources.groovy:

beans = {
     corsFilter(CorsFilter)
}

Hope this helps someone.