From 189c0721c20713a220ad326e5f6870bd5434133c Mon Sep 17 00:00:00 2001 From: Ryan Baxter Date: Thu, 1 Jul 2021 17:36:04 -0400 Subject: [PATCH 1/5] Cherry pick ad9e361 --- .../SecureHeadersGatewayFilterFactory.java | 65 ++++++++++--------- ...ecureHeadersGatewayFilterFactoryTests.java | 15 +++++ ...eHeadersGatewayFilterFactoryUnitTests.java | 39 +++++++++-- .../test/HttpBinCompatibleController.java | 11 ++++ 4 files changed, 93 insertions(+), 37 deletions(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactory.java index 3f755b11..ab151592 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactory.java @@ -92,44 +92,47 @@ public class SecureHeadersGatewayFilterFactory List disabled = properties.getDisable(); Config config = originalConfig.withDefaults(properties); + return chain.filter(exchange).then(Mono.fromRunnable(() -> { + if (isEnabled(disabled, X_XSS_PROTECTION_HEADER)) { + headers.addIfAbsent(X_XSS_PROTECTION_HEADER, + config.getXssProtectionHeader()); + } - if (isEnabled(disabled, X_XSS_PROTECTION_HEADER)) { - headers.add(X_XSS_PROTECTION_HEADER, config.getXssProtectionHeader()); - } + if (isEnabled(disabled, STRICT_TRANSPORT_SECURITY_HEADER)) { + headers.addIfAbsent(STRICT_TRANSPORT_SECURITY_HEADER, + config.getStrictTransportSecurity()); + } - if (isEnabled(disabled, STRICT_TRANSPORT_SECURITY_HEADER)) { - headers.add(STRICT_TRANSPORT_SECURITY_HEADER, - config.getStrictTransportSecurity()); - } + if (isEnabled(disabled, X_FRAME_OPTIONS_HEADER)) { + headers.addIfAbsent(X_FRAME_OPTIONS_HEADER, + config.getFrameOptions()); + } - if (isEnabled(disabled, X_FRAME_OPTIONS_HEADER)) { - headers.add(X_FRAME_OPTIONS_HEADER, config.getFrameOptions()); - } + if (isEnabled(disabled, X_CONTENT_TYPE_OPTIONS_HEADER)) { + headers.addIfAbsent(X_CONTENT_TYPE_OPTIONS_HEADER, + config.getContentTypeOptions()); + } - if (isEnabled(disabled, X_CONTENT_TYPE_OPTIONS_HEADER)) { - headers.add(X_CONTENT_TYPE_OPTIONS_HEADER, - config.getContentTypeOptions()); - } + if (isEnabled(disabled, REFERRER_POLICY_HEADER)) { + headers.addIfAbsent(REFERRER_POLICY_HEADER, + config.getReferrerPolicy()); + } - if (isEnabled(disabled, REFERRER_POLICY_HEADER)) { - headers.add(REFERRER_POLICY_HEADER, config.getReferrerPolicy()); - } + if (isEnabled(disabled, CONTENT_SECURITY_POLICY_HEADER)) { + headers.addIfAbsent(CONTENT_SECURITY_POLICY_HEADER, + config.getContentSecurityPolicy()); + } - if (isEnabled(disabled, CONTENT_SECURITY_POLICY_HEADER)) { - headers.add(CONTENT_SECURITY_POLICY_HEADER, - config.getContentSecurityPolicy()); - } + if (isEnabled(disabled, X_DOWNLOAD_OPTIONS_HEADER)) { + headers.addIfAbsent(X_DOWNLOAD_OPTIONS_HEADER, + config.getDownloadOptions()); + } - if (isEnabled(disabled, X_DOWNLOAD_OPTIONS_HEADER)) { - headers.add(X_DOWNLOAD_OPTIONS_HEADER, config.getDownloadOptions()); - } - - if (isEnabled(disabled, X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER)) { - headers.add(X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER, - config.getPermittedCrossDomainPolicies()); - } - - return chain.filter(exchange); + if (isEnabled(disabled, X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER)) { + headers.addIfAbsent(X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER, + config.getPermittedCrossDomainPolicies()); + } + })); } @Override diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryTests.java index 1ec2cae5..afac7f06 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryTests.java @@ -28,6 +28,7 @@ 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.http.MediaType; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.web.reactive.function.client.ClientResponse; @@ -78,6 +79,20 @@ public class SecureHeadersGatewayFilterFactoryTests extends BaseWebClientTests { }).expectComplete().verify(DURATION); } + @Test + public void addsSecureHeadersAfterResponseIsReceived() { + Mono result = webClient.patch().uri("/headers") + .header("Host", "www.secureheaders.org") + .contentType(MediaType.APPLICATION_JSON) + .bodyValue("{ \"X-Frame-Options\": \"sameorigin\" }").exchange(); + + StepVerifier.create(result).consumeNextWith(response -> { + assertThat(response.statusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.headers().header(X_FRAME_OPTIONS_HEADER)) + .containsOnly("sameorigin"); + }).expectComplete().verify(DURATION); + } + @EnableAutoConfiguration @SpringBootConfiguration @Import(DefaultTestConfig.class) diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryUnitTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryUnitTests.java index 41cbf7ad..3b1346d7 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryUnitTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryUnitTests.java @@ -73,9 +73,8 @@ public class SecureHeadersGatewayFilterFactoryUnitTests { new SecureHeadersProperties()); filter = filterFactory.apply(new Config()); - filter.filter(exchange, filterChain); - - ServerHttpResponse response = captor.getValue().getResponse(); + filter.filter(exchange, filterChain).block(); + ServerHttpResponse response = exchange.getResponse(); assertThat(response.getHeaders()).containsKeys(X_XSS_PROTECTION_HEADER, STRICT_TRANSPORT_SECURITY_HEADER, X_FRAME_OPTIONS_HEADER, X_CONTENT_TYPE_OPTIONS_HEADER, REFERRER_POLICY_HEADER, @@ -95,7 +94,7 @@ public class SecureHeadersGatewayFilterFactoryUnitTests { properties); filter = filterFactory.apply(new Config()); - filter.filter(exchange, filterChain); + filter.filter(exchange, filterChain).block(); ServerHttpResponse response = captor.getValue().getResponse(); assertThat(response.getHeaders()).doesNotContainKeys(X_XSS_PROTECTION_HEADER, @@ -116,9 +115,9 @@ public class SecureHeadersGatewayFilterFactoryUnitTests { config.setReferrerPolicy("referrer"); filter = filterFactory.apply(config); - filter.filter(exchange, filterChain); + filter.filter(exchange, filterChain).block(); - ServerHttpResponse response = captor.getValue().getResponse(); + ServerHttpResponse response = exchange.getResponse(); assertThat(response.getHeaders()).containsKeys(X_XSS_PROTECTION_HEADER, STRICT_TRANSPORT_SECURITY_HEADER, X_FRAME_OPTIONS_HEADER, X_CONTENT_TYPE_OPTIONS_HEADER, REFERRER_POLICY_HEADER, @@ -145,6 +144,34 @@ public class SecureHeadersGatewayFilterFactoryUnitTests { } + @Test + public void doesNotDuplicateHeaders() { + String originalHeaderValue = "original-header-value"; + SecureHeadersGatewayFilterFactory filterFactory = new SecureHeadersGatewayFilterFactory( + new SecureHeadersProperties()); + Config config = new Config(); + + String[] headers = { X_XSS_PROTECTION_HEADER, STRICT_TRANSPORT_SECURITY_HEADER, + X_FRAME_OPTIONS_HEADER, X_CONTENT_TYPE_OPTIONS_HEADER, + REFERRER_POLICY_HEADER, CONTENT_SECURITY_POLICY_HEADER, + X_DOWNLOAD_OPTIONS_HEADER, X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER }; + + for (String header : headers) { + filter = filterFactory.apply(config); + + MockServerHttpRequest request = MockServerHttpRequest.get("http://localhost") + .build(); + exchange = MockServerWebExchange.from(request); + exchange.getResponse().getHeaders().set(header, originalHeaderValue); + + filter.filter(exchange, filterChain).block(); + + ServerHttpResponse response = captor.getValue().getResponse(); + assertThat(response.getHeaders().get(header)) + .containsOnly(originalHeaderValue); + } + } + @Test public void toStringFormat() { GatewayFilter filter = new SecureHeadersGatewayFilterFactory( diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/HttpBinCompatibleController.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/HttpBinCompatibleController.java index f915a8a9..3d9998d8 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/HttpBinCompatibleController.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/HttpBinCompatibleController.java @@ -80,6 +80,17 @@ public class HttpBinCompatibleController { return result; } + @RequestMapping(path = "/headers", method = RequestMethod.PATCH) + public ResponseEntity> headersPatch(ServerWebExchange exchange, + @RequestBody Map headersToAdd) { + Map result = new HashMap<>(); + result.put("headers", getHeaders(exchange)); + ResponseEntity.BodyBuilder responseEntity = ResponseEntity.status(HttpStatus.OK); + headersToAdd.forEach(responseEntity::header); + + return responseEntity.body(result); + } + @RequestMapping(path = "/delay/{sec}", produces = MediaType.APPLICATION_JSON_VALUE) public Mono> get(ServerWebExchange exchange, @PathVariable int sec) throws InterruptedException { From 907119dfa38ffc1734a6e898935c63b389d995f7 Mon Sep 17 00:00:00 2001 From: Olga Maciaszek-Sharma Date: Fri, 2 Jul 2021 19:00:46 +0200 Subject: [PATCH 2/5] Fix 2214 hoxton (#2285) --- .../config/GatewayRedisAutoConfiguration.java | 3 +-- .../headers/ForwardedHeadersFilter.java | 15 ++++++++++-- .../headers/ForwardedHeadersFilterTests.java | 24 +++++++++++++++++++ 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayRedisAutoConfiguration.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayRedisAutoConfiguration.java index 78ee06ad..e912d1c9 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayRedisAutoConfiguration.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayRedisAutoConfiguration.java @@ -44,8 +44,7 @@ import org.springframework.web.reactive.DispatcherHandler; @AutoConfigureBefore(GatewayAutoConfiguration.class) @ConditionalOnBean(ReactiveRedisTemplate.class) @ConditionalOnClass({ RedisTemplate.class, DispatcherHandler.class }) -@ConditionalOnProperty(name = "spring.cloud.gateway.redis.enabled", - matchIfMissing = true) +@ConditionalOnProperty(name = "spring.cloud.gateway.redis.enabled", matchIfMissing = true) class GatewayRedisAutoConfiguration { @Bean diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java index 6f24c512..04592e28 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java @@ -16,6 +16,8 @@ package org.springframework.cloud.gateway.filter.headers; +import java.net.Inet6Address; +import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.URI; import java.util.ArrayList; @@ -120,8 +122,17 @@ public class ForwardedHeadersFilter implements HttpHeadersFilter, Ordered { if (remoteAddress != null) { // If remoteAddress is unresolved, calling getHostAddress() would cause a // NullPointerException. - String forValue = remoteAddress.isUnresolved() ? remoteAddress.getHostName() - : remoteAddress.getAddress().getHostAddress(); + String forValue; + if (remoteAddress.isUnresolved()) { + forValue = remoteAddress.getHostName(); + } + else { + InetAddress address = remoteAddress.getAddress(); + forValue = remoteAddress.getAddress().getHostAddress(); + if (address instanceof Inet6Address) { + forValue = "[" + forValue + "]"; + } + } int port = remoteAddress.getPort(); if (port >= 0) { forValue = forValue + ":" + port; diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java index c7e8e9e4..4d6b0104 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java @@ -131,6 +131,30 @@ public class ForwardedHeadersFilterTests { .containsEntry("for", "\"10.0.0.1:80\""); } + @Test + public void correctIPv6RemoteAddressMapping() throws UnknownHostException { + MockServerHttpRequest request = MockServerHttpRequest.get("http://localhost/get") + .remoteAddress(new InetSocketAddress( + InetAddress.getByName("2001:db8:cafe:0:0:0:0:17"), 80)) + .header(HttpHeaders.HOST, "myhost").build(); + + ForwardedHeadersFilter filter = new ForwardedHeadersFilter(); + + HttpHeaders headers = filter.filter(request.getHeaders(), + MockServerWebExchange.from(request)); + + assertThat(headers.get(FORWARDED_HEADER)).hasSize(1); + + List forwardeds = ForwardedHeadersFilter + .parse(headers.get(FORWARDED_HEADER)); + + assertThat(forwardeds).hasSize(1); + Forwarded forwarded = forwardeds.get(0); + + assertThat(forwarded.getValues()).containsEntry("for", + "\"[2001:db8:cafe:0:0:0:0:17]:80\""); + } + @Test public void unresolvedRemoteAddressFallsBackToHostName() throws UnknownHostException { MockServerHttpRequest request = MockServerHttpRequest.get("http://localhost/get") From c87602f09e53fb9de085488c60a32e5d3b3638b0 Mon Sep 17 00:00:00 2001 From: Olga MaciaszekSharma Date: Fri, 2 Jul 2021 19:03:05 +0200 Subject: [PATCH 3/5] Revert "Fix 2214 hoxton (#2285)" This reverts commit 907119dfa38ffc1734a6e898935c63b389d995f7. --- .../config/GatewayRedisAutoConfiguration.java | 3 ++- .../headers/ForwardedHeadersFilter.java | 15 ++---------- .../headers/ForwardedHeadersFilterTests.java | 24 ------------------- 3 files changed, 4 insertions(+), 38 deletions(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayRedisAutoConfiguration.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayRedisAutoConfiguration.java index e912d1c9..78ee06ad 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayRedisAutoConfiguration.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayRedisAutoConfiguration.java @@ -44,7 +44,8 @@ import org.springframework.web.reactive.DispatcherHandler; @AutoConfigureBefore(GatewayAutoConfiguration.class) @ConditionalOnBean(ReactiveRedisTemplate.class) @ConditionalOnClass({ RedisTemplate.class, DispatcherHandler.class }) -@ConditionalOnProperty(name = "spring.cloud.gateway.redis.enabled", matchIfMissing = true) +@ConditionalOnProperty(name = "spring.cloud.gateway.redis.enabled", + matchIfMissing = true) class GatewayRedisAutoConfiguration { @Bean diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java index 04592e28..6f24c512 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java @@ -16,8 +16,6 @@ package org.springframework.cloud.gateway.filter.headers; -import java.net.Inet6Address; -import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.URI; import java.util.ArrayList; @@ -122,17 +120,8 @@ public class ForwardedHeadersFilter implements HttpHeadersFilter, Ordered { if (remoteAddress != null) { // If remoteAddress is unresolved, calling getHostAddress() would cause a // NullPointerException. - String forValue; - if (remoteAddress.isUnresolved()) { - forValue = remoteAddress.getHostName(); - } - else { - InetAddress address = remoteAddress.getAddress(); - forValue = remoteAddress.getAddress().getHostAddress(); - if (address instanceof Inet6Address) { - forValue = "[" + forValue + "]"; - } - } + String forValue = remoteAddress.isUnresolved() ? remoteAddress.getHostName() + : remoteAddress.getAddress().getHostAddress(); int port = remoteAddress.getPort(); if (port >= 0) { forValue = forValue + ":" + port; diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java index 4d6b0104..c7e8e9e4 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java @@ -131,30 +131,6 @@ public class ForwardedHeadersFilterTests { .containsEntry("for", "\"10.0.0.1:80\""); } - @Test - public void correctIPv6RemoteAddressMapping() throws UnknownHostException { - MockServerHttpRequest request = MockServerHttpRequest.get("http://localhost/get") - .remoteAddress(new InetSocketAddress( - InetAddress.getByName("2001:db8:cafe:0:0:0:0:17"), 80)) - .header(HttpHeaders.HOST, "myhost").build(); - - ForwardedHeadersFilter filter = new ForwardedHeadersFilter(); - - HttpHeaders headers = filter.filter(request.getHeaders(), - MockServerWebExchange.from(request)); - - assertThat(headers.get(FORWARDED_HEADER)).hasSize(1); - - List forwardeds = ForwardedHeadersFilter - .parse(headers.get(FORWARDED_HEADER)); - - assertThat(forwardeds).hasSize(1); - Forwarded forwarded = forwardeds.get(0); - - assertThat(forwarded.getValues()).containsEntry("for", - "\"[2001:db8:cafe:0:0:0:0:17]:80\""); - } - @Test public void unresolvedRemoteAddressFallsBackToHostName() throws UnknownHostException { MockServerHttpRequest request = MockServerHttpRequest.get("http://localhost/get") From 8f8bc9e58a7a5120bfdc09503905b84546e41918 Mon Sep 17 00:00:00 2001 From: hhwidera Date: Fri, 16 Apr 2021 16:57:09 +0200 Subject: [PATCH 4/5] fix problem with missing '[' and ']' around IPv6 address. See https://tools.ietf.org/html/rfc7239 --- .../headers/ForwardedHeadersFilter.java | 14 +++++++++++-- .../headers/ForwardedHeadersFilterTests.java | 20 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java index 6f24c512..ab00f643 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java @@ -16,6 +16,8 @@ package org.springframework.cloud.gateway.filter.headers; +import java.net.Inet6Address; +import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.URI; import java.util.ArrayList; @@ -120,8 +122,16 @@ public class ForwardedHeadersFilter implements HttpHeadersFilter, Ordered { if (remoteAddress != null) { // If remoteAddress is unresolved, calling getHostAddress() would cause a // NullPointerException. - String forValue = remoteAddress.isUnresolved() ? remoteAddress.getHostName() - : remoteAddress.getAddress().getHostAddress(); + String forValue; + if (remoteAddress.isUnresolved()) { + forValue = remoteAddress.getHostName(); + } else { + InetAddress address = remoteAddress.getAddress(); + forValue = remoteAddress.getAddress().getHostAddress(); + if (address instanceof Inet6Address) { + forValue = "[" + forValue + "]"; + } + } int port = remoteAddress.getPort(); if (port >= 0) { forValue = forValue + ":" + port; diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java index c7e8e9e4..677077e7 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java @@ -131,6 +131,26 @@ public class ForwardedHeadersFilterTests { .containsEntry("for", "\"10.0.0.1:80\""); } + @Test + public void correctIPv6RemoteAddressMapping() throws UnknownHostException { + MockServerHttpRequest request = MockServerHttpRequest.get("http://localhost/get") + .remoteAddress(new InetSocketAddress(InetAddress.getByName("2001:db8:cafe:0:0:0:0:17"), 80)) + .header(HttpHeaders.HOST, "myhost").build(); + + ForwardedHeadersFilter filter = new ForwardedHeadersFilter(); + + HttpHeaders headers = filter.filter(request.getHeaders(), MockServerWebExchange.from(request)); + + assertThat(headers.get(FORWARDED_HEADER)).hasSize(1); + + List forwardeds = ForwardedHeadersFilter.parse(headers.get(FORWARDED_HEADER)); + + assertThat(forwardeds).hasSize(1); + Forwarded forwarded = forwardeds.get(0); + + assertThat(forwarded.getValues()).containsEntry("for", "\"[2001:db8:cafe:0:0:0:0:17]:80\""); + } + @Test public void unresolvedRemoteAddressFallsBackToHostName() throws UnknownHostException { MockServerHttpRequest request = MockServerHttpRequest.get("http://localhost/get") From 47595a7e3a6fd9da19664c4facd639bd363324d7 Mon Sep 17 00:00:00 2001 From: Olga MaciaszekSharma Date: Fri, 2 Jul 2021 19:05:35 +0200 Subject: [PATCH 5/5] Reformat. --- .../config/GatewayRedisAutoConfiguration.java | 3 +-- .../filter/headers/ForwardedHeadersFilter.java | 3 ++- .../filter/headers/ForwardedHeadersFilterTests.java | 12 ++++++++---- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayRedisAutoConfiguration.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayRedisAutoConfiguration.java index 78ee06ad..e912d1c9 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayRedisAutoConfiguration.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayRedisAutoConfiguration.java @@ -44,8 +44,7 @@ import org.springframework.web.reactive.DispatcherHandler; @AutoConfigureBefore(GatewayAutoConfiguration.class) @ConditionalOnBean(ReactiveRedisTemplate.class) @ConditionalOnClass({ RedisTemplate.class, DispatcherHandler.class }) -@ConditionalOnProperty(name = "spring.cloud.gateway.redis.enabled", - matchIfMissing = true) +@ConditionalOnProperty(name = "spring.cloud.gateway.redis.enabled", matchIfMissing = true) class GatewayRedisAutoConfiguration { @Bean diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java index ab00f643..04592e28 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java @@ -125,7 +125,8 @@ public class ForwardedHeadersFilter implements HttpHeadersFilter, Ordered { String forValue; if (remoteAddress.isUnresolved()) { forValue = remoteAddress.getHostName(); - } else { + } + else { InetAddress address = remoteAddress.getAddress(); forValue = remoteAddress.getAddress().getHostAddress(); if (address instanceof Inet6Address) { diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java index 677077e7..4d6b0104 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilterTests.java @@ -134,21 +134,25 @@ public class ForwardedHeadersFilterTests { @Test public void correctIPv6RemoteAddressMapping() throws UnknownHostException { MockServerHttpRequest request = MockServerHttpRequest.get("http://localhost/get") - .remoteAddress(new InetSocketAddress(InetAddress.getByName("2001:db8:cafe:0:0:0:0:17"), 80)) + .remoteAddress(new InetSocketAddress( + InetAddress.getByName("2001:db8:cafe:0:0:0:0:17"), 80)) .header(HttpHeaders.HOST, "myhost").build(); ForwardedHeadersFilter filter = new ForwardedHeadersFilter(); - HttpHeaders headers = filter.filter(request.getHeaders(), MockServerWebExchange.from(request)); + HttpHeaders headers = filter.filter(request.getHeaders(), + MockServerWebExchange.from(request)); assertThat(headers.get(FORWARDED_HEADER)).hasSize(1); - List forwardeds = ForwardedHeadersFilter.parse(headers.get(FORWARDED_HEADER)); + List forwardeds = ForwardedHeadersFilter + .parse(headers.get(FORWARDED_HEADER)); assertThat(forwardeds).hasSize(1); Forwarded forwarded = forwardeds.get(0); - assertThat(forwarded.getValues()).containsEntry("for", "\"[2001:db8:cafe:0:0:0:0:17]:80\""); + assertThat(forwarded.getValues()).containsEntry("for", + "\"[2001:db8:cafe:0:0:0:0:17]:80\""); } @Test