Spring-cloud-gateway: Preflight Request

Created on 12 Mar 2018  Â·  41Comments  Â·  Source: spring-cloud/spring-cloud-gateway

Hi,

Is OPTIONS by default allowed? I am getting error for POST with json body which send a preflight request of OPTIONS method. Error is cross origin.

Thanks

enhancement

Most helpful comment

@hnxuruochen Just did a workaroundd below to set RoutePredicateHandlerMapping CORS configuration.

@Bean public CorsConfiguration corsConfiguration(RoutePredicateHandlerMapping routePredicateHandlerMapping) { CorsConfiguration corsConfiguration = new CorsConfiguration().applyPermitDefaultValues(); Arrays.asList(HttpMethod.OPTIONS, HttpMethod.PUT, HttpMethod.GET, HttpMethod.DELETE, HttpMethod.POST) .forEach(m -> corsConfiguration.addAllowedMethod(m)); corsConfiguration.addAllowedOrigin("*"); routePredicateHandlerMapping.setCorsConfigurations(new HashMap<String, CorsConfiguration>() {{ put("/**", corsConfiguration); }}); return corsConfiguration; }

All 41 comments

I was able to confirm that the gateway is causing the error. It returns forbidden when the below headers are in the OPTIONS method.

screen shot 2018-03-12 at 1 27 00 am

I will try later configuring the webflux cors filter.

It did not work but I found the culprit. This might require a change in the gateway.

In the class org.springframework.web.reactive.handlerAbstractHandlerMapping, there is a check if the request is CORS. When I was debugging, the configA and configB are both null. ConfigA is looking for @CrossOrigin which we do not have in gateway. Then ConfigB is also null because the handler passed was actually a list of OrderedGatewayFilter and reactive expects it to be CorsConfiguration. I think there has to be handling at the gateway but I feel it could be a big change? The work around I can think is add a filter that will remove the "Origin" header but a security liability.

screen shot 2018-03-12 at 11 18 08 pm

Feels like a duplicate of #112. Have you tried this https://github.com/spring-cloud/spring-cloud-gateway/issues/112#issuecomment-346951627

I saw that. I just tried the Cors configurer part.it did not work. the route part for sure will work because it removes the origin header. actually that is the one that made it work.

yes also tried the one in the docs. did not work. In gateway case, global configure is the only approach that may work but, when i debug, webflux does not load it.

I did further debug. I found out that when declaring below only sets the globalCorsConfigSource in RouterFunctionMapping and RequestMappingHandlerMapping but not in RoutePredicateHandlerMapping which gateway is using. This handler looks like causes the 403 response from reactive.

screen shot 2018-03-13 at 9 54 00 am

Looks like RouterFunctionMapping and RequestMappingHandlerMapping do an initial processing to set the Cors configuration if present in the context. Do you think gateway should do same thing in RoutePredicateHandlerMapping?

It could

@sincang I don't see anything in RouterFunctionMapping. RequestMappingHandlerMapping uses @CrossOrigin. Looks like we could do something with properties.

@sincang normal spring cors configuration should work to populate configA. configB is not needed to function properly

@spencergibb WebfluxConfigurationSupport creates RouterFunctionMapping. It is where the cors config was set. Please see below.

BTW, if we use @CrossOrigin, I am wondering where to put it since gateway does not have mapping for paths locally.

screen shot 2018-03-13 at 1 38 34 pm

@CrossOrigin doesn't make sense for the gateway.

maybe that https://github.com/spring-cloud/spring-cloud-gateway/issues/229#issuecomment-372754112 is what is missing for the global configuration to work.

Should we set the cors config in GatewayAutoConfig if available in context?

something like that.

Thanks. Will wait for your change then will test it.

it won't be immediate.

@spencergibb I will just wait or Is it fine if I send PR, just take a look?

PRs are always welcome!

@sincang I also met the same problem, is the bug fixed? Or what can I do to solve this problem?
Really need your help.

