diff --git a/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/ProxyExchange.java b/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/ProxyExchange.java index 531bee0f..e998e029 100644 --- a/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/ProxyExchange.java +++ b/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/ProxyExchange.java @@ -45,6 +45,7 @@ import jakarta.servlet.http.HttpServletRequestWrapper; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponseWrapper; +import org.springframework.cloud.gateway.mvc.config.ProxyProperties; import org.springframework.core.Conventions; import org.springframework.core.MethodParameter; import org.springframework.core.ParameterizedTypeReference; @@ -137,6 +138,12 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBody */ public class ProxyExchange { + /** + * Contains headers that are considered case-sensitive by default. + * @deprecated {@link ProxyProperties#DEFAULT_SENSITIVE} + */ + public static Set DEFAULT_SENSITIVE = ProxyProperties.DEFAULT_SENSITIVE; + private URI uri; private RestTemplate rest; @@ -203,6 +210,17 @@ public class ProxyExchange { return this; } + /** + * Sets the names of sensitive headers that are not passed downstream to the backend + * service. + * @param names the names of sensitive headers + * @return this for convenience + * @deprecated {@link #excluded(String...)} + */ + public ProxyExchange sensitive(String... names) { + return excluded(names); + } + /** * Sets the names of excluded headers that are not passed downstream to the backend * service. diff --git a/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeArgumentResolver.java b/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeArgumentResolver.java index b7a27418..9af97ab2 100644 --- a/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeArgumentResolver.java +++ b/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeArgumentResolver.java @@ -62,6 +62,11 @@ public class ProxyExchangeArgumentResolver implements HandlerMethodArgumentResol : autoForwardedHeaders.stream().map(String::toLowerCase).collect(toSet()); } + @Deprecated + public void setSensitive(Set excluded) { + setExcluded(excluded); + } + public void setExcluded(Set excluded) { this.excluded = excluded; } diff --git a/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyProperties.java b/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyProperties.java index c7f2f3f3..59296583 100644 --- a/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyProperties.java +++ b/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyProperties.java @@ -37,6 +37,16 @@ import org.springframework.http.HttpHeaders; @ConfigurationProperties("spring.cloud.gateway.proxy") public class ProxyProperties { + /** + * Contains headers that are considered case-sensitive by default. + */ + public static Set DEFAULT_SENSITIVE = Set.of("cookie", "authorization"); + + /** + * Contains headers that are skipped by default. + */ + public static Set DEFAULT_SKIPPED = Set.of("content-length", "host"); + /** * Fixed header values that will be added to all downstream requests. */ @@ -50,12 +60,13 @@ public class ProxyProperties { /** * A set of sensitive header names that will not be sent downstream by default. */ - private Set sensitive = Set.of("cookie", "authorization"); + private Set sensitive = DEFAULT_SENSITIVE; /** - * A set of header names that will not be sent downstream because they could be problematic. + * A set of header names that will not be sent downstream because they could be + * problematic. */ - private Set skipped = Set.of("content-length", "host"); + private Set skipped = DEFAULT_SKIPPED; public Map getHeaders() { return headers; diff --git a/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/ProductionConfigurationTests.java b/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/ProductionConfigurationTests.java index 7fd4e976..4b2188e8 100644 --- a/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/ProductionConfigurationTests.java +++ b/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/ProductionConfigurationTests.java @@ -115,9 +115,9 @@ public class ProductionConfigurationTests { @Test public void postJsonWithWhitespace() { var json = """ - { - "foo": "bar" - }"""; + { + "foo": "bar" + }"""; var headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); @@ -456,8 +456,7 @@ public class ProductionConfigurationTests { } @PostMapping("/proxy/checkContentLength") - public ResponseEntity checkContentLength( - ProxyExchange proxy) { + public ResponseEntity checkContentLength(ProxyExchange proxy) { return proxy.uri(home.toString() + "/checkContentLength").post(); } @@ -506,8 +505,9 @@ public class ProductionConfigurationTests { } @PostMapping("/checkContentLength") - public ResponseEntity checkContentLength(@RequestHeader(name = "Content-Length", required = false) Integer contentLength, - @RequestBody String json) { + public ResponseEntity checkContentLength( + @RequestHeader(name = "Content-Length", required = false) Integer contentLength, + @RequestBody String json) { if (contentLength != null && contentLength != json.length()) { return ResponseEntity.badRequest().build(); } diff --git a/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/http/GetWithBodyRequestClientHttpRequestFactory.java b/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/http/GetWithBodyRequestClientHttpRequestFactory.java index fd4a0653..9ffdf1d3 100644 --- a/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/http/GetWithBodyRequestClientHttpRequestFactory.java +++ b/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/http/GetWithBodyRequestClientHttpRequestFactory.java @@ -113,17 +113,18 @@ public class GetWithBodyRequestClientHttpRequestFactory implements ClientHttpReq } } + /** + * Represents an HTTP GET request with a body. + */ public static class GetWithEntity extends HttpEntityEnclosingRequestBase { - public static final String METHOD_NAME = "GET"; - public GetWithEntity(final URI uri) { setURI(uri); } @Override public String getMethod() { - return METHOD_NAME; + return HttpMethod.GET.name(); } } diff --git a/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/ProxyExchange.java b/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/ProxyExchange.java index 9d99445c..983f4466 100644 --- a/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/ProxyExchange.java +++ b/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/ProxyExchange.java @@ -29,6 +29,7 @@ import java.util.stream.Collectors; import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; +import org.springframework.cloud.gateway.webflux.config.ProxyProperties; import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpHeaders; @@ -111,6 +112,12 @@ import org.springframework.web.server.ServerWebExchange; */ public class ProxyExchange { + /** + * Contains headers that are considered case-sensitive by default. + * @deprecated {@link ProxyProperties#DEFAULT_SENSITIVE} + */ + public static Set DEFAULT_SENSITIVE = ProxyProperties.DEFAULT_SENSITIVE; + private HttpMethod httpMethod; private URI uri; @@ -190,6 +197,17 @@ public class ProxyExchange { return this; } + /** + * Sets the names of sensitive headers that are not passed downstream to the backend + * service. + * @param names the names of sensitive headers + * @return this for convenience + * @deprecated {@link #excluded(String...)} + */ + public ProxyExchange sensitive(String... names) { + return excluded(names); + } + /** * Sets the names of excluded headers that are not passed downstream to the backend * service. diff --git a/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyExchangeArgumentResolver.java b/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyExchangeArgumentResolver.java index 16430803..7aa52163 100644 --- a/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyExchangeArgumentResolver.java +++ b/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyExchangeArgumentResolver.java @@ -58,6 +58,11 @@ public class ProxyExchangeArgumentResolver implements HandlerMethodArgumentResol this.autoForwardedHeaders = autoForwardedHeaders; } + @Deprecated + public void setSensitive(Set excluded) { + setExcluded(excluded); + } + public void setExcluded(Set excluded) { this.excluded = excluded; } diff --git a/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyProperties.java b/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyProperties.java index c45e2949..38e000d5 100644 --- a/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyProperties.java +++ b/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyProperties.java @@ -37,6 +37,16 @@ import org.springframework.http.HttpHeaders; @ConfigurationProperties("spring.cloud.gateway.proxy") public class ProxyProperties { + /** + * Contains headers that are considered case-sensitive by default. + */ + public static Set DEFAULT_SENSITIVE = Set.of("cookie", "authorization"); + + /** + * Contains headers that are skipped by default. + */ + public static Set DEFAULT_SKIPPED = Set.of("content-length", "host"); + /** * Fixed header values that will be added to all downstream requests. */ @@ -50,12 +60,13 @@ public class ProxyProperties { /** * A set of sensitive header names that will not be sent downstream by default. */ - private Set sensitive = Set.of("cookie", "authorization"); + private Set sensitive = DEFAULT_SENSITIVE; /** - * A set of header names that will not be sent downstream because they could be problematic. + * A set of header names that will not be sent downstream because they could be + * problematic. */ - private Set skipped = Set.of("content-length", "host"); + private Set skipped = DEFAULT_SKIPPED; public Map getHeaders() { return headers; diff --git a/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/ProductionConfigurationTests.java b/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/ProductionConfigurationTests.java index 972b6f07..f7246e18 100644 --- a/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/ProductionConfigurationTests.java +++ b/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/ProductionConfigurationTests.java @@ -58,8 +58,7 @@ import org.springframework.web.util.UriComponentsBuilder; import static org.assertj.core.api.Assertions.assertThat; -@SpringBootTest(properties = { "spring.cloud.gateway.proxy.skipped=host" }, - webEnvironment = WebEnvironment.RANDOM_PORT) +@SpringBootTest(properties = { "spring.cloud.gateway.proxy.skipped=host" }, webEnvironment = WebEnvironment.RANDOM_PORT) @ContextConfiguration(classes = TestApplication.class) @DirtiesContext public class ProductionConfigurationTests { @@ -122,9 +121,9 @@ public class ProductionConfigurationTests { @Test public void postJsonWithWhitespace() { var json = """ - { - "foo": "bar" - }"""; + { + "foo": "bar" + }"""; var headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); @@ -369,8 +368,7 @@ public class ProductionConfigurationTests { } @PostMapping("/proxy/checkContentLength") - public Mono> checkContentLength( - ProxyExchange proxy) { + public Mono> checkContentLength(ProxyExchange proxy) { return proxy.uri(home.toString() + "/checkContentLength").post(); } @@ -430,8 +428,9 @@ public class ProductionConfigurationTests { } @PostMapping("/checkContentLength") - public ResponseEntity checkContentLength(@RequestHeader(name = "Content-Length", required = false) Integer contentLength, - @RequestBody String json) { + public ResponseEntity checkContentLength( + @RequestHeader(name = "Content-Length", required = false) Integer contentLength, + @RequestBody String json) { if (contentLength != null && contentLength != json.length()) { return ResponseEntity.badRequest().build(); }