Closed vpavlyuk closed 5 years ago
Forgot to provide the gateway CORS configuration. The issue can be see even with 'allow all' configuration, no matter programmatic or declared in application.xml:
@Bean
public CorsConfiguration corsConfiguration(RoutePredicateHandlerMapping routePredicateHandlerMapping) {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedOrigins(Collections.unmodifiableList(Arrays.asList(CorsConfiguration.ALL)));
corsConfiguration.setAllowedMethods(Arrays.asList(
HttpMethod.POST.name(),
HttpMethod.GET.name(),
HttpMethod.OPTIONS.name(),
HttpMethod.DELETE.name(),
HttpMethod.PUT.name(),
HttpMethod.PATCH.name()
));
corsConfiguration.setAllowedHeaders(
Arrays.asList(ORIGIN, X_REQUESTED_WITH, CONTENT_TYPE, ACCEPT, AUTHORIZATION, "XXX"));
corsConfiguration.setMaxAge(3600L);
corsConfiguration.setAllowCredentials(true);
routePredicateHandlerMapping.setCorsConfigurations(
new HashMap<String, CorsConfiguration>() {{ put("/**", corsConfiguration); }});
return corsConfiguration;
}
That test doesn't fail for me.
Please use https://github.com/vpavlyuk/spring-cloud-gateway-sample to reproduce.
java.lang.AssertionError: Response header 'Access-Control-Allow-Origin' expected:<[http://wat.com]> but was:<[http://wat.com, http://wat.com]>
Then downgrade in pom.xml to spring-boot-starter-parent version 2.0.5.RELEASE, and to Finchley.BUILD-SNAPSHOT. The test passes.
It's not complete since there's no downstream service to connect to.
@spencergibb I added a route to httpbin.org to reproduce manually and updated the sample. https://github.com/vpavlyuk/spring-cloud-gateway-sample#manually-with-httpbinorg-backend
I see it happen, but I think it wasn't on purpose that it didn't happen Finchley, so I'm not sure it is a regression. If anything, it might be a bug that it didn't add them. You've configured spring boot (running the gateway) to add the headers and your downstream service adds them. There's no gateway specific code that adds them, we just plug into spring framework and it does it. I think the right thing is to do what you are doing and dedupe on your legacy services.
OK, thanks, feel free to close this. If it'd make sense I can contribute the deduping filter to SCG.
PRs welcome
I have the same question, if the downstream service write the Access-Control-Allow-Origin:x , when return to the client , it will be Access-Control-Allow-Origin: x, *, and the browser not working. finally I add a global filter after NettyWriteResponseFilter to fix the bad header.
I'll contribute my dedupe filter to SCG once I find time to brush it up.
Created PR https://github.com/spring-cloud/spring-cloud-gateway/pull/866 with a generic dedupe filter.
Same thing happening here :( We are trying to migrate our current Spring Cloud Zuul gateway to the newest Spring Cloud Gateway (v2.1.0.RELEASE) based on Webflux, and the browser client is having the same issues with duplicated CORS Access-Control-Allow-Origin response header.
Still facing the issue with duplicate origins in Access-Control-Allow-Origin , even though the last comment says it has been fixed with Greenwich.SR2 release. Can anybody tell me the workaround or the proper version to be used?
I'm facing this weird behavior too, when no 'Access-Control-Allow-Origin' is added: No 'Access-Control-Allow-Origin' header is present on the requested resource.
But if any 'Access-Control-Allow-Origin' is set, then my response come with an extra The 'Access-Control-Allow-Origin' header contains multiple values ', ', but only one is allowed. or The 'Access-Control-Allow-Origin' header contains multiple values 'http://localhost:8080, ', but only one is allowed.
Version: Greenwich.SR2
Check if the upstream application has CORS configuration setup too. That was causing this issue for me. I removed it and the issue was gone. If you do not have control on the upstream application, try using the dedupe filter (check spring io docs for spring cloud gateway).
Thanx @swarnar87 , I forgot to remove @CrossOrigin from my upstream application controllers
Thanx 42
nice
This works for me No need to add any bean.
spring:
cloud:
gateway:
default-filters:
- DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-Allow-Credentials, RETAIN_UNIQUE
globalcors:
cors-configurations:
'[/**]':
allowed-origins: "*"
allowed-methods: "*"
allowed-headers: "*"
allow-credentials: true
This works for me No need to add any bean.
spring: cloud: gateway: default-filters: - DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-Allow-Credentials, RETAIN_UNIQUE globalcors: cors-configurations: '[/**]': allowed-origins: "*" allowed-methods: "*" allowed-headers: "*" allow-credentials: true
This almost worked for me,
The RETAIN_UNIQUE parameter will retain every unique header that is added along the way. So my client(localhost:4200) and browser was still reporting duplicate headers with values "http://localhost:4200" and "*".
I decided to be explicit with the allowed-origins: "http://localhost:4200" which ensured they matched. This will still allow the browser to throw CORS errors if any other origin is used in your server, which is probably good from a security standpoint.
Learn more about setting gateway filter factories here... https://cloud.spring.io/spring-cloud-gateway/2.1.x/multi/multi__gatewayfilter_factories.html
This works for me No need to add any bean.
spring: cloud: gateway: default-filters: - DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-Allow-Credentials, RETAIN_UNIQUE globalcors: cors-configurations: '[/**]': allowed-origins: "*" allowed-methods: "*" allowed-headers: "*" allow-credentials: true
I have applied following configuration but still receive error:
Access to XMLHttpRequest at 'http://localhost:8080/xx/yy?' from origin 'http://localhost:57254' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
This works for me No need to add any bean.
spring: cloud: gateway: default-filters: - DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-Allow-Credentials, RETAIN_UNIQUE globalcors: cors-configurations: '[/**]': allowed-origins: "*" allowed-methods: "*" allowed-headers: "*" allow-credentials: true
I have applied following configuration but still receive error:
Access to XMLHttpRequest at 'http://localhost:8080/xx/yy?' from origin 'http://localhost:57254' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Make sure you getting the cross origin response header from your downstream services.
As per your comment its does get the cors header No 'Access-Control-Allow-Origin' header is present on the requested resource.
/*
Default: Retain the first value only.
*/
RETAIN_FIRST,
/*
Retain the last value only.
*/
RETAIN_LAST,
/*
Retain all unique values in the order of their first encounter.
*/
RETAIN_UNIQUE
This works for me No need to add any bean.
spring: cloud: gateway: default-filters: - DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-Allow-Credentials, RETAIN_UNIQUE globalcors: cors-configurations: '[/**]': allowed-origins: "*" allowed-methods: "*" allowed-headers: "*" allow-credentials: true
That works for me!
Check if the upstream application has CORS configuration setup too. That was causing this issue for me. I removed it and the issue was gone. If you do not have control on the upstream application, try using the dedupe filter (check spring io docs for spring cloud gateway).
Thanks,work for me
/* Default: Retain the first value only. */ RETAIN_FIRST, /* Retain the last value only. */ RETAIN_LAST, /* Retain all unique values in the order of their first encounter. */ RETAIN_UNIQUE
RETAIN_FIRST worked for me. Thanks everyone.
In Spring Cloud Gateway 2022.0.3 I added:
spring:
cloud:
gateway:
default-filters:
- DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-Allow-Credentials, RETAIN_UNIQUE
globalcors:
cors-configurations:
'[/**]':
allowed-origins: "*"
allowed-methods: "*"
allowed-headers: "*"
allow-credentials: true
Error During startup:
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to bind properties under 'spring.cloud.gateway.globalcors.cors-configurations[/**]' to org.springframework.web.cors.CorsConfiguration:
Reason: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.String] to type [org.springframework.web.cors.CorsConfiguration]
Action:
Update your application's configuration
Any solution?
In Spring Cloud Gateway 2022.0.3 I added:
spring: cloud: gateway: default-filters: - DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-Allow-Credentials, RETAIN_UNIQUE globalcors: cors-configurations: '[/**]': allowed-origins: "*" allowed-methods: "*" allowed-headers: "*" allow-credentials: true
Error During startup:
*************************** APPLICATION FAILED TO START *************************** Description: Failed to bind properties under 'spring.cloud.gateway.globalcors.cors-configurations[/**]' to org.springframework.web.cors.CorsConfiguration: Reason: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.String] to type [org.springframework.web.cors.CorsConfiguration] Action: Update your application's configuration
Any solution?
Just from what you posted it sounds like '[/**]' isn't placed in a valid location. I think it's reading that as a string than getting your cors properties below.
In Spring Cloud Gateway 2022.0.3 I added:
spring: cloud: gateway: default-filters: - DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-Allow-Credentials, RETAIN_UNIQUE globalcors: cors-configurations: '[/**]': allowed-origins: "*" allowed-methods: "*" allowed-headers: "*" allow-credentials: true
Error During startup:
*************************** APPLICATION FAILED TO START *************************** Description: Failed to bind properties under 'spring.cloud.gateway.globalcors.cors-configurations[/**]' to org.springframework.web.cors.CorsConfiguration: Reason: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.String] to type [org.springframework.web.cors.CorsConfiguration] Action: Update your application's configuration
Any solution?
Just from what you posted it sounds like '[/**]' isn't placed in a valid location. I think it's reading that as a string than getting your cors properties below.
Yes, I saw it and I tested it but I the configuration is not working.
@rcbandit111 it's best not to comment on an unrelated issue. Please open a new one with a complete, minimal, verifiable sample (something that we can unzip attached to the new issue or git clone, build, and deploy) that reproduces the problem.
Some of the legacy back ends behind our gateway have their own CORS filters. On non-OPTIONS requests, they return their own Access-Control-Allow-Origin and Access-Control-Allow-Credentials response headers. With Finchley train, the gateway's CORS processor would not duplicate these response headers. After upgrade to Greenwich BUILD-SNAPSHOT and Spring Boot 2.1.1.Release, these response headers are in two copies each, rightfully upsetting the consumer (Angular based) apps:
I will dedup those with a global post filter for now, but still thought to file this issue as the behavior changed and perhaps can be fixed at the source. Here is an integration test snippet I have that succeeds with Finchley train but fails with Greenwich: