You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by pz...@apache.org on 2018/06/21 19:11:12 UTC
knox git commit: Support service role-based whitelist for dispatches
and redirects
Repository: knox
Updated Branches:
refs/heads/master 89bf09f97 -> 8bdd03cd6
Support service role-based whitelist for dispatches and redirects
Project: http://git-wip-us.apache.org/repos/asf/knox/repo
Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/8bdd03cd
Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/8bdd03cd
Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/8bdd03cd
Branch: refs/heads/master
Commit: 8bdd03cd60f44c4c2d3786ccca4dba31aa7361d1
Parents: 89bf09f
Author: Phil Zampino <pz...@apache.org>
Authored: Mon Jun 18 19:36:54 2018 -0400
Committer: Phil Zampino <pz...@apache.org>
Committed: Thu Jun 21 11:52:18 2018 -0700
----------------------------------------------------------------------
gateway-release/home/conf/gateway-site.xml | 13 +-
.../gateway/config/impl/GatewayConfigImpl.java | 21 ++
.../gateway/service/knoxsso/WebSSOResource.java | 9 +-
.../service/knoxsso/WebSSOResourceTest.java | 156 ++++++++++-
.../apache/knox/gateway/SpiGatewayMessages.java | 8 +
.../knox/gateway/config/GatewayConfig.java | 16 ++
.../gateway/dispatch/GatewayDispatchFilter.java | 35 ++-
.../knox/gateway/util/WhitelistUtils.java | 91 +++++++
.../dispatch/GatewayDispatchFilterTest.java | 263 +++++++++++++++++++
.../knox/gateway/util/WhitelistUtilsTest.java | 145 ++++++++++
.../apache/knox/gateway/GatewayTestConfig.java | 9 +
11 files changed, 746 insertions(+), 20 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/knox/blob/8bdd03cd/gateway-release/home/conf/gateway-site.xml
----------------------------------------------------------------------
diff --git a/gateway-release/home/conf/gateway-site.xml b/gateway-release/home/conf/gateway-site.xml
index 64abf16..9894cf1 100644
--- a/gateway-release/home/conf/gateway-site.xml
+++ b/gateway-release/home/conf/gateway-site.xml
@@ -86,7 +86,7 @@ limitations under the License.
</property>
<!-- Knox Admin related config -->
- <property>
+ <property>
<name>gateway.knox.admin.groups</name>
<value>admin</value>
</property>
@@ -128,5 +128,16 @@ limitations under the License.
<name>gateway.group.config.hadoop.security.group.mapping.ldap.search.attr.group.name</name>
<value>cn</value>
</property>
+ <property>
+ <name>gateway.dispatch.whitelist.services</name>
+ <value>DATANODE,HBASEUI,HDFSUI,JOBHISTORYUI,NODEUI,RESOURCEMANAGER,WEBHBASE,WEBHDFS,YARNUI</value>
+ <description>The comma-delimited list of service roles for which the gateway.dispatch.whitelist should be applied.</description>
+ </property>
+
+ <property>
+ <name>gateway.dispatch.whitelist</name>
+ <value></value>
+ <description>The whitelist to be applied for dispatches associated with the service roles specified by gateway.dispatch.whitelist.services.</description>
+ </property>
</configuration>
http://git-wip-us.apache.org/repos/asf/knox/blob/8bdd03cd/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java b/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
index 815bb95..0ff8b22 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
@@ -253,6 +253,9 @@ public class GatewayConfigImpl extends Configuration implements GatewayConfig {
static final String AUTO_DEPLOY_TOPOLOGIES = GATEWAY_CONFIG_FILE_PREFIX + ".auto.deploy.topologies";
static final String DEFAULT_AUTO_DEPLOY_TOPOLOGIES = "manager,admin";
+ static final String DISPATCH_HOST_WHITELIST = GATEWAY_CONFIG_FILE_PREFIX + ".dispatch.whitelist";
+ static final String DISPATCH_HOST_WHITELIST_SERVICES = DISPATCH_HOST_WHITELIST + ".services";
+
private static List<String> DEFAULT_GLOBAL_RULES_SERVICES;
@@ -1089,4 +1092,22 @@ public class GatewayConfigImpl extends Configuration implements GatewayConfig {
return topologyNames;
}
+ public String getDispatchWhitelist() {
+ return get(DISPATCH_HOST_WHITELIST);
+ }
+
+ @Override
+ public List<String> getDispatchWhitelistServices() {
+ List<String> result = new ArrayList<>();
+
+ String serviceList = get(DISPATCH_HOST_WHITELIST_SERVICES);
+ if (serviceList != null) {
+ for (String service : Arrays.asList(serviceList.split(","))) {
+ result.add(service.trim());
+ }
+ }
+
+ return result;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/knox/blob/8bdd03cd/gateway-service-knoxsso/src/main/java/org/apache/knox/gateway/service/knoxsso/WebSSOResource.java
----------------------------------------------------------------------
diff --git a/gateway-service-knoxsso/src/main/java/org/apache/knox/gateway/service/knoxsso/WebSSOResource.java b/gateway-service-knoxsso/src/main/java/org/apache/knox/gateway/service/knoxsso/WebSSOResource.java
index a103dac..2454e41 100644
--- a/gateway-service-knoxsso/src/main/java/org/apache/knox/gateway/service/knoxsso/WebSSOResource.java
+++ b/gateway-service-knoxsso/src/main/java/org/apache/knox/gateway/service/knoxsso/WebSSOResource.java
@@ -48,6 +48,7 @@ import org.apache.knox.gateway.services.security.token.TokenServiceException;
import org.apache.knox.gateway.services.security.token.impl.JWT;
import org.apache.knox.gateway.util.RegExUtils;
import org.apache.knox.gateway.util.Urls;
+import org.apache.knox.gateway.util.WhitelistUtils;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static javax.ws.rs.core.MediaType.APPLICATION_XML;
@@ -66,8 +67,6 @@ public class WebSSOResource {
private static final String ORIGINAL_URL_REQUEST_PARAM = "originalUrl";
private static final String ORIGINAL_URL_COOKIE_NAME = "original-url";
private static final String DEFAULT_SSO_COOKIE_NAME = "hadoop-jwt";
- // default for the whitelist - open up for development - relative paths and localhost only
- private static final String DEFAULT_WHITELIST = "^/.*$;^https?://(localhost|127.0.0.1|0:0:0:0:0:0:0:1|::1):\\d{0,9}/.*$";
private static final long TOKEN_TTL_DEFAULT = 30000L;
static final String RESOURCE_PATH = "/api/v1/websso";
private static KnoxSSOMessages log = MessagesFactory.get( KnoxSSOMessages.class );
@@ -122,8 +121,7 @@ public class WebSSOResource {
whitelist = context.getInitParameter(SSO_COOKIE_TOKEN_WHITELIST_PARAM);
if (whitelist == null) {
- // default to local/relative targets
- whitelist = DEFAULT_WHITELIST;
+ whitelist = WhitelistUtils.getDispatchWhitelist(request);
}
String audiences = context.getInitParameter(SSO_COOKIE_TOKEN_AUDIENCES_PARAM);
@@ -183,7 +181,8 @@ public class WebSSOResource {
log.originalURLNotFound();
throw new WebApplicationException("Original URL not found in the request.", Response.Status.BAD_REQUEST);
}
- boolean validRedirect = RegExUtils.checkWhitelist(whitelist, original);
+
+ boolean validRedirect = (whitelist == null) || whitelist.isEmpty() || RegExUtils.checkWhitelist(whitelist, original);
if (!validRedirect) {
log.whiteListMatchFail(original, whitelist);
throw new WebApplicationException("Original URL not valid according to the configured whitelist.",
http://git-wip-us.apache.org/repos/asf/knox/blob/8bdd03cd/gateway-service-knoxsso/src/test/java/org/apache/knox/gateway/service/knoxsso/WebSSOResourceTest.java
----------------------------------------------------------------------
diff --git a/gateway-service-knoxsso/src/test/java/org/apache/knox/gateway/service/knoxsso/WebSSOResourceTest.java b/gateway-service-knoxsso/src/test/java/org/apache/knox/gateway/service/knoxsso/WebSSOResourceTest.java
index 0eb717e..65b3a26 100644
--- a/gateway-service-knoxsso/src/test/java/org/apache/knox/gateway/service/knoxsso/WebSSOResourceTest.java
+++ b/gateway-service-knoxsso/src/test/java/org/apache/knox/gateway/service/knoxsso/WebSSOResourceTest.java
@@ -17,11 +17,14 @@
*/
package org.apache.knox.gateway.service.knoxsso;
+import org.apache.knox.gateway.config.GatewayConfig;
import org.apache.knox.gateway.util.RegExUtils;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import java.lang.reflect.Field;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
@@ -49,7 +52,6 @@ import org.apache.knox.gateway.services.security.token.JWTokenAuthority;
import org.apache.knox.gateway.services.security.token.TokenServiceException;
import org.apache.knox.gateway.services.security.token.impl.JWT;
import org.apache.knox.gateway.services.security.token.impl.JWTToken;
-import org.apache.knox.gateway.util.RegExUtils;
import org.easymock.EasyMock;
import org.junit.Assert;
import org.junit.BeforeClass;
@@ -96,22 +98,22 @@ public class WebSSOResourceTest {
Assert.assertTrue("Failed to match whitelist", RegExUtils.checkWhitelist(whitelist,
"http://host.example2.com:1234/"));
// fail on missing port
- Assert.assertFalse("Matched whitelist inappropriately", RegExUtils.checkWhitelist(whitelist,
+ assertFalse("Matched whitelist inappropriately", RegExUtils.checkWhitelist(whitelist,
"http://host.example2.com/"));
// fail on invalid port
- Assert.assertFalse("Matched whitelist inappropriately", RegExUtils.checkWhitelist(whitelist,
+ assertFalse("Matched whitelist inappropriately", RegExUtils.checkWhitelist(whitelist,
"http://host.example.com:8081/"));
// fail on alphanumeric port
- Assert.assertFalse("Matched whitelist inappropriately", RegExUtils.checkWhitelist(whitelist,
+ assertFalse("Matched whitelist inappropriately", RegExUtils.checkWhitelist(whitelist,
"http://host.example.com:A080/"));
// fail on invalid hostname/domain
- Assert.assertFalse("Matched whitelist inappropriately", RegExUtils.checkWhitelist(whitelist,
+ assertFalse("Matched whitelist inappropriately", RegExUtils.checkWhitelist(whitelist,
"http://host.example.net:8080/"));
// fail on required port
- Assert.assertFalse("Matched whitelist inappropriately", RegExUtils.checkWhitelist(whitelist,
+ assertFalse("Matched whitelist inappropriately", RegExUtils.checkWhitelist(whitelist,
"http://host.example2.com/"));
// fail on required https
- Assert.assertFalse("Matched whitelist inappropriately", RegExUtils.checkWhitelist(whitelist,
+ assertFalse("Matched whitelist inappropriately", RegExUtils.checkWhitelist(whitelist,
"http://host.example3.com/"));
// match on localhost and port
Assert.assertTrue("Failed to match whitelist", RegExUtils.checkWhitelist(whitelist,
@@ -402,7 +404,6 @@ public class WebSSOResourceTest {
@Test
public void testCustomTTL() throws Exception {
-
ServletContext context = EasyMock.createNiceMock(ServletContext.class);
EasyMock.expect(context.getInitParameter("knoxsso.cookie.name")).andReturn(null);
EasyMock.expect(context.getInitParameter("knoxsso.cookie.secure.only")).andReturn(null);
@@ -572,6 +573,145 @@ public class WebSSOResourceTest {
assertTrue((expiresDate.getTime() - now.getTime()) < 30000L);
}
+ @Test
+ public void testDefaultWhitelistLocalhostByAddress() throws Exception {
+ doTestDefaultLocalhostWhitelist("127.0.0.1");
+ }
+
+ @Test
+ public void testDefaultWhitelistLocalhostByName() throws Exception {
+ doTestDefaultLocalhostWhitelist("localhost");
+ }
+
+ @Test
+ public void testDefaultDomainWhitelist() throws Exception {
+ doTestDefaultDomainWhitelist("knox.test.org");
+ doTestDefaultDomainWhitelist("knox.test.com");
+ }
+
+ private void doTestDefaultLocalhostWhitelist(String localhostId) throws Exception {
+ String whitelistValue = doTestDefaultWhitelist(localhostId);
+ assertTrue(whitelistValue.contains("localhost"));
+ }
+
+ private void doTestDefaultDomainWhitelist(String hostname) throws Exception {
+ String whitelistValue = doTestDefaultWhitelist(hostname);
+ assertTrue(whitelistValue.contains(hostname.substring(hostname.indexOf('.')).replaceAll("\\.", "\\\\.")));
+ }
+
+
+ private String doTestDefaultWhitelist(String hostname) throws Exception {
+ final String testServiceRole = "TEST";
+
+ GatewayConfig config = EasyMock.createNiceMock(GatewayConfig.class);
+ EasyMock.expect(config.getDispatchWhitelistServices()).andReturn(Collections.singletonList(testServiceRole)).anyTimes();
+ EasyMock.expect(config.getDispatchWhitelist()).andReturn(null).anyTimes();
+ EasyMock.replay(config);
+
+ ServletContext context = EasyMock.createNiceMock(ServletContext.class);
+ EasyMock.expect(context.getInitParameter("knoxsso.cookie.name")).andReturn(null);
+ EasyMock.expect(context.getInitParameter("knoxsso.cookie.secure.only")).andReturn(null);
+ EasyMock.expect(context.getInitParameter("knoxsso.cookie.max.age")).andReturn(null);
+ EasyMock.expect(context.getInitParameter("knoxsso.cookie.domain.suffix")).andReturn(null);
+ EasyMock.expect(context.getInitParameter("knoxsso.redirect.whitelist.regex")).andReturn(null);
+ EasyMock.expect(context.getInitParameter("knoxsso.token.audiences")).andReturn(null);
+ EasyMock.expect(context.getInitParameter("knoxsso.token.ttl")).andReturn("60000");
+ EasyMock.expect(context.getInitParameter("knoxsso.enable.session")).andReturn(null);
+ EasyMock.expect(context.getAttribute("org.apache.knox.gateway.config")).andReturn(config).anyTimes();
+
+ HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
+ EasyMock.expect(request.getParameter("originalUrl")).andReturn("http://localhost:9080/service");
+ EasyMock.expect(request.getParameterMap()).andReturn(Collections.<String,String[]>emptyMap());
+ EasyMock.expect(request.getServletContext()).andReturn(context).anyTimes();
+ EasyMock.expect(request.getAttribute("targetServiceRole")).andReturn(testServiceRole).anyTimes();
+ EasyMock.expect(request.getServerName()).andReturn(hostname).anyTimes();
+
+ Principal principal = EasyMock.createNiceMock(Principal.class);
+ EasyMock.expect(principal.getName()).andReturn("alice").anyTimes();
+ EasyMock.expect(request.getUserPrincipal()).andReturn(principal).anyTimes();
+
+ GatewayServices services = EasyMock.createNiceMock(GatewayServices.class);
+ EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services);
+
+ JWTokenAuthority authority = new TestJWTokenAuthority(publicKey, privateKey);
+ EasyMock.expect(services.getService(GatewayServices.TOKEN_SERVICE)).andReturn(authority);
+
+ HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
+ ServletOutputStream outputStream = EasyMock.createNiceMock(ServletOutputStream.class);
+ CookieResponseWrapper responseWrapper = new CookieResponseWrapper(response, outputStream);
+
+ EasyMock.replay(principal, services, context, request);
+
+ WebSSOResource webSSOResponse = new WebSSOResource();
+ webSSOResponse.request = request;
+ webSSOResponse.response = responseWrapper;
+ webSSOResponse.context = context;
+ webSSOResponse.init();
+
+ Field whitelistField = webSSOResponse.getClass().getDeclaredField("whitelist");
+ whitelistField.setAccessible(true);
+ String whitelistValue = (String) whitelistField.get(webSSOResponse);
+ assertNotNull(whitelistValue);
+
+ return whitelistValue;
+ }
+
+ @Test
+ public void testTopologyDefinedWhitelist() throws Exception {
+ final String testServiceRole = "TEST";
+
+ GatewayConfig config = EasyMock.createNiceMock(GatewayConfig.class);
+ EasyMock.expect(config.getDispatchWhitelistServices()).andReturn(Collections.singletonList(testServiceRole)).anyTimes();
+ EasyMock.expect(config.getDispatchWhitelist()).andReturn(null).anyTimes();
+ EasyMock.replay(config);
+
+ ServletContext context = EasyMock.createNiceMock(ServletContext.class);
+ EasyMock.expect(context.getInitParameter("knoxsso.cookie.name")).andReturn(null);
+ EasyMock.expect(context.getInitParameter("knoxsso.cookie.secure.only")).andReturn(null);
+ EasyMock.expect(context.getInitParameter("knoxsso.cookie.max.age")).andReturn(null);
+ EasyMock.expect(context.getInitParameter("knoxsso.cookie.domain.suffix")).andReturn(null);
+ EasyMock.expect(context.getInitParameter("knoxsso.redirect.whitelist.regex")).andReturn("^.*$");
+ EasyMock.expect(context.getInitParameter("knoxsso.token.audiences")).andReturn(null);
+ EasyMock.expect(context.getInitParameter("knoxsso.token.ttl")).andReturn("60000");
+ EasyMock.expect(context.getInitParameter("knoxsso.enable.session")).andReturn(null);
+ EasyMock.expect(context.getAttribute("org.apache.knox.gateway.config")).andReturn(config).anyTimes();
+
+ HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
+ EasyMock.expect(request.getParameter("originalUrl")).andReturn("http://localhost:9080/service");
+ EasyMock.expect(request.getParameterMap()).andReturn(Collections.<String,String[]>emptyMap());
+ EasyMock.expect(request.getServletContext()).andReturn(context).anyTimes();
+ EasyMock.expect(request.getAttribute("targetServiceRole")).andReturn(testServiceRole).anyTimes();
+ EasyMock.expect(request.getServerName()).andReturn("localhost").anyTimes();
+
+ Principal principal = EasyMock.createNiceMock(Principal.class);
+ EasyMock.expect(principal.getName()).andReturn("alice").anyTimes();
+ EasyMock.expect(request.getUserPrincipal()).andReturn(principal).anyTimes();
+
+ GatewayServices services = EasyMock.createNiceMock(GatewayServices.class);
+ EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services);
+
+ JWTokenAuthority authority = new TestJWTokenAuthority(publicKey, privateKey);
+ EasyMock.expect(services.getService(GatewayServices.TOKEN_SERVICE)).andReturn(authority);
+
+ HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
+ ServletOutputStream outputStream = EasyMock.createNiceMock(ServletOutputStream.class);
+ CookieResponseWrapper responseWrapper = new CookieResponseWrapper(response, outputStream);
+
+ EasyMock.replay(principal, services, context, request);
+
+ WebSSOResource webSSOResponse = new WebSSOResource();
+ webSSOResponse.request = request;
+ webSSOResponse.response = responseWrapper;
+ webSSOResponse.context = context;
+ webSSOResponse.init();
+
+ Field whitelistField = webSSOResponse.getClass().getDeclaredField("whitelist");
+ whitelistField.setAccessible(true);
+ String whitelistValue = (String) whitelistField.get(webSSOResponse);
+ assertNotNull(whitelistValue);
+ assertEquals("^.*$", whitelistValue);
+ }
+
/**
* A wrapper for HttpServletResponseWrapper to store the cookies
*/
http://git-wip-us.apache.org/repos/asf/knox/blob/8bdd03cd/gateway-spi/src/main/java/org/apache/knox/gateway/SpiGatewayMessages.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/SpiGatewayMessages.java b/gateway-spi/src/main/java/org/apache/knox/gateway/SpiGatewayMessages.java
index 38e81be..c0ced17 100644
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/SpiGatewayMessages.java
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/SpiGatewayMessages.java
@@ -81,4 +81,12 @@ public interface SpiGatewayMessages {
@Message( level = MessageLevel.ERROR, text = "Error reading Kerberos login configuration {0} : {1}" )
void errorReadingKerberosLoginConfig(String fileName, @StackTrace(level=MessageLevel.ERROR) Exception e);
+ @Message( level = MessageLevel.INFO,
+ text = "Applying a derived dispatch whitelist because none is configured in gateway-site: {0}" )
+ void derivedDispatchWhitelist(final String derivedWhitelist);
+
+ @Message( level = MessageLevel.ERROR,
+ text = "The dispatch to {0} was disallowed because it fails the dispatch whitelist validation. See documentation for dispatch whitelisting." )
+ void dispatchDisallowed(String uri);
+
}
http://git-wip-us.apache.org/repos/asf/knox/blob/8bdd03cd/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java b/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
index 8a43cb7..c5e2337 100644
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
@@ -418,4 +418,20 @@ public interface GatewayConfig {
*/
List<String> getAutoDeployTopologyNames();
+ /*
+ * Get the semicolon-delimited set of regular expressions defining to which hosts Knox will permit requests to be
+ * dispatched.
+ *
+ * @return The whitelist, which will be null if none is configured (in which case, requests to any host are permitted).
+ */
+ String getDispatchWhitelist();
+
+ /**
+ * Get the set of service roles to which the dispatch whitelist will be applied.
+ *
+ * @return The service roles, or an empty list if none are configured.
+ */
+ List<String> getDispatchWhitelistServices();
+
+
}
http://git-wip-us.apache.org/repos/asf/knox/blob/8bdd03cd/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/GatewayDispatchFilter.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/GatewayDispatchFilter.java b/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/GatewayDispatchFilter.java
index 8f3399a..0a993a0 100644
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/GatewayDispatchFilter.java
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/GatewayDispatchFilter.java
@@ -23,6 +23,8 @@ import org.apache.knox.gateway.config.ConfigurationInjectorBuilder;
import org.apache.knox.gateway.i18n.messages.MessagesFactory;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.knox.gateway.util.RegExUtils;
+import org.apache.knox.gateway.util.WhitelistUtils;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
@@ -110,19 +112,40 @@ public class GatewayDispatchFilter extends AbstractGatewayFilter {
protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
String method = request.getMethod().toUpperCase();
Adapter adapter = METHOD_ADAPTERS.get(method);
- if ( adapter != null ) {
- try {
- adapter.doMethod(getDispatch(), request, response);
- } catch ( URISyntaxException e ) {
- throw new ServletException(e);
+ if (adapter != null) {
+ if (isDispatchAllowed(request)) {
+ try {
+ adapter.doMethod(getDispatch(), request, response);
+ } catch (URISyntaxException e) {
+ throw new ServletException(e);
+ }
+ } else {
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST);
}
} else {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
}
}
+ private boolean isDispatchAllowed(HttpServletRequest request) {
+ boolean isAllowed = true;
+
+ String whitelist = WhitelistUtils.getDispatchWhitelist(request);
+ if (whitelist != null) {
+
+ String requestURI = request.getRequestURI();
+
+ isAllowed = RegExUtils.checkWhitelist(whitelist, requestURI);
+ if (!isAllowed) {
+ LOG.dispatchDisallowed(requestURI);
+ }
+ }
+
+ return isAllowed;
+ }
+
private interface Adapter {
- public void doMethod(Dispatch dispatch, HttpServletRequest request, HttpServletResponse response)
+ void doMethod(Dispatch dispatch, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException, URISyntaxException;
}
http://git-wip-us.apache.org/repos/asf/knox/blob/8bdd03cd/gateway-spi/src/main/java/org/apache/knox/gateway/util/WhitelistUtils.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/util/WhitelistUtils.java b/gateway-spi/src/main/java/org/apache/knox/gateway/util/WhitelistUtils.java
new file mode 100644
index 0000000..50795e5
--- /dev/null
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/util/WhitelistUtils.java
@@ -0,0 +1,91 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.apache.knox.gateway.util;
+
+import org.apache.knox.gateway.SpiGatewayMessages;
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class WhitelistUtils {
+
+ static final String LOCALHOST_REGEXP_SEGMENT = "(localhost|127\\.0\\.0\\.1|0:0:0:0:0:0:0:1|::1)";
+
+ static final String LOCALHOST_REGEXP = "^" + LOCALHOST_REGEXP_SEGMENT + "$";
+
+ static final String DEFAULT_DISPATCH_WHITELIST_TEMPLATE = "^/.*$;^https?://%s:[0-9]+/?.*$";
+
+ private static final SpiGatewayMessages LOG = MessagesFactory.get(SpiGatewayMessages.class);
+
+ private static final List<String> DEFAULT_SERVICE_ROLES = Arrays.asList("KNOXSSO");
+
+
+ public static String getDispatchWhitelist(HttpServletRequest request) {
+ String whitelist = null;
+
+ GatewayConfig config = (GatewayConfig) request.getServletContext().getAttribute("org.apache.knox.gateway.config");
+ if (config != null) {
+ List<String> whitelistedServiceRoles = new ArrayList<>();
+ whitelistedServiceRoles.addAll(DEFAULT_SERVICE_ROLES);
+ whitelistedServiceRoles.addAll(config.getDispatchWhitelistServices());
+
+ String serviceRole = (String) request.getAttribute("targetServiceRole");
+ if (whitelistedServiceRoles.contains(serviceRole)) {
+ // Check the whitelist against the URL to be dispatched
+ whitelist = config.getDispatchWhitelist();
+ if (whitelist == null || whitelist.isEmpty()) {
+ whitelist = deriveDefaultDispatchWhitelist(request);
+ LOG.derivedDispatchWhitelist(whitelist);
+ }
+ }
+ }
+
+ return whitelist;
+ }
+
+ private static String deriveDefaultDispatchWhitelist(HttpServletRequest request) {
+ String defaultWhitelist = null;
+
+ String thisHost = request.getHeader("X-Forwarded-Host");
+ if (thisHost == null) {
+ thisHost = request.getServerName();
+ }
+
+ // If the host is not some form of localhost, try to determine its domain
+ if (!thisHost.matches(LOCALHOST_REGEXP)) {
+ int domainIndex = thisHost.indexOf('.');
+ if (domainIndex > 0) {
+ String domain = thisHost.substring(thisHost.indexOf('.'));
+ String domainPattern = ".+" + domain.replaceAll("\\.", "\\\\.");
+ defaultWhitelist = String.format(DEFAULT_DISPATCH_WHITELIST_TEMPLATE, domainPattern);
+ }
+ }
+
+ // If the host is localhost or the domain could not be determined, default to the local/relative whitelist
+ if (defaultWhitelist == null) {
+ defaultWhitelist = String.format(DEFAULT_DISPATCH_WHITELIST_TEMPLATE, LOCALHOST_REGEXP_SEGMENT);
+ }
+
+ return defaultWhitelist;
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/8bdd03cd/gateway-spi/src/test/java/org/apache/knox/gateway/dispatch/GatewayDispatchFilterTest.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/test/java/org/apache/knox/gateway/dispatch/GatewayDispatchFilterTest.java b/gateway-spi/src/test/java/org/apache/knox/gateway/dispatch/GatewayDispatchFilterTest.java
new file mode 100644
index 0000000..0408d79
--- /dev/null
+++ b/gateway-spi/src/test/java/org/apache/knox/gateway/dispatch/GatewayDispatchFilterTest.java
@@ -0,0 +1,263 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.apache.knox.gateway.dispatch;
+
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.test.mock.MockHttpServletResponse;
+import org.easymock.EasyMock;
+import org.junit.Test;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+
+public class GatewayDispatchFilterTest {
+
+ /**
+ * Verify that a whitelist violation results in a HTTP 400 response.
+ */
+ @Test
+ public void testServiceDispatchWhitelistViolation() throws Exception {
+ final String serviceRole = "KNOXSSO";
+
+ GatewayConfig config = EasyMock.createNiceMock(GatewayConfig.class);
+ EasyMock.expect(config.getDispatchWhitelistServices()).andReturn(Collections.emptyList()).anyTimes();
+ EasyMock.expect(config.getDispatchWhitelist()).andReturn(null).anyTimes();
+ EasyMock.replay(config);
+
+ ServletContext sc = EasyMock.createNiceMock(ServletContext.class);
+ EasyMock.expect(sc.getAttribute("org.apache.knox.gateway.config")).andReturn(config).anyTimes();
+ EasyMock.replay(sc);
+
+ HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
+ EasyMock.expect(request.getMethod()).andReturn("GET").anyTimes();
+ EasyMock.expect(request.getServerName()).andReturn("localhost").anyTimes();
+ EasyMock.expect(request.getRequestURI()).andReturn("http://www.notonmylist.org:9999").anyTimes();
+ EasyMock.expect(request.getAttribute("targetServiceRole")).andReturn(serviceRole).anyTimes();
+ EasyMock.expect(request.getServletContext()).andReturn(sc).anyTimes();
+ EasyMock.replay(request);
+
+ HttpServletResponse response = new TestHttpServletResponse();
+ (new GatewayDispatchFilter()).doFilter(request, response, null);
+ assertEquals(400, response.getStatus());
+ }
+
+
+ /**
+ * If the dispatch service is not configured to honor the whitelist, the dispatching should be permitted.
+ */
+ @Test
+ public void testServiceDispatchWhitelistNoServiceRoles() throws Exception {
+ final String serviceRole = "TESTROLE";
+ doTestServiceDispatchWhitelist(Collections.emptyList(),
+ "^https?://localhost.*$",
+ serviceRole,
+ "http://www.notonmylist.org:9999", true);
+ }
+
+ /**
+ * If the dispatch service is configured to honor the whitelist, but no whitelist is configured, then the default
+ * whitelist should be applied. If the dispatch URL does not match the default whitelist, then the dispatch should be
+ * disallowed.
+ */
+ @Test
+ public void testServiceDispatchWhitelistNoWhiteListForRole_invalid() throws Exception {
+ final String serviceRole = "TESTROLE";
+ doTestServiceDispatchWhitelist(Collections.singletonList(serviceRole),
+ null,
+ serviceRole,
+ "http://www.notonmylist.org:9999", false);
+ }
+
+ /**
+ * If the dispatch service is configured to honor the whitelist, but no whitelist is configured, then the default
+ * whitelist should be applied. If the dispatch URL does not match the default whitelist, then the dispatch should be
+ * disallowed.
+ */
+ @Test
+ public void testServiceDispatchWhitelistNoWhiteListForRole_invalid_alt_localhost() throws Exception {
+ final String serviceRole = "TESTROLE";
+ doTestServiceDispatchWhitelist(Collections.singletonList(serviceRole),
+ "127.0.0.1",
+ null,
+ serviceRole,
+ "http://www.notonmylist.org:9999", false);
+ }
+
+ /**
+ * If the dispatch service is configured to honor the whitelist, but no whitelist is configured, then the default
+ * whitelist should be applied. If the dispatch URL does not match the default domain-based whitelist, then the
+ * dispatch should be disallowed.
+ */
+ @Test
+ public void testServiceDispatchWhitelistNoWhiteListForRole_invalid_domain() throws Exception {
+ final String serviceRole = "TESTROLE";
+ doTestServiceDispatchWhitelist(Collections.singletonList(serviceRole),
+ "knoxbox.test.org",
+ null,
+ serviceRole,
+ "http://www.notonmylist.org:9999", false);
+ }
+
+ /**
+ * If the dispatch service is configured to honor the whitelist, but no whitelist is configured, then the default
+ * whitelist should be applied. If the dispatch URL matches the default domain-based whitelist, then the dispatch
+ * should be permitted.
+ */
+ @Test
+ public void testServiceDispatchWhitelistNoWhiteListForRole_valid_domain() throws Exception {
+ final String serviceRole = "TESTROLE";
+ doTestServiceDispatchWhitelist(Collections.singletonList(serviceRole),
+ "knoxbox.test.org",
+ null,
+ serviceRole,
+ "http://onmylist.test.org:9999", true);
+ }
+
+ /**
+ * If the dispatch service is configured to honor the whitelist, but no whitelist is configured, then the default
+ * whitelist should be applied. If the dispatch URL does match the default whitelist, then the dispatch should be
+ * allowed.
+ */
+ @Test
+ public void testServiceDispatchWhitelistNoWhiteListForRole_valid() throws Exception {
+ final String serviceRole = "TESTROLE";
+ doTestServiceDispatchWhitelist(Collections.singletonList(serviceRole),
+ null,
+ serviceRole,
+ "http://localhost:9999", true);
+ }
+
+ /**
+ * An empty whitelist should be treated as the default whitelist.
+ */
+ @Test
+ public void testServiceDispatchWhitelistEmptyWhitelist() throws Exception {
+ final String serviceRole = "TESTROLE";
+ doTestServiceDispatchWhitelist(Collections.singletonList(serviceRole),
+ "",
+ serviceRole,
+ "http://www.notonmylist.org:9999",
+ false);
+ }
+
+
+ /**
+ * If a custom whitelist is configured, and the requested service role is among those configured to honor that
+ * whitelist, the request should be disallowed if the URL does NOT match the whitelist.
+ */
+ @Test
+ public void testServiceDispatchWhitelistCustomWhitelist_invalid() throws Exception {
+ final String serviceRole = "TESTROLE";
+ doTestServiceDispatchWhitelist(Collections.singletonList(serviceRole),
+ "^.*mydomain\\.org.*$;^.*myotherdomain.com.*",
+ serviceRole,
+ "http://www.notonmylist.org:9999",
+ false);
+ }
+
+
+ /**
+ * If a custom whitelist is configured, and the requested service role is among those configured to honor that
+ * whitelist, the request should be permitted if the URL matches the whitelist.
+ */
+ @Test
+ public void testServiceDispatchWhitelistCustomWhitelist_valid() throws Exception {
+ final String serviceRole = "TESTROLE";
+ doTestServiceDispatchWhitelist(Collections.singletonList(serviceRole),
+ "^.*mydomain\\.org.*$;^.*myotherdomain.com.*;^.*onmylist\\.org.*$",
+ serviceRole,
+ "http://www.onmylist.org:9999",
+ true);
+ }
+
+ /**
+ * The configured whitelist should be ignored for services which are NOT configured to honor the whitelist, and those
+ * dispatches should be permitted.
+ */
+ @Test
+ public void testServiceDispatchWhitelistCustomWhitelistNoServiceRoles() throws Exception {
+ final String serviceRole = "TESTROLE";
+ doTestServiceDispatchWhitelist(Arrays.asList("MYROLE","SOMEOTHER_ROLE"), // Different roles than the one requested
+ "^.*mydomain\\.org.*$;^.*myotherdomain.com.*",
+ serviceRole,
+ "http://www.onmylist.org:9999",
+ true);
+ }
+
+
+ private void doTestServiceDispatchWhitelist(List<String> whitelistedServices,
+ String whitelist,
+ String serviceRole,
+ String dispatchURL,
+ boolean expectation) throws Exception {
+ doTestServiceDispatchWhitelist(whitelistedServices, "localhost", whitelist, serviceRole, dispatchURL, expectation);
+ }
+
+ private void doTestServiceDispatchWhitelist(List<String> whitelistedServices,
+ String serverName,
+ String whitelist,
+ String serviceRole,
+ String dispatchURL,
+ boolean expectation) throws Exception {
+
+ GatewayConfig config = EasyMock.createNiceMock(GatewayConfig.class);
+ EasyMock.expect(config.getDispatchWhitelistServices()).andReturn(whitelistedServices).anyTimes();
+ EasyMock.expect(config.getDispatchWhitelist()).andReturn(whitelist).anyTimes();
+ EasyMock.replay(config);
+
+ ServletContext sc = EasyMock.createNiceMock(ServletContext.class);
+ EasyMock.expect(sc.getAttribute("org.apache.knox.gateway.config")).andReturn(config).anyTimes();
+ EasyMock.replay(sc);
+
+ HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
+ EasyMock.expect(request.getServerName()).andReturn(serverName).anyTimes();
+ EasyMock.expect(request.getRequestURI()).andReturn(dispatchURL).anyTimes();
+ EasyMock.expect(request.getAttribute("targetServiceRole")).andReturn(serviceRole).anyTimes();
+ EasyMock.expect(request.getServletContext()).andReturn(sc).anyTimes();
+ EasyMock.replay(request);
+
+ GatewayDispatchFilter gdf = new GatewayDispatchFilter();
+ Method isDispatchAllowedMethod =
+ GatewayDispatchFilter.class.getDeclaredMethod("isDispatchAllowed", HttpServletRequest.class);
+ isDispatchAllowedMethod.setAccessible(true);
+ boolean isAllowed = (boolean) isDispatchAllowedMethod.invoke(gdf, request);
+ assertEquals(expectation, isAllowed);
+ }
+
+ private static class TestHttpServletResponse extends MockHttpServletResponse {
+ int status = 0;
+
+ @Override
+ public void sendError(int i) throws IOException {
+ status = i;
+ }
+
+ @Override
+ public int getStatus() {
+ return status;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/8bdd03cd/gateway-spi/src/test/java/org/apache/knox/gateway/util/WhitelistUtilsTest.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/test/java/org/apache/knox/gateway/util/WhitelistUtilsTest.java b/gateway-spi/src/test/java/org/apache/knox/gateway/util/WhitelistUtilsTest.java
new file mode 100644
index 0000000..3094c6f
--- /dev/null
+++ b/gateway-spi/src/test/java/org/apache/knox/gateway/util/WhitelistUtilsTest.java
@@ -0,0 +1,145 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.apache.knox.gateway.util;
+
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.easymock.EasyMock;
+import org.junit.Test;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+public class WhitelistUtilsTest {
+
+ @Test
+ public void testDefault() throws Exception {
+ String whitelist = doTestGetDispatchWhitelist(createMockGatewayConfig(Collections.emptyList(), null), "TEST");
+ assertNull("The test service role is not configured to honor the whitelist, so there should be none returned.",
+ whitelist);
+ }
+
+ /**
+ * KNOXSSO is implicitly included in the set of service roles for which the whitelist will be applied.
+ */
+ @Test
+ public void testDefaultKnoxSSO() throws Exception {
+ String whitelist = doTestGetDispatchWhitelist(createMockGatewayConfig(Collections.emptyList(), null), "KNOXSSO");
+ assertNotNull(whitelist);
+ }
+
+ @Test
+ public void testDefaultForAffectedServiceRole() throws Exception {
+ final String serviceRole = "TEST";
+
+ GatewayConfig config = createMockGatewayConfig(Collections.singletonList(serviceRole), null);
+
+ // Check localhost by name
+ String whitelist = doTestGetDispatchWhitelist(config, serviceRole);
+ assertNotNull(whitelist);
+ assertTrue(whitelist.contains("localhost"));
+
+ // Check localhost by loopback address
+ whitelist = doTestGetDispatchWhitelist(config, "127.0.0.1", serviceRole);
+ assertNotNull(whitelist);
+ assertTrue(whitelist.contains("localhost"));
+ }
+
+
+ @Test
+ public void testDefaultDomainWhitelist() throws Exception {
+ final String serviceRole = "TEST";
+
+ String whitelist =
+ doTestGetDispatchWhitelist(createMockGatewayConfig(Collections.singletonList(serviceRole), null),
+ "host0.test.org",
+ serviceRole);
+ assertNotNull(whitelist);
+ assertTrue(whitelist.contains("\\.test\\.org"));
+ }
+
+ @Test
+ public void testDefaultProxiedDomainWhitelist() throws Exception {
+ final String serviceRole = "TEST";
+
+ String whitelist =
+ doTestGetDispatchWhitelist(createMockGatewayConfig(Collections.singletonList(serviceRole), null),
+ "host0.test.org",
+ "forwarded-host.proxy.org",
+ serviceRole);
+ assertNotNull(whitelist);
+ assertTrue(whitelist.contains("\\.proxy\\.org"));
+ }
+
+ @Test
+ public void testConfiguredWhitelist() throws Exception {
+ final String serviceRole = "TEST";
+ final String WHITELIST = "^.*\\.my\\.domain\\.com.*$";
+
+ String whitelist =
+ doTestGetDispatchWhitelist(createMockGatewayConfig(Collections.singletonList(serviceRole), WHITELIST),
+ serviceRole);
+ assertNotNull(whitelist);
+ assertTrue(whitelist.equals(WHITELIST));
+ }
+
+
+ private String doTestGetDispatchWhitelist(GatewayConfig config, String serviceRole) {
+ return doTestGetDispatchWhitelist(config, "localhost", serviceRole);
+ }
+
+
+ private String doTestGetDispatchWhitelist(GatewayConfig config,
+ String serverName,
+ String serviceRole) {
+ return doTestGetDispatchWhitelist(config, serverName, null, serviceRole);
+ }
+
+ private String doTestGetDispatchWhitelist(GatewayConfig config,
+ String serverName,
+ String xForwardedHost,
+ String serviceRole) {
+ ServletContext sc = EasyMock.createNiceMock(ServletContext.class);
+ EasyMock.expect(sc.getAttribute("org.apache.knox.gateway.config")).andReturn(config).anyTimes();
+ EasyMock.replay(sc);
+
+ HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
+ EasyMock.expect(request.getServerName()).andReturn(serverName).anyTimes();
+ EasyMock.expect(request.getHeader("X-Forwarded-Host")).andReturn(xForwardedHost).anyTimes();
+ EasyMock.expect(request.getAttribute("targetServiceRole")).andReturn(serviceRole).anyTimes();
+ EasyMock.expect(request.getServletContext()).andReturn(sc).anyTimes();
+ EasyMock.replay(request);
+
+ return WhitelistUtils.getDispatchWhitelist(request);
+ }
+
+
+ private static GatewayConfig createMockGatewayConfig(final List<String> serviceRoles, final String whitelist) {
+ GatewayConfig config = EasyMock.createNiceMock(GatewayConfig.class);
+ EasyMock.expect(config.getDispatchWhitelistServices()).andReturn(serviceRoles).anyTimes();
+ EasyMock.expect(config.getDispatchWhitelist()).andReturn(whitelist).anyTimes();
+ EasyMock.replay(config);
+
+ return config;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/8bdd03cd/gateway-test-release-utils/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
----------------------------------------------------------------------
diff --git a/gateway-test-release-utils/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java b/gateway-test-release-utils/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
index ef5c1c4..f8d4ec7 100644
--- a/gateway-test-release-utils/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
+++ b/gateway-test-release-utils/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
@@ -723,4 +723,13 @@ public class GatewayTestConfig extends Configuration implements GatewayConfig {
return null;
}
+ public String getDispatchWhitelist() {
+ return null;
+ }
+
+ @Override
+ public List<String> getDispatchWhitelistServices() {
+ return Collections.emptyList();
+ }
+
}