@sincang OK I read this article three times and get your work finally. Sorry I'm a fresh man.
I create a new class and extend RoutePredicateHandlerMapping then copy your code into the class and overide the old method.
It works. Thanks.

@hnxuruochen Just did a workaroundd below to set RoutePredicateHandlerMapping CORS configuration.

@Bean public CorsConfiguration corsConfiguration(RoutePredicateHandlerMapping routePredicateHandlerMapping) { CorsConfiguration corsConfiguration = new CorsConfiguration().applyPermitDefaultValues(); Arrays.asList(HttpMethod.OPTIONS, HttpMethod.PUT, HttpMethod.GET, HttpMethod.DELETE, HttpMethod.POST) .forEach(m -> corsConfiguration.addAllowedMethod(m)); corsConfiguration.addAllowedOrigin("*"); routePredicateHandlerMapping.setCorsConfigurations(new HashMap<String, CorsConfiguration>() {{ put("/**", corsConfiguration); }}); return corsConfiguration; }

Why do I actually have to give control over CORS to the Gateway instead of being able to leave it to a specific microservice developer, thus simply forwarding options request to the underlying service?

You don't have to give control to the Gateway, it is optional. The Gateway has global support so that you have the option not to update your micro services to handle it.

But then the OPTIONS request is always being responded by 403 instead of being sent to the underlying microservice

But then the OPTIONS request is always being responded by 403 instead of being sent to the underlying microservice

strugling now。。。

Because CORS is by default disabled. Spring cloud gateway has nothing to do on this. It is the webflux default behavior . You have to declare global CORS. Put all HTTP methods and * origin so you will let your respective services handle the finer control. You can do it in your application.yml file. Check the documentation.

@sincang
The documentation linked says "The gateway can be configured to control CORS behavior". And I even debugged it to make sure that it does. This configuration makes gateway process the preflight and answer, the OPTIONS request never gets forwarded to underlying service. But, why do I have to trust the preflight request to the gateway when I would rather have it passed to a respective underlying webservice as the gateway should do by default ?

@maslano what do you suggest to be the correct behavior?

This spring configuration is optional. If you don't supply some global CORS configuration you get the default behavior from webflux. All we are doing here is plugging into: https://github.com/spring-projects/spring-framework/blob/v5.0.10.RELEASE/spring-webflux/src/main/java/org/springframework/web/reactive/handler/AbstractHandlerMapping.java#L152

It seems, that example provided on the page https://cloud.spring.io/spring-cloud-gateway/multi/multi__cors_configuration.html is not valid.
In CorsConfiguration.checkOrigin the check is done for requestOrigin, which includes schema 'http' or 'https', while example does not include schema and has just a domain: docs.spring.io.

It confused me and I've spent time on debugging, why CORS were not working for me.

Please open a new issue

@spencergibb I think implementation is correct and the issue is with documentation.
Do you mean to open issue for fixing documentation?

Documentation

Did someone find a way to forward preflight requests to services behind the API gateway? Like @maslano I neither want WebFlux nor Spring Cloud Gateway to handle CORS. I'm trying to build a gateway that decides dynamically based on the Host header and information stored in a database to which service to forward a request to. So route-specific CORS won't be of any help in this case. I'd like to forward the OPTIONS request to the responsible service and pass through the CORS headers from there to the client of the gateway.

I already tried registering a custom CorsWebFilter with a CorsConfigurationSource that always returns null and a CorsProcessor that always returns true, but then
RoutePredicateHandlerMapping#getCorsProcessor still returns a DefaultCorsProcessor. So I patched the current master of Spring Cloud Gateway to also use my stub there. Then I got a response with HTTP status 200 instead of 403 but the gateway still didn't forward the request. I suppose that's because WebFlux also has a check for isPreFlightRequest in AbstractHandlerMapping that marks the request as handled in this case. That's when I came here for help.

Is there already a way to achieve what I'm trying to do here with Spring Cloud Gateway and if not, are there any plans on supporting this in the future?

@thammerl please open a new issue.

Opened #830.

Was this page helpful?
0 / 5 - 0 ratings