Allows to override default set of sensitive headers in WebFlux ProxyExchange

Fixes gh-1800
Fixes gh-1974
This commit is contained in:
Dennis Menge
2020-10-07 17:00:22 +02:00
committed by spencergibb
parent b528c9dfc7
commit 894402aab3
4 changed files with 80 additions and 15 deletions

View File

@@ -32,6 +32,7 @@ import java.util.List;
import java.util.Set;
import java.util.Vector;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
@@ -215,6 +216,8 @@ public class ProxyExchange<T> {
if (this.sensitive == null) {
this.sensitive = new HashSet<>();
}
this.sensitive.clear();
for (String name : names) {
this.sensitive.add(name.toLowerCase());
}
@@ -342,20 +345,19 @@ public class ProxyExchange<T> {
}
private BodyBuilder headers(BodyBuilder builder) {
Set<String> sensitive = this.sensitive;
if (sensitive == null) {
sensitive = DEFAULT_SENSITIVE;
}
proxy();
for (String name : headers.keySet()) {
if (sensitive.contains(name.toLowerCase())) {
continue;
}
for (String name : filterHeaderKeys(headers)) {
builder.header(name, headers.get(name).toArray(new String[0]));
}
return builder;
}
private Set<String> filterHeaderKeys(HttpHeaders headers) {
final Set<String> sensitiveHeaders = this.sensitive != null ? this.sensitive : DEFAULT_SENSITIVE;
return headers.keySet().stream().filter(header -> !sensitiveHeaders.contains(header.toLowerCase()))
.collect(Collectors.toSet());
}
private void proxy() {
try {
URI uri = new URI(webRequest.getNativeRequest(HttpServletRequest.class).getRequestURL().toString());

View File

@@ -236,6 +236,29 @@ public class ProductionConfigurationTests {
assertThat(deleteResponse.getBody().get("deleted")).isEqualToComparingFieldByField(foo);
}
@Test
@SuppressWarnings({ "Duplicates", "unchecked" })
public void testSensitiveHeadersOverride() throws Exception {
Map<String, List<String>> headers = rest
.exchange(
RequestEntity.get(rest.getRestTemplate().getUriTemplateHandler().expand("/proxy/headers"))
.header("foo", "bar").header("abc", "xyz").header("cookie", "monster").build(),
Map.class)
.getBody();
assertThat(headers).doesNotContainKey("foo").doesNotContainKey("hello").containsKeys("bar", "abc");
assertThat(headers.get("cookie")).containsOnly("monster");
}
@Test
public void testSensitiveHeadersDefault() throws Exception {
Map<String, List<String>> headers = rest.exchange(RequestEntity
.get(rest.getRestTemplate().getUriTemplateHandler().expand("/proxy/sensitive-headers-default"))
.header("cookie", "monster").build(), Map.class).getBody();
assertThat(headers).doesNotContainKey("cookie");
}
@Test
@SuppressWarnings({ "Duplicates", "unchecked" })
public void headers() throws Exception {
@@ -406,8 +429,16 @@ public class ProductionConfigurationTests {
@GetMapping("/proxy/headers")
@SuppressWarnings("Duplicates")
public ResponseEntity<Map<String, List<String>>> headers(ProxyExchange<Map<String, List<String>>> proxy) {
proxy.sensitive("foo");
proxy.sensitive("hello");
proxy.sensitive("foo", "hello");
proxy.header("bar", "hello");
proxy.header("abc", "123");
proxy.header("hello", "world");
return proxy.uri(home.toString() + "/headers").get();
}
@GetMapping("/proxy/sensitive-headers-default")
public ResponseEntity<Map<String, List<String>>> defaultSensitiveHeaders(
ProxyExchange<Map<String, List<String>>> proxy) {
proxy.header("bar", "hello");
proxy.header("abc", "123");
proxy.header("hello", "world");

View File

@@ -140,8 +140,6 @@ public class ProxyExchange<T> {
this.bindingContext = bindingContext;
this.responseType = type;
this.rest = rest;
this.sensitive = new HashSet<>(DEFAULT_SENSITIVE.size());
this.sensitive.addAll(DEFAULT_SENSITIVE);
this.httpMethod = exchange.getRequest().getMethod();
}
@@ -206,6 +204,8 @@ public class ProxyExchange<T> {
if (this.sensitive == null) {
this.sensitive = new HashSet<>();
}
this.sensitive.clear();
for (String name : names) {
this.sensitive.add(name.toLowerCase());
}
@@ -376,7 +376,8 @@ public class ProxyExchange<T> {
}
private Set<String> filterHeaderKeys(HttpHeaders headers) {
return headers.keySet().stream().filter(header -> !sensitive.contains(header.toLowerCase()))
final Set<String> sensitiveHeaders = this.sensitive != null ? this.sensitive : DEFAULT_SENSITIVE;
return headers.keySet().stream().filter(header -> !sensitiveHeaders.contains(header.toLowerCase()))
.collect(Collectors.toSet());
}

View File

@@ -174,6 +174,29 @@ public class ProductionConfigurationTests {
.isEqualTo("host=localhost:" + port + ";foobar");
}
@Test
@SuppressWarnings({ "Duplicates", "unchecked" })
public void testSensitiveHeadersOverride() throws Exception {
Map<String, List<String>> headers = rest
.exchange(RequestEntity.get(rest.getRestTemplate().getUriTemplateHandler().expand("/proxy/headers"))
.header("foo", "bar").header("abc", "xyz").header("cookie", "monster").build(), Map.class)
.getBody();
assertThat(headers).doesNotContainKey("foo").doesNotContainKey("hello").containsKeys("bar", "abc");
assertThat(headers.get("cookie")).containsOnly("monster");
}
@Test
public void testSensitiveHeadersDefault() throws Exception {
Map<String, List<String>> headers = rest
.exchange(RequestEntity.get(rest.getRestTemplate().getUriTemplateHandler().expand("/proxy/sensitive-headers-default"))
.header("cookie", "monster")
.build(), Map.class)
.getBody();
assertThat(headers).doesNotContainKey("cookie");
}
@Test
@SuppressWarnings({ "Duplicates", "unchecked" })
public void headers() throws Exception {
@@ -317,8 +340,16 @@ public class ProductionConfigurationTests {
@GetMapping("/proxy/headers")
public Mono<ResponseEntity<Map<String, List<String>>>> headers(
ProxyExchange<Map<String, List<String>>> proxy) {
proxy.sensitive("foo");
proxy.sensitive("hello");
proxy.sensitive("foo", "hello");
proxy.header("bar", "hello");
proxy.header("abc", "123");
proxy.header("hello", "world");
return proxy.uri(home.toString() + "/headers").get();
}
@GetMapping("/proxy/sensitive-headers-default")
public Mono<ResponseEntity<Map<String, List<String>>>> defaultSensitiveHeaders(
ProxyExchange<Map<String, List<String>>> proxy) {
proxy.header("bar", "hello");
proxy.header("abc", "123");
proxy.header("hello", "world");