From 1e76e7122567bee0d22dd5399877911a039fc18a Mon Sep 17 00:00:00 2001 From: Tillmann Heigel Date: Thu, 28 Jun 2018 10:08:32 +0200 Subject: [PATCH 1/9] Fix a small typo in spring-cloud-gateway.adoc PostGatewayFilterFactory example wasn't compiling. --- docs/src/main/asciidoc/spring-cloud-gateway.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/main/asciidoc/spring-cloud-gateway.adoc b/docs/src/main/asciidoc/spring-cloud-gateway.adoc index 73a145cb..0621df6e 100644 --- a/docs/src/main/asciidoc/spring-cloud-gateway.adoc +++ b/docs/src/main/asciidoc/spring-cloud-gateway.adoc @@ -990,7 +990,7 @@ public class PostGatewayFilterFactory extends AbstractGatewayFilterFactory { return chain.filter(exchange).then(Mono.fromRunnable(() -> { - ServerHttpReponse response = exchange.getResponse(); + ServerHttpResponse response = exchange.getResponse(); //Manipulate the response in some way })); }; From 07611ef8f895be75d1dc13e4cc13165f95db8546 Mon Sep 17 00:00:00 2001 From: Tony Clarke Date: Thu, 28 Jun 2018 13:41:59 -0400 Subject: [PATCH 2/9] Support global configuration for CORS. See https://github.com/spring-cloud/spring-cloud-gateway/issues/229 --- .../config/GatewayAutoConfiguration.java | 11 ++- .../gateway/config/GlobalCorsProperties.java | 40 ++++++++ .../handler/RoutePredicateHandlerMapping.java | 12 ++- .../cloud/gateway/cors/CorsTests.java | 93 +++++++++++++++++++ .../src/test/resources/application.yml | 5 + 5 files changed, 153 insertions(+), 8 deletions(-) create mode 100644 spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/config/GlobalCorsProperties.java create mode 100644 spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/cors/CorsTests.java diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java index b936e620..23ff89a8 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java @@ -280,9 +280,14 @@ public class GatewayAutoConfiguration { } @Bean - public RoutePredicateHandlerMapping routePredicateHandlerMapping(FilteringWebHandler webHandler, - RouteLocator routeLocator) { - return new RoutePredicateHandlerMapping(webHandler, routeLocator); + public GlobalCorsProperties globalCorsProperties() { + return new GlobalCorsProperties(); + } + + @Bean + public RoutePredicateHandlerMapping routePredicateHandlerMapping(FilteringWebHandler webHandler, RouteLocator routeLocator, + GlobalCorsProperties globalCorsProperties) { + return new RoutePredicateHandlerMapping(webHandler, routeLocator, globalCorsProperties); } // ConfigurationProperty beans diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/config/GlobalCorsProperties.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/config/GlobalCorsProperties.java new file mode 100644 index 00000000..8216d2f3 --- /dev/null +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/config/GlobalCorsProperties.java @@ -0,0 +1,40 @@ +/* + * Copyright 2013-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.springframework.cloud.gateway.config; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping; +import org.springframework.web.cors.CorsConfiguration; + +/** + * Configuration properties for global configuration of cors. See {@link RoutePredicateHandlerMapping} + */ +@ConfigurationProperties("spring.cloud.gateway.globalcors") +public class GlobalCorsProperties { + + private final Map corsConfigurations = new LinkedHashMap<>(); + + public Map getCorsConfigurations() + { + return corsConfigurations; + } + +} diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/handler/RoutePredicateHandlerMapping.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/handler/RoutePredicateHandlerMapping.java index 53fdf340..665e9294 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/handler/RoutePredicateHandlerMapping.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/handler/RoutePredicateHandlerMapping.java @@ -19,6 +19,7 @@ package org.springframework.cloud.gateway.handler; import java.util.function.Function; +import org.springframework.cloud.gateway.config.GlobalCorsProperties; import org.springframework.cloud.gateway.route.Route; import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.web.cors.CorsConfiguration; @@ -39,11 +40,12 @@ public class RoutePredicateHandlerMapping extends AbstractHandlerMapping { private final FilteringWebHandler webHandler; private final RouteLocator routeLocator; - public RoutePredicateHandlerMapping(FilteringWebHandler webHandler, RouteLocator routeLocator) { + public RoutePredicateHandlerMapping(FilteringWebHandler webHandler, RouteLocator routeLocator, GlobalCorsProperties globalCorsProperties) { this.webHandler = webHandler; this.routeLocator = routeLocator; - setOrder(1); + setOrder(1); + setCorsConfigurations(globalCorsProperties.getCorsConfigurations()); } @Override @@ -70,10 +72,10 @@ public class RoutePredicateHandlerMapping extends AbstractHandlerMapping { @Override protected CorsConfiguration getCorsConfiguration(Object handler, ServerWebExchange exchange) { - //TODO: support cors configuration via global properties and - // properties on a route see gh-229 + // TODO: support cors configuration via properties on a route see gh-229 // see RequestMappingHandlerMapping.initCorsConfiguration() - // also see https://github.com/spring-projects/spring-framework/blob/master/spring-web/src/test/java/org/springframework/web/cors/reactive/CorsWebFilterTests.java + // also see https://github.com/spring-projects/spring-framework/blob/master/spring-web/src/test/java/org/springframework/web/cors/reactive/CorsWebFilterTests.java + return super.getCorsConfiguration(handler, exchange); } diff --git a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/cors/CorsTests.java b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/cors/CorsTests.java new file mode 100644 index 00000000..7aef6073 --- /dev/null +++ b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/cors/CorsTests.java @@ -0,0 +1,93 @@ +/* + * Copyright 2013-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.springframework.cloud.gateway.cors; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.gateway.test.BaseWebClientTests; +import org.springframework.context.annotation.Import; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.reactive.function.client.ClientResponse; + +import reactor.core.publisher.Mono; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = RANDOM_PORT) +@DirtiesContext +public class CorsTests extends BaseWebClientTests { + + @Test + public void testPreFlightCorsRequest() { + ClientResponse clientResponse = webClient.options().uri("/abc/123/function") + .header("Origin", "domain.com") + .header("Access-Control-Request-Method", "GET") + .exchange().block(); + HttpHeaders asHttpHeaders = clientResponse.headers().asHttpHeaders(); + Mono bodyToMono = clientResponse.bodyToMono(String.class); + //pre-flight request shouldn't return the response body + assertNull(bodyToMono.block()); + assertEquals("Missing header value in response: "+HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN,"*", asHttpHeaders.getAccessControlAllowOrigin()); + assertEquals("Pre Flight call failed.", HttpStatus.OK, clientResponse.statusCode()); + } + + @Test + public void testCorsRequest() { + ClientResponse clientResponse = webClient.get().uri("/abc/123/function") + .header("Origin", "domain.com") + .header(HttpHeaders.HOST, "www.path.org") + .exchange().block(); + HttpHeaders asHttpHeaders = clientResponse.headers().asHttpHeaders(); + Mono bodyToMono = clientResponse.bodyToMono(String.class); + assertNotNull(bodyToMono.block()); + assertEquals("Missing header value in response: "+HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN,"*", asHttpHeaders.getAccessControlAllowOrigin()); + assertEquals("Pre Flight call failed.", HttpStatus.OK, clientResponse.statusCode()); + } + + @EnableAutoConfiguration + @SpringBootConfiguration + @Import(DefaultTestConfig.class) + public static class TestConfig { + + // this enables the access-control-allow-origin header from the target MS +// @Bean +// public WebFluxConfigurer corsConfigurer() { +// return new WebFluxConfigurerComposite() { +// +// @Override +// public void addCorsMappings(CorsRegistry registry) { +// registry.addMapping("/**") +// .allowedOrigins("*") +// .allowedMethods("*"); +// } +// }; +// } + + } + +} diff --git a/spring-cloud-gateway-core/src/test/resources/application.yml b/spring-cloud-gateway-core/src/test/resources/application.yml index dc2bb2eb..5dbdfa9c 100644 --- a/spring-cloud-gateway-core/src/test/resources/application.yml +++ b/spring-cloud-gateway-core/src/test/resources/application.yml @@ -7,6 +7,11 @@ test: spring: cloud: gateway: + globalcors: + corsConfigurations: + '[/**]': + maxAge: 10 + allowedOrigins: "*" default-filters: - AddResponseHeader=X-Response-Default-Foo, Default-Bar - PrefixPath=/httpbin From 6e138c40b626b31f3289ea9b8f5937b1003c2a97 Mon Sep 17 00:00:00 2001 From: Tony Clarke Date: Thu, 28 Jun 2018 13:53:26 -0400 Subject: [PATCH 3/9] Update formatting --- .../gateway/config/GlobalCorsProperties.java | 14 ++--- .../cloud/gateway/cors/CorsTests.java | 62 ++++++++----------- 2 files changed, 34 insertions(+), 42 deletions(-) diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/config/GlobalCorsProperties.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/config/GlobalCorsProperties.java index 8216d2f3..8675ac41 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/config/GlobalCorsProperties.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/config/GlobalCorsProperties.java @@ -25,16 +25,16 @@ import org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping; import org.springframework.web.cors.CorsConfiguration; /** - * Configuration properties for global configuration of cors. See {@link RoutePredicateHandlerMapping} + * Configuration properties for global configuration of cors. See + * {@link RoutePredicateHandlerMapping} */ @ConfigurationProperties("spring.cloud.gateway.globalcors") public class GlobalCorsProperties { - - private final Map corsConfigurations = new LinkedHashMap<>(); - public Map getCorsConfigurations() - { - return corsConfigurations; - } + private final Map corsConfigurations = new LinkedHashMap<>(); + + public Map getCorsConfigurations() { + return corsConfigurations; + } } diff --git a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/cors/CorsTests.java b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/cors/CorsTests.java index 7aef6073..e699637c 100644 --- a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/cors/CorsTests.java +++ b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/cors/CorsTests.java @@ -45,49 +45,41 @@ public class CorsTests extends BaseWebClientTests { @Test public void testPreFlightCorsRequest() { ClientResponse clientResponse = webClient.options().uri("/abc/123/function") - .header("Origin", "domain.com") - .header("Access-Control-Request-Method", "GET") + .header("Origin", "domain.com") + .header("Access-Control-Request-Method", "GET").exchange().block(); + HttpHeaders asHttpHeaders = clientResponse.headers().asHttpHeaders(); + Mono bodyToMono = clientResponse.bodyToMono(String.class); + // pre-flight request shouldn't return the response body + assertNull(bodyToMono.block()); + assertEquals( + "Missing header value in response: " + + HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, + "*", asHttpHeaders.getAccessControlAllowOrigin()); + assertEquals("Pre Flight call failed.", HttpStatus.OK, + clientResponse.statusCode()); + } + + @Test + public void testCorsRequest() { + ClientResponse clientResponse = webClient.get().uri("/abc/123/function") + .header("Origin", "domain.com").header(HttpHeaders.HOST, "www.path.org") .exchange().block(); HttpHeaders asHttpHeaders = clientResponse.headers().asHttpHeaders(); Mono bodyToMono = clientResponse.bodyToMono(String.class); - //pre-flight request shouldn't return the response body - assertNull(bodyToMono.block()); - assertEquals("Missing header value in response: "+HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN,"*", asHttpHeaders.getAccessControlAllowOrigin()); - assertEquals("Pre Flight call failed.", HttpStatus.OK, clientResponse.statusCode()); + assertNotNull(bodyToMono.block()); + assertEquals( + "Missing header value in response: " + + HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, + "*", asHttpHeaders.getAccessControlAllowOrigin()); + assertEquals("Pre Flight call failed.", HttpStatus.OK, + clientResponse.statusCode()); } - - @Test - public void testCorsRequest() { - ClientResponse clientResponse = webClient.get().uri("/abc/123/function") - .header("Origin", "domain.com") - .header(HttpHeaders.HOST, "www.path.org") - .exchange().block(); - HttpHeaders asHttpHeaders = clientResponse.headers().asHttpHeaders(); - Mono bodyToMono = clientResponse.bodyToMono(String.class); - assertNotNull(bodyToMono.block()); - assertEquals("Missing header value in response: "+HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN,"*", asHttpHeaders.getAccessControlAllowOrigin()); - assertEquals("Pre Flight call failed.", HttpStatus.OK, clientResponse.statusCode()); - } @EnableAutoConfiguration @SpringBootConfiguration @Import(DefaultTestConfig.class) - public static class TestConfig { - - // this enables the access-control-allow-origin header from the target MS -// @Bean -// public WebFluxConfigurer corsConfigurer() { -// return new WebFluxConfigurerComposite() { -// -// @Override -// public void addCorsMappings(CorsRegistry registry) { -// registry.addMapping("/**") -// .allowedOrigins("*") -// .allowedMethods("*"); -// } -// }; -// } - + public static class TestConfig { + } } From 747c871bc21dcccfb7198c2a97ad1f9892ed9e63 Mon Sep 17 00:00:00 2001 From: Tony Clarke Date: Thu, 28 Jun 2018 21:22:11 -0400 Subject: [PATCH 4/9] Tighten up CORS test --- .../org/springframework/cloud/gateway/cors/CorsTests.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/cors/CorsTests.java b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/cors/CorsTests.java index e699637c..e62667b0 100644 --- a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/cors/CorsTests.java +++ b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/cors/CorsTests.java @@ -22,6 +22,8 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; +import java.util.Arrays; + import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.SpringBootConfiguration; @@ -30,6 +32,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.gateway.test.BaseWebClientTests; import org.springframework.context.annotation.Import; import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringRunner; @@ -55,6 +58,11 @@ public class CorsTests extends BaseWebClientTests { "Missing header value in response: " + HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*", asHttpHeaders.getAccessControlAllowOrigin()); + assertEquals( + "Missing header value in response: " + + HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, + Arrays.asList(new HttpMethod[] { HttpMethod.GET, HttpMethod.HEAD }), + asHttpHeaders.getAccessControlAllowMethods()); assertEquals("Pre Flight call failed.", HttpStatus.OK, clientResponse.statusCode()); } From 94d59452665f9d0bcefe97df5529ddc43cbc4b61 Mon Sep 17 00:00:00 2001 From: Tony Clarke Date: Wed, 11 Jul 2018 16:30:52 -0400 Subject: [PATCH 5/9] Provide documenation on how to configure CORS in spring cloud gateway --- .../main/asciidoc/spring-cloud-gateway.adoc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/src/main/asciidoc/spring-cloud-gateway.adoc b/docs/src/main/asciidoc/spring-cloud-gateway.adoc index 2d02210b..8e1d89dd 100644 --- a/docs/src/main/asciidoc/spring-cloud-gateway.adoc +++ b/docs/src/main/asciidoc/spring-cloud-gateway.adoc @@ -971,6 +971,24 @@ The Gateway can be configured to create routes based on services registered with To enable this, set `spring.cloud.gateway.discovery.locator.enabled=true` and make sure a `DiscoveryClient` implementation is on the classpath and enabled (such as Netflix Eureka, Consul or Zookeeper). +== CORS Configuration + +The gateway can be configured to control CORS behavior. The "global" CORS configuration is a map of URL patterns to https://docs.spring.io/spring/docs/5.0.x/javadoc-api/org/springframework/web/cors/CorsConfiguration.html[Spring Framework `CorsConfiguration`]. + +.application.yml +[source,yaml] +---- +spring: + cloud: + gateway: + globalcors: + corsConfigurations: + '[/**]': + allowedOrigins: "*" +---- + +In the example above, CORS requests will be allowed from all origins for all requested paths. + == Actuator API TODO: document the `/gateway` actuator endpoint From 84ac4963e81ec953388d4d5a4ab6497580eb291f Mon Sep 17 00:00:00 2001 From: Tillmann Heigel Date: Thu, 19 Jul 2018 19:14:05 +0200 Subject: [PATCH 6/9] This proves a bug with the ForwardedHeadersFilter (#440) --- .../headers/ForwardedHeadersFilterTests.java | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java index 21e343fa..19c637d1 100644 --- a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java +++ b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java @@ -17,6 +17,9 @@ package org.springframework.cloud.gateway.filter.headers; +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.cloud.gateway.filter.headers.ForwardedHeadersFilter.FORWARDED_HEADER; + import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; @@ -27,16 +30,12 @@ import java.util.List; import java.util.Map; import org.junit.Test; - import org.springframework.cloud.gateway.filter.headers.ForwardedHeadersFilter.Forwarded; import org.springframework.http.HttpHeaders; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; import org.springframework.util.StringUtils; -import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.cloud.gateway.filter.headers.ForwardedHeadersFilter.FORWARDED_HEADER; - /** * @author Spencer Gibb */ @@ -67,6 +66,36 @@ public class ForwardedHeadersFilterTests { .containsEntry("for", "\"10.0.0.1:80\""); } + @Test + public void forwardedHeaderExists() throws UnknownHostException { + MockServerHttpRequest request = MockServerHttpRequest + .get("http://localhost/get") + .remoteAddress(new InetSocketAddress(InetAddress.getByName("10.0.0.1"), 80)) + .header(FORWARDED_HEADER, "for=12.34.56.78;host=example.com;proto=https; for=23.45.67.89") + .build(); + + ForwardedHeadersFilter filter = new ForwardedHeadersFilter(); + + HttpHeaders headers = filter.filter(request.getHeaders(), MockServerWebExchange.from(request)); + + assertThat(headers.get(FORWARDED_HEADER)).hasSize(2); + + + List forwardeds = ForwardedHeadersFilter.parse(headers.get(FORWARDED_HEADER)); + + assertThat(forwardeds).hasSize(2); + Forwarded addedForwardedHeader = forwardeds.get(0); + Forwarded existingForwardedHeader = forwardeds.get(1); + + assertThat(existingForwardedHeader.getValues()) + .containsEntry("proto", "http") + .containsEntry("for", "\"10.0.0.1:80\""); + + assertThat(addedForwardedHeader.getValues()) + .containsEntry("proto", "https") + .containsEntry("for", "23.45.67.89"); + } + @Test public void noHostHeader() throws UnknownHostException { MockServerHttpRequest request = MockServerHttpRequest From 23800cbd5c01818f0f4692836792ccf92cc8800c Mon Sep 17 00:00:00 2001 From: Tillmann Heigel Date: Thu, 19 Jul 2018 19:15:22 +0200 Subject: [PATCH 7/9] This solves a bug with the ForwardedHeadersFilter (#440) --- .../cloud/gateway/filter/headers/ForwardedHeadersFilter.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java index f5671412..d3941636 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java @@ -25,7 +25,6 @@ import java.util.List; import java.util.Map; import org.jetbrains.annotations.Nullable; - import org.springframework.core.Ordered; import org.springframework.http.HttpHeaders; import org.springframework.http.server.reactive.ServerHttpRequest; @@ -58,7 +57,7 @@ public class ForwardedHeadersFilter implements HttpHeadersFilter, Ordered { List forwardeds = parse(original.get(FORWARDED_HEADER)); for (Forwarded f : forwardeds) { - updated.add(FORWARDED_HEADER, f.toString()); + updated.add(FORWARDED_HEADER, f.toHeaderValue()); } //TODO: add new forwarded From b54825766a5a5eb896824bb0d5cad19e4fb67f09 Mon Sep 17 00:00:00 2001 From: Tillmann Heigel Date: Fri, 20 Jul 2018 09:18:52 +0200 Subject: [PATCH 8/9] Use the correct code formatter as mentioned by @ryanjbaxter --- .../headers/ForwardedHeadersFilterTests.java | 40 +++++++++---------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java index 19c637d1..dc1df9e3 100644 --- a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java +++ b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java @@ -17,18 +17,6 @@ package org.springframework.cloud.gateway.filter.headers; -import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.cloud.gateway.filter.headers.ForwardedHeadersFilter.FORWARDED_HEADER; - -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import org.junit.Test; import org.springframework.cloud.gateway.filter.headers.ForwardedHeadersFilter.Forwarded; import org.springframework.http.HttpHeaders; @@ -36,6 +24,14 @@ import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; import org.springframework.util.StringUtils; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; +import java.util.*; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.cloud.gateway.filter.headers.ForwardedHeadersFilter.FORWARDED_HEADER; + /** * @author Spencer Gibb */ @@ -121,7 +117,7 @@ public class ForwardedHeadersFilterTests { @Test public void forwardedParsedCorrectly() { - String[] valid = new String[] { + String[] valid = new String[]{ "for=\"_gazonk\"", "for=192.0.2.60;proto=http;by=203.0.113.43", "for=192.0.2.43, for=198.51.100.17", @@ -132,15 +128,15 @@ public class ForwardedHeadersFilterTests { @SuppressWarnings("unchecked") List>> expectedFor = new ArrayList>>() {{ - add(list(map("for", "\"_gazonk\""))); - add(list(map("for", "192.0.2.60", "proto", "http", "by", "203.0.113.43"))); - add(list(map("for", "192.0.2.43"), map("for", "198.51.100.17"))); - add(list(map("for", "12.34.56.78", "host", "example.com", "proto", "https"), - map("for", "23.45.67.89"))); - add(list(map("for", "12.34.56.78"), - map("for", "23.45.67.89", "secret", "egah2CGj55fSJFs"), - map("for", "10.1.2.3"))); - add(list(map("for", "\"[2001:db8:cafe::17]:4711\""))); + add(list(map("for", "\"_gazonk\""))); + add(list(map("for", "192.0.2.60", "proto", "http", "by", "203.0.113.43"))); + add(list(map("for", "192.0.2.43"), map("for", "198.51.100.17"))); + add(list(map("for", "12.34.56.78", "host", "example.com", "proto", "https"), + map("for", "23.45.67.89"))); + add(list(map("for", "12.34.56.78"), + map("for", "23.45.67.89", "secret", "egah2CGj55fSJFs"), + map("for", "10.1.2.3"))); + add(list(map("for", "\"[2001:db8:cafe::17]:4711\""))); }}; for (int i = 0; i < valid.length; i++) { From 8f4a944ea2780bf448c9ec34abe0c639f97ac88d Mon Sep 17 00:00:00 2001 From: Tony Clarke Date: Fri, 20 Jul 2018 15:53:15 -0400 Subject: [PATCH 9/9] Update documenation on how to configure CORS request/response --- docs/src/main/asciidoc/spring-cloud-gateway.adoc | 6 ++++-- .../org/springframework/cloud/gateway/cors/CorsTests.java | 2 +- .../src/test/resources/application.yml | 2 ++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/src/main/asciidoc/spring-cloud-gateway.adoc b/docs/src/main/asciidoc/spring-cloud-gateway.adoc index 8e1d89dd..94a78e0a 100644 --- a/docs/src/main/asciidoc/spring-cloud-gateway.adoc +++ b/docs/src/main/asciidoc/spring-cloud-gateway.adoc @@ -984,10 +984,12 @@ spring: globalcors: corsConfigurations: '[/**]': - allowedOrigins: "*" + allowedOrigins: "docs.spring.io" + allowedMethods: + - GET ---- -In the example above, CORS requests will be allowed from all origins for all requested paths. +In the example above, CORS requests will be allowed from requests that originate from docs.spring.io for all GET requested paths. == Actuator API diff --git a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/cors/CorsTests.java b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/cors/CorsTests.java index e62667b0..3e8eeb76 100644 --- a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/cors/CorsTests.java +++ b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/cors/CorsTests.java @@ -79,7 +79,7 @@ public class CorsTests extends BaseWebClientTests { "Missing header value in response: " + HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*", asHttpHeaders.getAccessControlAllowOrigin()); - assertEquals("Pre Flight call failed.", HttpStatus.OK, + assertEquals("CORS request failed.", HttpStatus.OK, clientResponse.statusCode()); } diff --git a/spring-cloud-gateway-core/src/test/resources/application.yml b/spring-cloud-gateway-core/src/test/resources/application.yml index 71763f20..6ae8ed00 100644 --- a/spring-cloud-gateway-core/src/test/resources/application.yml +++ b/spring-cloud-gateway-core/src/test/resources/application.yml @@ -12,6 +12,8 @@ spring: '[/**]': maxAge: 10 allowedOrigins: "*" + allowedMethods: + - GET default-filters: - AddResponseHeader=X-Response-Default-Foo, Default-Bar - PrefixPath=/httpbin