Commit 40361f1b by Dave Syer

Add whitelist hosts and sensitive headers

parent 17eb2f8d
......@@ -1227,6 +1227,15 @@ span all services and supersede any other route specification.
This means that all calls such as "/myusers/101" will be forwarded to "/101" on the "users" service.
But calls including "/admin/" will not resolve.
=== Sensitive Headers
It's OK to share headers between services in the same system, but you
probably don't want sensitive headers leaking downstream into external
servers. Thus if you use an explicit URL in a route configuration (as
opposed to a service id), then you can also specify a list of
sensitive headers and a whitelist of host patterns to not receive
those headers.
=== Strangulation Patterns and Local Forwards
A common pattern when migrating an existing application or API is to
......
......@@ -19,8 +19,10 @@ package org.springframework.cloud.netflix.zuul.filters;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
......@@ -37,6 +39,7 @@ import org.springframework.boot.actuate.trace.TraceRepository;
import org.springframework.http.HttpHeaders;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.PatternMatchUtils;
import org.springframework.web.util.UriTemplate;
import org.springframework.web.util.UriUtils;
import org.springframework.web.util.WebUtils;
......@@ -65,8 +68,20 @@ public class ProxyRequestHelper {
private Set<String> ignoredHeaders = new LinkedHashSet<>();
private Set<String> sensitiveHeaders = new LinkedHashSet<>();
private Set<String> whitelistHosts = new LinkedHashSet<>();
public void setWhitelistHosts(Set<String> whitelistHosts) {
this.whitelistHosts.addAll(whitelistHosts);
}
public void setSensitiveHeaders(Set<String> sensitiveHeaders) {
this.sensitiveHeaders.addAll(sensitiveHeaders);
}
public void setIgnoredHeaders(Set<String> ignoredHeaders) {
this.ignoredHeaders = ignoredHeaders;
this.ignoredHeaders.addAll(ignoredHeaders);
}
public void setTraces(TraceRepository traces) {
......@@ -182,11 +197,28 @@ public class ProxyRequestHelper {
for (String name : this.ignoredHeaders) {
set.add(name.toLowerCase());
}
for (String name : getSensitiveHeaders(ctx)) {
set.add(name.toLowerCase());
}
for (String name : names) {
set.add(name.toLowerCase());
}
}
private Collection<String> getSensitiveHeaders(RequestContext ctx) {
URL uri = ctx.getRouteHost();
if (uri == null) {
return Collections.emptySet();
}
String host;
host = uri.getHost();
if (PatternMatchUtils.simpleMatch(this.whitelistHosts.toArray(new String[0]),
host)) {
return this.sensitiveHeaders;
}
return Collections.emptySet();
}
public boolean isIncludedHeader(String headerName) {
String name = headerName.toLowerCase();
RequestContext ctx = RequestContext.getCurrentContext();
......
......@@ -66,6 +66,8 @@ public class ZuulProperties {
private Set<String> ignoredHeaders = new LinkedHashSet<>();
private Sensitive sensitive = new Sensitive();
private String servletPath = "/zuul";
private boolean ignoreLocalService = true;
......@@ -106,6 +108,21 @@ public class ZuulProperties {
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Sensitive {
/**
* Headers that are considered sensitive, and not passed on through a proxy.
*/
private Set<String> headers = new LinkedHashSet<>(Arrays.asList("Cookie"));
/**
* Hostname (patterns) that are considered safe and can receive sensitive headers
* when a route is specified as a URL.
*/
private Set<String> whitelist = new LinkedHashSet<>(Arrays.asList("localhost"));
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class ZuulRoute {
private String id;
......
......@@ -209,9 +209,10 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
.build();
this.connectionManager = new PoolingHttpClientConnectionManager(registry);
this.connectionManager.setMaxTotal(hostProperties.getMaxTotalConnections());
this.connectionManager
.setDefaultMaxPerRoute(hostProperties.getMaxPerRouteConnections());
.setMaxTotal(this.hostProperties.getMaxTotalConnections());
this.connectionManager.setDefaultMaxPerRoute(
this.hostProperties.getMaxPerRouteConnections());
return this.connectionManager;
}
catch (Exception ex) {
......
......@@ -17,10 +17,9 @@
package org.springframework.cloud.netflix.zuul.filters;
import java.io.IOException;
import java.util.Collection;
import java.net.URL;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.Before;
import org.junit.Test;
......@@ -28,7 +27,6 @@ import org.mockito.Mock;
import org.springframework.boot.actuate.trace.InMemoryTraceRepository;
import org.springframework.boot.actuate.trace.Trace;
import org.springframework.boot.actuate.trace.TraceRepository;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.http.HttpHeaders;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
......@@ -163,7 +161,7 @@ public class ProxyRequestHelperTests {
}
@Test
public void getQueryString(){
public void getQueryString() {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("a", "1234");
params.add("b", "5678");
......@@ -174,7 +172,7 @@ public class ProxyRequestHelperTests {
}
@Test
public void getQueryStringWithEmptyParam(){
public void getQueryStringWithEmptyParam() {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("wsdl", "");
......@@ -182,4 +180,36 @@ public class ProxyRequestHelperTests {
assertThat(queryString, is("?wsdl"));
}
@Test
public void ignoreSensitiveHeadersMatchingHost() throws Exception {
ProxyRequestHelper helper = new ProxyRequestHelper();
helper.setSensitiveHeaders(Collections.singleton("Cookie"));
helper.setWhitelistHosts(Collections.singleton("*"));
RequestContext context = RequestContext.getCurrentContext();
context.setRouteHost(new URL("http://example.com"));
helper.addIgnoredHeaders();
assertThat(helper.isIncludedHeader("Cookie"), is(false));
}
@Test
public void ignoreSensitiveHeadersNotMatching() throws Exception {
ProxyRequestHelper helper = new ProxyRequestHelper();
helper.setSensitiveHeaders(Collections.singleton("Cookie"));
helper.setWhitelistHosts(Collections.singleton("foo.com"));
RequestContext context = RequestContext.getCurrentContext();
context.setRouteHost(new URL("http://example.com"));
helper.addIgnoredHeaders();
assertThat(helper.isIncludedHeader("Cookie"), is(true));
}
@Test
public void ignoreSensitiveHeadersWhenNoRoute() throws Exception {
ProxyRequestHelper helper = new ProxyRequestHelper();
helper.setSensitiveHeaders(Collections.singleton("Cookie"));
helper.setWhitelistHosts(Collections.singleton("foo.com"));
RequestContext context = RequestContext.getCurrentContext();
helper.addIgnoredHeaders();
assertThat(helper.isIncludedHeader("Cookie"), is(true));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment