You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by mo...@apache.org on 2019/08/06 18:28:35 UTC
[knox] branch master updated: KNOX-1694 - Prevent port mapped
topologies from being exposed to gateway port (#126)
This is an automated email from the ASF dual-hosted git repository.
more pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/knox.git
The following commit(s) were added to refs/heads/master by this push:
new 55adc6a KNOX-1694 - Prevent port mapped topologies from being exposed to gateway port (#126)
55adc6a is described below
commit 55adc6a9cd59525f41159c5499ab214749887be9
Author: Sandeep Moré <mo...@apache.org>
AuthorDate: Tue Aug 6 14:28:30 2019 -0400
KNOX-1694 - Prevent port mapped topologies from being exposed to gateway port (#126)
---
.../org/apache/knox/gateway/GatewayMessages.java | 12 ++
.../org/apache/knox/gateway/GatewayServer.java | 63 ++++---
.../gateway/filter/PortMappingHelperHandler.java | 79 ++++-----
.../knox/gateway/GatewayDefaultTopologyTest.java | 75 ++++++++
.../GatewayPortMappingDisableFeatureTest.java | 163 +-----------------
.../knox/gateway/GatewayPortMappingFailTest.java | 50 +-----
.../knox/gateway/GatewayPortMappingFuncTest.java | 179 +------------------
.../org/apache/knox/gateway/PortMappingHelper.java | 189 +++++++++++++++++++++
8 files changed, 365 insertions(+), 445 deletions(-)
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayMessages.java b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayMessages.java
index 1c52d56..aa019da 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayMessages.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayMessages.java
@@ -449,6 +449,14 @@ public interface GatewayMessages {
text = "Topology port mapping feature enabled: {0}")
void gatewayTopologyPortMappingEnabled(boolean enabled);
+ @Message(level = MessageLevel.ERROR,
+ text = "No topology mapped to port: {0}")
+ void noTopologyMappedToPort(int port);
+
+ @Message(level = MessageLevel.ERROR,
+ text = "Could not find topology {0} specified in port mapping config")
+ void noMappedTopologyFound(String topology);
+
@Message(level = MessageLevel.DEBUG,
text = "Creating a connector for topology {0} listening on port {1}.")
void createJettyConnector(String topology, int port);
@@ -490,6 +498,10 @@ public interface GatewayMessages {
+ "Gateway restart will be required if in the future \"{0}\" topology is added.")
void topologyPortMappingCannotFindTopology(String topology, int port);
+ @Message(level = MessageLevel.ERROR,
+ text = "Port mapped topology {0} cannot be configured as default topology")
+ void defaultTopologyInPortmappedTopology(String topology);
+
@Message( level = MessageLevel.WARN, text = "There is no registry client defined for remote configuration monitoring." )
void missingClientConfigurationForRemoteMonitoring();
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
index 5462aa1..6e8777e 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
@@ -34,11 +34,10 @@ import org.apache.knox.gateway.deploy.DeploymentException;
import org.apache.knox.gateway.deploy.DeploymentFactory;
import org.apache.knox.gateway.filter.CorrelationHandler;
import org.apache.knox.gateway.filter.PortMappingHelperHandler;
-import org.apache.knox.gateway.filter.RequestUpdateHandler;
import org.apache.knox.gateway.i18n.messages.MessagesFactory;
import org.apache.knox.gateway.i18n.resources.ResourcesFactory;
-import org.apache.knox.gateway.services.ServiceType;
import org.apache.knox.gateway.services.GatewayServices;
+import org.apache.knox.gateway.services.ServiceType;
import org.apache.knox.gateway.services.registry.ServiceRegistry;
import org.apache.knox.gateway.services.security.AliasServiceException;
import org.apache.knox.gateway.services.security.SSLService;
@@ -56,13 +55,13 @@ import org.apache.knox.gateway.websockets.GatewayWebsocketHandler;
import org.apache.log4j.PropertyConfigurator;
import org.eclipse.jetty.server.ConnectionFactory;
import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.NetworkConnector;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.RequestLogHandler;
@@ -424,7 +423,6 @@ public class GatewayServer {
HttpConfiguration httpConfig = new HttpConfiguration();
httpConfig.setRequestHeaderSize( config.getHttpServerRequestHeaderBuffer() );
- //httpConfig.setRequestBufferSize( config.getHttpServerRequestBuffer() );
httpConfig.setResponseHeaderSize( config.getHttpServerResponseHeaderBuffer() );
httpConfig.setOutputBufferSize( config.getHttpServerResponseBuffer() );
@@ -459,6 +457,15 @@ public class GatewayServer {
final GatewayServices services,
final ContextHandlerCollection contexts,
final Map<String, Integer> topologyPortMap) {
+
+ final Map<String, Handler> contextToHandlerMap = new HashMap<>();
+ if(contexts.getHandlers() != null) {
+ Arrays.asList(contexts.getHandlers()).stream()
+ .filter(h -> h instanceof WebAppContext)
+ .forEach(h -> contextToHandlerMap
+ .put(((WebAppContext) h).getContextPath(), h));
+ }
+
HandlerCollection handlers = new HandlerCollection();
RequestLogHandler logHandler = new RequestLogHandler();
@@ -485,21 +492,26 @@ public class GatewayServer {
if (config.isGatewayPortMappingEnabled()) {
- for (final Map.Entry<String, Integer> entry : topologyPortMap
- .entrySet()) {
- log.createJettyHandler(entry.getKey());
- final ContextHandler topologyContextHandler = new ContextHandler();
-
- final RequestUpdateHandler updateHandler = new RequestUpdateHandler(
- config, entry.getKey(), services);
-
- topologyContextHandler.setHandler(updateHandler);
- topologyContextHandler.setVirtualHosts(
- new String[] { "@" + entry.getKey().toLowerCase(Locale.ROOT) });
-
- handlers.addHandler(topologyContextHandler);
- }
-
+ /* Do the virtual host bindings for all the defined topology port mapped
+ * contexts except for the one that has gateway port to prevent issues
+ * with context deployment */
+ topologyPortMap
+ .entrySet()
+ .stream()
+ .filter(e -> !e.getValue().equals(config.getGatewayPort()))
+ .forEach( entry -> {
+ log.createJettyHandler(entry.getKey());
+ final Handler context = contextToHandlerMap
+ .get("/" + config.getGatewayPath() + "/" + entry.getKey());
+
+ if(context != null) {
+ ((WebAppContext) context).setVirtualHosts(
+ new String[] { "@" + entry.getKey().toLowerCase(Locale.ROOT) });
+ } else {
+ // no topology found for mapping entry.getKey()
+ log.noMappedTopologyFound(entry.getKey());
+ }
+ });
}
handlers.addHandler(logHandler);
@@ -565,7 +577,20 @@ public class GatewayServer {
port, topologyName));
}
}
+ }
+ /*
+ * Check for a case where default topology is also in port mapping list.
+ * This is not a valid scenario, you cannot have same topology listening on
+ * multiple ports.
+ */
+ if (config.getDefaultTopologyName() != null && config
+ .getGatewayPortMappings()
+ .containsKey(config.getDefaultTopologyName())) {
+ log.defaultTopologyInPortmappedTopology(config.getDefaultTopologyName());
+ throw new IOException(String.format(Locale.ROOT,
+ "Default topology cannot be in port mapping list, please remove %s from port mapping list or don't make it a default topology.",
+ config.getDefaultTopologyName()));
}
}
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/filter/PortMappingHelperHandler.java b/gateway-server/src/main/java/org/apache/knox/gateway/filter/PortMappingHelperHandler.java
index e776596..f917f8f 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/filter/PortMappingHelperHandler.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/filter/PortMappingHelperHandler.java
@@ -16,7 +16,6 @@
*/
package org.apache.knox.gateway.filter;
-import org.apache.commons.lang3.StringUtils;
import org.apache.knox.gateway.GatewayMessages;
import org.apache.knox.gateway.config.GatewayConfig;
import org.apache.knox.gateway.i18n.messages.MessagesFactory;
@@ -47,31 +46,28 @@ public class PortMappingHelperHandler extends HandlerWrapper {
private static final GatewayMessages LOG = MessagesFactory
.get(GatewayMessages.class);
- final GatewayConfig config;
+ private final GatewayConfig config;
+ private final Map<String, Integer> topologyPortMap;
private String defaultTopologyRedirectContext;
public PortMappingHelperHandler(final GatewayConfig config) {
this.config = config;
+ this.topologyPortMap = config.getGatewayPortMappings();
+
//Set up context for default topology feature.
String defaultTopologyName = config.getDefaultTopologyName();
// default topology feature can also be enabled using port mapping feature
// config e.g. gateway.port.mapping.{defaultTopologyName}
-
if(defaultTopologyName == null && config.getGatewayPortMappings().values().contains(config.getGatewayPort())) {
-
for(final Map.Entry<String, Integer> entry: config.getGatewayPortMappings().entrySet()) {
-
- if(entry.getValue() == config.getGatewayPort()) {
+ if(entry.getValue().intValue() == config.getGatewayPort()) {
defaultTopologyRedirectContext = "/" + config.getGatewayPath() + "/" + entry.getKey();
break;
}
-
}
-
-
}
if (defaultTopologyName != null) {
@@ -85,7 +81,6 @@ public class PortMappingHelperHandler extends HandlerWrapper {
LOG.defaultTopologySetup(defaultTopologyName,
defaultTopologyRedirectContext);
}
-
}
@Override
@@ -95,60 +90,54 @@ public class PortMappingHelperHandler extends HandlerWrapper {
String newTarget = target;
String baseURI = baseRequest.getRequestURI();
+ final int port = baseRequest.getLocalPort();
+ RequestUpdateHandler.ForwardedRequest newRequest;
// If Port Mapping feature enabled
- if (config.isGatewayPortMappingEnabled()) {
- int targetIndex;
- String context = "";
-
- // extract the gateway specific part i.e. {/gatewayName/}
- String originalContextPath = "";
- targetIndex = StringUtils.ordinalIndexOf(target, "/", 2);
-
- // Match found e.g. /{string}/
- if (targetIndex > 0) {
- originalContextPath = target.substring(0, targetIndex + 1);
- } else if (targetIndex == -1) {
- targetIndex = StringUtils.ordinalIndexOf(target, "/", 1);
- // For cases "/" and "/hive"
- if(targetIndex == 0) {
- originalContextPath = target;
- }
+ if (config.isGatewayPortMappingEnabled() && topologyPortMap.containsValue(port)) {
+
+ final String topologyName = topologyPortMap.entrySet()
+ .stream()
+ .filter(e -> e.getValue().equals(port))
+ .map(Map.Entry::getKey)
+ .findFirst()
+ .orElse(null);
+ final String gatewayTopologyContext =
+ "/" + config.getGatewayPath() + "/" + topologyName;
+
+ if(!target.contains(gatewayTopologyContext)) {
+ newTarget = gatewayTopologyContext + target;
}
- // Match "/{gatewayName}/{topologyName/foo" or "/".
- // There could be a case where content is served from the root
- // i.e. https://host:port/
+ // if the request does not contain /{gatewayName}/{topologyName}
+ if(!baseRequest.getRequestURI().contains(gatewayTopologyContext)) {
+ newRequest = new RequestUpdateHandler.ForwardedRequest(
+ request, gatewayTopologyContext, newTarget);
- if (!baseURI.startsWith(originalContextPath)) {
- final int index = StringUtils.ordinalIndexOf(baseURI, "/", 3);
- if (index > 0) {
- context = baseURI.substring(0, index);
- }
- }
+ baseRequest.setPathInfo(gatewayTopologyContext + baseRequest.getPathInfo());
+ baseRequest.setURIPathQuery(gatewayTopologyContext + baseRequest.getRequestURI());
- if(!StringUtils.isBlank(context)) {
- LOG.topologyPortMappingAddContext(target, context + target);
+ LOG.topologyPortMappingUpdateRequest(target, newTarget);
+ super.handle(newTarget, baseRequest, newRequest, response);
+ }
+ else {
+ super.handle(newTarget, baseRequest, request, response);
}
- // Move on to the next handler in chain with updated path
- newTarget = context + target;
}
-
//Backwards compatibility for default topology feature
- if (defaultTopologyRedirectContext != null && !baseURI
+ else if (defaultTopologyRedirectContext != null && !baseURI
.startsWith("/" + config.getGatewayPath())) {
newTarget = defaultTopologyRedirectContext + target;
- final RequestUpdateHandler.ForwardedRequest newRequest = new RequestUpdateHandler.ForwardedRequest(
+ newRequest = new RequestUpdateHandler.ForwardedRequest(
request, defaultTopologyRedirectContext, newTarget);
LOG.defaultTopologyForward(target, newTarget);
super.handle(newTarget, baseRequest, newRequest, response);
} else {
-
+ /* case where topology port mapping is not enabled (or improperly configured) and no default topology is configured */
super.handle(newTarget, baseRequest, request, response);
}
-
}
}
diff --git a/gateway-test/src/test/java/org/apache/knox/gateway/GatewayDefaultTopologyTest.java b/gateway-test/src/test/java/org/apache/knox/gateway/GatewayDefaultTopologyTest.java
new file mode 100644
index 0000000..be43dd2
--- /dev/null
+++ b/gateway-test/src/test/java/org/apache/knox/gateway/GatewayDefaultTopologyTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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;
+
+import org.apache.knox.test.TestUtils;
+import org.apache.knox.test.category.ReleaseTest;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import java.io.IOException;
+
+import static org.apache.knox.test.TestUtils.LOG_ENTER;
+import static org.apache.knox.test.TestUtils.LOG_EXIT;
+
+/**
+ * Test default topology feature
+ */
+@Category(ReleaseTest.class)
+public class GatewayDefaultTopologyTest extends PortMappingHelper {
+
+ public GatewayDefaultTopologyTest() {
+ super();
+ }
+
+ @BeforeClass
+ public static void setup() throws Exception {
+ /* setup test with eerie as a default topology */
+ init("eerie",false);
+ }
+
+ @AfterClass
+ public static void cleanup() throws Exception {
+ LOG_ENTER();
+ driver.cleanup();
+ driver.reset();
+ masterServer.reset();
+ LOG_EXIT();
+ }
+
+ /*
+ * Test the standard case:
+ * http://localhost:{topologyPort}/gateway/eerie/webhdfs/v1
+ */
+ @Test(timeout = TestUtils.MEDIUM_TIMEOUT )
+ public void testBasicListOperation() throws IOException {
+ test("http://localhost:" + driver.getGatewayPort() + "/gateway/eerie" + "/webhdfs" );
+ }
+
+ /*
+ * Test the Default Topology Feature, activated by property
+ * "default.app.topology.name"
+ *
+ * http://localhost:{eeriePort}/gateway/eerie/webhdfs/v1
+ */
+ @Test(timeout = TestUtils.MEDIUM_TIMEOUT )
+ public void testDefaultTopologyFeature() throws IOException {
+ test("http://localhost:" + driver.getGatewayPort() + "/webhdfs" );
+ }
+}
diff --git a/gateway-test/src/test/java/org/apache/knox/gateway/GatewayPortMappingDisableFeatureTest.java b/gateway-test/src/test/java/org/apache/knox/gateway/GatewayPortMappingDisableFeatureTest.java
index 4d9e767..5d50700 100644
--- a/gateway-test/src/test/java/org/apache/knox/gateway/GatewayPortMappingDisableFeatureTest.java
+++ b/gateway-test/src/test/java/org/apache/knox/gateway/GatewayPortMappingDisableFeatureTest.java
@@ -16,12 +16,8 @@
*/
package org.apache.knox.gateway;
-import com.mycila.xmltool.XMLDoc;
-import com.mycila.xmltool.XMLTag;
import org.apache.knox.test.TestUtils;
import org.apache.knox.test.category.ReleaseTest;
-import org.apache.knox.test.mock.MockServer;
-import org.apache.http.HttpStatus;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -33,31 +29,15 @@ import java.io.IOException;
import java.net.ConnectException;
import java.util.concurrent.ConcurrentHashMap;
-import static io.restassured.RestAssured.given;
import static org.apache.knox.test.TestUtils.LOG_ENTER;
import static org.apache.knox.test.TestUtils.LOG_EXIT;
-import static org.hamcrest.CoreMatchers.is;
/**
* Test that the Gateway Topology Port Mapping feature is disabled properly.
*
*/
@Category(ReleaseTest.class)
-public class GatewayPortMappingDisableFeatureTest {
-
- // Specifies if the test requests should go through the gateway or directly to the services.
- // This is frequently used to verify the behavior of the test both with and without the gateway.
- private static final boolean USE_GATEWAY = true;
-
- // Specifies if the test requests should be sent to mock services or the real services.
- // This is frequently used to verify the behavior of the test both with and without mock services.
- private static final boolean USE_MOCK_SERVICES = true;
-
- private static GatewayTestDriver driver = new GatewayTestDriver();
-
- private static MockServer masterServer;
-
- private int eeriePort;
+public class GatewayPortMappingDisableFeatureTest extends PortMappingHelper {
@Rule
public ExpectedException exception = ExpectedException.none();
@@ -66,41 +46,13 @@ public class GatewayPortMappingDisableFeatureTest {
super();
}
- /**
- * Creates a deployment of a gateway instance that all test methods will share. This method also creates a
- * registry of sorts for all of the services that will be used by the test methods.
- * The createTopology method is used to create the topology file that would normally be read from disk.
- * The driver.setupGateway invocation is where the creation of GATEWAY_HOME occurs.
- * <p>
- * This would normally be done once for this suite but the failure tests start affecting each other depending
- * on the state the last 'active' url
- *
- * @throws Exception Thrown if any failure occurs.
- */
@Before
public void setup() throws Exception {
- LOG_ENTER();
-
eeriePort = getAvailablePort(1240, 49151);
-
ConcurrentHashMap<String, Integer> topologyPortMapping = new ConcurrentHashMap<>();
topologyPortMapping.put("eerie", eeriePort);
-
- masterServer = new MockServer("master", true);
- GatewayTestConfig config = new GatewayTestConfig();
- config.setGatewayPath("gateway");
- config.setTopologyPortMapping(topologyPortMapping);
- // disable the feature
- config.setGatewayPortMappingEnabled(false);
-
- driver.setResourceBase(WebHdfsHaFuncTest.class);
- driver.setupLdap(0);
-
- driver.setupService("WEBHDFS", "http://vm.local:50070/webhdfs", "/eerie/webhdfs", USE_MOCK_SERVICES);
-
- driver.setupGateway(config, "eerie", createTopology("WEBHDFS"), USE_GATEWAY);
-
- LOG_EXIT();
+ /* define port mappings but feature disabled */
+ init(null, topologyPortMapping, false);
}
@After
@@ -117,9 +69,7 @@ public class GatewayPortMappingDisableFeatureTest {
*/
@Test(timeout = TestUtils.MEDIUM_TIMEOUT )
public void testBasicListOperation() throws IOException {
- LOG_ENTER();
test(driver.getUrl("WEBHDFS") );
- LOG_EXIT();
}
/*
@@ -127,115 +77,8 @@ public class GatewayPortMappingDisableFeatureTest {
*/
@Test(timeout = TestUtils.MEDIUM_TIMEOUT )
public void testMultiPortFailOperation() throws IOException {
- LOG_ENTER();
exception.expect(ConnectException.class);
exception.expectMessage("Connection refused");
-
test("http://localhost:" + eeriePort + "/webhdfs" );
- LOG_EXIT();
- }
-
- private void test (final String url) throws IOException {
- String password = "hdfs-password";
- String username = "hdfs";
-
- masterServer.expect()
- .method("GET")
- .pathInfo("/webhdfs/v1/")
- .queryParam("op", "LISTSTATUS")
- .queryParam("user.name", username)
- .respond()
- .status(HttpStatus.SC_OK)
- .content(driver.getResourceBytes("webhdfs-liststatus-success.json"))
- .contentType("application/json");
-
- given()
- .auth().preemptive().basic(username, password)
- .header("X-XSRF-Header", "jksdhfkhdsf")
- .queryParam("op", "LISTSTATUS")
- .then()
- .log().ifError()
- .statusCode(HttpStatus.SC_OK)
- .body("FileStatuses.FileStatus[0].pathSuffix", is("app-logs"))
- .when().get(url + "/v1/");
- masterServer.isEmpty();
- }
-
- /**
- * Creates a topology that is deployed to the gateway instance for the test suite.
- * Note that this topology is shared by all of the test methods in this suite.
- *
- * @return A populated XML structure for a topology file.
- */
- private static XMLTag createTopology(final String role) {
- return XMLDoc.newDocument(true)
- .addRoot("topology")
- .addTag("gateway")
- .addTag("provider")
- .addTag("role").addText("webappsec")
- .addTag("name").addText("WebAppSec")
- .addTag("enabled").addText("true")
- .addTag("param")
- .addTag("name").addText("csrf.enabled")
- .addTag("value").addText("true").gotoParent().gotoParent()
- .addTag("provider")
- .addTag("role").addText("authentication")
- .addTag("name").addText("ShiroProvider")
- .addTag("enabled").addText("true")
- .addTag("param")
- .addTag("name").addText("main.ldapRealm")
- .addTag("value").addText("org.apache.knox.gateway.shirorealm.KnoxLdapRealm").gotoParent()
- .addTag("param")
- .addTag("name").addText("main.ldapRealm.userDnTemplate")
- .addTag("value").addText("uid={0},ou=people,dc=hadoop,dc=apache,dc=org").gotoParent()
- .addTag("param")
- .addTag("name").addText("main.ldapRealm.contextFactory.url")
- .addTag("value").addText(driver.getLdapUrl()).gotoParent()
- .addTag("param")
- .addTag("name").addText("main.ldapRealm.contextFactory.authenticationMechanism")
- .addTag("value").addText("simple").gotoParent()
- .addTag("param")
- .addTag("name").addText("urls./**")
- .addTag("value").addText("authcBasic").gotoParent().gotoParent()
- .addTag("provider")
- .addTag("role").addText("identity-assertion")
- .addTag("enabled").addText("true")
- .addTag("name").addText("Default").gotoParent()
- .addTag("provider")
- .addTag("role").addText("authorization")
- .addTag("enabled").addText("true")
- .addTag("name").addText("AclsAuthz").gotoParent()
- .addTag("param")
- .addTag("name").addText("webhdfs-acl")
- .addTag("value").addText("hdfs;*;*").gotoParent()
- .addTag("provider")
- .addTag("role").addText("ha")
- .addTag("enabled").addText("true")
- .addTag("name").addText("HaProvider")
- .addTag("param")
- .addTag("name").addText("WEBHDFS")
- .addTag("value").addText("maxFailoverAttempts=3;failoverSleep=15;maxRetryAttempts=3;retrySleep=10;enabled=true").gotoParent()
- .gotoRoot()
- .addTag("service")
- .addTag("role").addText(role)
- .addTag("url").addText("http://localhost:" + masterServer.getPort() + "/webhdfs")
- .gotoRoot();
- }
-
- /**
- * This utility method will return the next available port
- * that can be used.
- * @param min min port to check
- * @param max max port to check
- * @return Port that is available.
- */
- public static int getAvailablePort(final int min, final int max) {
- for (int i = min; i <= max; i++) {
- if (!GatewayServer.isPortInUse(i)) {
- return i;
- }
- }
- // too bad
- return -1;
}
}
diff --git a/gateway-test/src/test/java/org/apache/knox/gateway/GatewayPortMappingFailTest.java b/gateway-test/src/test/java/org/apache/knox/gateway/GatewayPortMappingFailTest.java
index 7daed0f..d6edf21 100644
--- a/gateway-test/src/test/java/org/apache/knox/gateway/GatewayPortMappingFailTest.java
+++ b/gateway-test/src/test/java/org/apache/knox/gateway/GatewayPortMappingFailTest.java
@@ -16,10 +16,9 @@
*/
package org.apache.knox.gateway;
+import org.apache.http.HttpStatus;
import org.apache.knox.test.TestUtils;
import org.apache.knox.test.category.ReleaseTest;
-import org.apache.knox.test.mock.MockServer;
-import org.apache.http.HttpStatus;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -36,21 +35,7 @@ import static org.apache.knox.test.TestUtils.LOG_EXIT;
* Test the fail cases for the Port Mapping Feature
*/
@Category(ReleaseTest.class)
-public class GatewayPortMappingFailTest {
-
- // Specifies if the test requests should go through the gateway or directly to the services.
- // This is frequently used to verify the behavior of the test both with and without the gateway.
- private static final boolean USE_GATEWAY = true;
-
- // Specifies if the test requests should be sent to mock services or the real services.
- // This is frequently used to verify the behavior of the test both with and without mock services.
- private static final boolean USE_MOCK_SERVICES = true;
-
- private static GatewayTestDriver driver = new GatewayTestDriver();
-
- private static MockServer masterServer;
-
- private static int eeriePort;
+public class GatewayPortMappingFailTest extends PortMappingHelper {
/**
* Create an instance
@@ -59,39 +44,12 @@ public class GatewayPortMappingFailTest {
super();
}
- /**
- * Creates a deployment of a gateway instance that all test methods will share. This method also creates a
- * registry of sorts for all of the services that will be used by the test methods.
- * The createTopology method is used to create the topology file that would normally be read from disk.
- * The driver.setupGateway invocation is where the creation of GATEWAY_HOME occurs.
- * <p>
- * This would normally be done once for this suite but the failure tests start affecting each other depending
- * on the state the last 'active' url
- *
- * @throws Exception Thrown if any failure occurs.
- */
@BeforeClass
public static void setup() throws Exception {
- LOG_ENTER();
-
- eeriePort = GatewayPortMappingFuncTest.getAvailablePort(1240, 49151);
-
+ eeriePort = getAvailablePort(1240, 49151);
ConcurrentHashMap<String, Integer> topologyPortMapping = new ConcurrentHashMap<>();
topologyPortMapping.put("eerie", eeriePort);
-
- masterServer = new MockServer("master", true);
- GatewayTestConfig config = new GatewayTestConfig();
- config.setGatewayPath("gateway");
- config.setTopologyPortMapping(topologyPortMapping);
-
- driver.setResourceBase(WebHdfsHaFuncTest.class);
- driver.setupLdap(0);
-
- driver.setupService("WEBHDFS", "http://vm.local:50070/webhdfs", "/eerie/webhdfs", USE_MOCK_SERVICES);
-
- driver.setupGateway(config, "eerie", GatewayPortMappingFuncTest.createTopology("WEBHDFS", driver.getLdapUrl(), masterServer.getPort()), USE_GATEWAY);
-
- LOG_EXIT();
+ init(null, topologyPortMapping);
}
@AfterClass
diff --git a/gateway-test/src/test/java/org/apache/knox/gateway/GatewayPortMappingFuncTest.java b/gateway-test/src/test/java/org/apache/knox/gateway/GatewayPortMappingFuncTest.java
index afd3e73..81ff7a2 100644
--- a/gateway-test/src/test/java/org/apache/knox/gateway/GatewayPortMappingFuncTest.java
+++ b/gateway-test/src/test/java/org/apache/knox/gateway/GatewayPortMappingFuncTest.java
@@ -16,12 +16,8 @@
*/
package org.apache.knox.gateway;
-import com.mycila.xmltool.XMLDoc;
-import com.mycila.xmltool.XMLTag;
import org.apache.knox.test.TestUtils;
import org.apache.knox.test.category.ReleaseTest;
-import org.apache.knox.test.mock.MockServer;
-import org.apache.http.HttpStatus;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -30,72 +26,26 @@ import org.junit.experimental.categories.Category;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
-import static io.restassured.RestAssured.given;
import static org.apache.knox.test.TestUtils.LOG_ENTER;
import static org.apache.knox.test.TestUtils.LOG_EXIT;
-import static org.hamcrest.CoreMatchers.is;
/**
* Test the Gateway Topology Port Mapping functionality
*
*/
@Category(ReleaseTest.class)
-public class GatewayPortMappingFuncTest {
-
- // Specifies if the test requests should go through the gateway or directly to the services.
- // This is frequently used to verify the behavior of the test both with and without the gateway.
- private static final boolean USE_GATEWAY = true;
-
- // Specifies if the test requests should be sent to mock services or the real services.
- // This is frequently used to verify the behavior of the test both with and without mock services.
- private static final boolean USE_MOCK_SERVICES = true;
-
- private static GatewayTestDriver driver = new GatewayTestDriver();
-
- private static MockServer masterServer;
-
- private static int eeriePort;
+public class GatewayPortMappingFuncTest extends PortMappingHelper {
public GatewayPortMappingFuncTest() {
super();
}
- /**
- * Creates a deployment of a gateway instance that all test methods will share. This method also creates a
- * registry of sorts for all of the services that will be used by the test methods.
- * The createTopology method is used to create the topology file that would normally be read from disk.
- * The driver.setupGateway invocation is where the creation of GATEWAY_HOME occurs.
- * <p>
- * This would normally be done once for this suite but the failure tests start affecting each other depending
- * on the state the last 'active' url
- *
- * @throws Exception Thrown if any failure occurs.
- */
@BeforeClass
public static void setup() throws Exception {
- LOG_ENTER();
-
eeriePort = getAvailablePort(1240, 49151);
-
ConcurrentHashMap<String, Integer> topologyPortMapping = new ConcurrentHashMap<>();
topologyPortMapping.put("eerie", eeriePort);
-
- masterServer = new MockServer("master", true);
- GatewayTestConfig config = new GatewayTestConfig();
- config.setGatewayPath("gateway");
- config.setTopologyPortMapping(topologyPortMapping);
-
- // Enable default topology
- config.setDefaultTopologyName("eerie");
-
- driver.setResourceBase(WebHdfsHaFuncTest.class);
- driver.setupLdap(0);
-
- driver.setupService("WEBHDFS", "http://vm.local:50070/webhdfs", "/eerie/webhdfs", USE_MOCK_SERVICES);
-
- driver.setupGateway(config, "eerie", createTopology("WEBHDFS", driver.getLdapUrl(), masterServer.getPort()), USE_GATEWAY);
-
- LOG_EXIT();
+ init(null, topologyPortMapping);
}
@AfterClass
@@ -109,25 +59,12 @@ public class GatewayPortMappingFuncTest {
/*
* Test the standard case:
- * http://localhost:{gatewayPort}/gateway/eerie/webhdfs/v1
+ * http://localhost:{topologyPort}/gateway/eerie/webhdfs/v1
*/
@Test(timeout = TestUtils.MEDIUM_TIMEOUT )
public void testBasicListOperation() throws IOException {
LOG_ENTER();
- test("http://localhost:" + driver.getGatewayPort() + "/gateway/eerie" + "/webhdfs" );
- LOG_EXIT();
- }
-
- /*
- * Test the Default Topology Feature, activated by property
- * "default.app.topology.name"
- *
- * http://localhost:{eeriePort}/gateway/eerie/webhdfs/v1
- */
- @Test(timeout = TestUtils.MEDIUM_TIMEOUT )
- public void testDefaultTopologyFeature() throws IOException {
- LOG_ENTER();
- test("http://localhost:" + driver.getGatewayPort() + "/webhdfs" );
+ test("http://localhost:" + eeriePort + "/gateway/eerie" + "/webhdfs" );
LOG_EXIT();
}
@@ -155,112 +92,4 @@ public class GatewayPortMappingFuncTest {
LOG_EXIT();
}
- private void test (final String url) throws IOException {
- String password = "hdfs-password";
- String username = "hdfs";
-
- masterServer.expect()
- .method("GET")
- .pathInfo("/webhdfs/v1/")
- .queryParam("op", "LISTSTATUS")
- .queryParam("user.name", username)
- .respond()
- .status(HttpStatus.SC_OK)
- .content(driver.getResourceBytes("webhdfs-liststatus-success.json"))
- .contentType("application/json");
-
- given()
- .auth().preemptive().basic(username, password)
- .header("X-XSRF-Header", "jksdhfkhdsf")
- .queryParam("op", "LISTSTATUS")
- .then()
- .log().ifError()
- .statusCode(HttpStatus.SC_OK)
- .body("FileStatuses.FileStatus[0].pathSuffix", is("app-logs"))
- .when().get(url + "/v1/");
- masterServer.isEmpty();
- }
-
- /**
- * Creates a topology that is deployed to the gateway instance for the test suite.
- * Note that this topology is shared by all of the test methods in this suite.
- * @param role role name
- * @param ldapURL ldap url
- * @param gatewayPort port for the gateway
- * @return A populated XML structure for a topology file.
- */
- public static XMLTag createTopology(final String role, final String ldapURL, final int gatewayPort ) {
- return XMLDoc.newDocument(true)
- .addRoot("topology")
- .addTag("gateway")
- .addTag("provider")
- .addTag("role").addText("webappsec")
- .addTag("name").addText("WebAppSec")
- .addTag("enabled").addText("true")
- .addTag("param")
- .addTag("name").addText("csrf.enabled")
- .addTag("value").addText("true").gotoParent().gotoParent()
- .addTag("provider")
- .addTag("role").addText("authentication")
- .addTag("name").addText("ShiroProvider")
- .addTag("enabled").addText("true")
- .addTag("param")
- .addTag("name").addText("main.ldapRealm")
- .addTag("value").addText("org.apache.knox.gateway.shirorealm.KnoxLdapRealm").gotoParent()
- .addTag("param")
- .addTag("name").addText("main.ldapRealm.userDnTemplate")
- .addTag("value").addText("uid={0},ou=people,dc=hadoop,dc=apache,dc=org").gotoParent()
- .addTag("param")
- .addTag("name").addText("main.ldapRealm.contextFactory.url")
- .addTag("value").addText(ldapURL).gotoParent()
- .addTag("param")
- .addTag("name").addText("main.ldapRealm.contextFactory.authenticationMechanism")
- .addTag("value").addText("simple").gotoParent()
- .addTag("param")
- .addTag("name").addText("urls./**")
- .addTag("value").addText("authcBasic").gotoParent().gotoParent()
- .addTag("provider")
- .addTag("role").addText("identity-assertion")
- .addTag("enabled").addText("true")
- .addTag("name").addText("Default").gotoParent()
- .addTag("provider")
- .addTag("role").addText("authorization")
- .addTag("enabled").addText("true")
- .addTag("name").addText("AclsAuthz").gotoParent()
- .addTag("param")
- .addTag("name").addText("webhdfs-acl")
- .addTag("value").addText("hdfs;*;*").gotoParent()
- .addTag("provider")
- .addTag("role").addText("ha")
- .addTag("enabled").addText("true")
- .addTag("name").addText("HaProvider")
- .addTag("param")
- .addTag("name").addText("WEBHDFS")
- .addTag("value").addText("maxFailoverAttempts=3;failoverSleep=15;maxRetryAttempts=3;retrySleep=10;enabled=true").gotoParent()
- .gotoRoot()
- .addTag("service")
- .addTag("role").addText(role)
- .addTag("url").addText("http://localhost:" + gatewayPort + "/webhdfs")
- .gotoRoot();
- }
-
- /**
- * This utility method will return the next available port
- * that can be used.
- * @param min min port to check
- * @param max max port to check
- * @return Port that is available.
- */
- public static int getAvailablePort(final int min, final int max) {
-
- for (int i = min; i <= max; i++) {
-
- if (!GatewayServer.isPortInUse(i)) {
- return i;
- }
- }
- // too bad
- return -1;
- }
-
}
diff --git a/gateway-test/src/test/java/org/apache/knox/gateway/PortMappingHelper.java b/gateway-test/src/test/java/org/apache/knox/gateway/PortMappingHelper.java
new file mode 100644
index 0000000..cede7aa
--- /dev/null
+++ b/gateway-test/src/test/java/org/apache/knox/gateway/PortMappingHelper.java
@@ -0,0 +1,189 @@
+/*
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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;
+
+import com.mycila.xmltool.XMLDoc;
+import com.mycila.xmltool.XMLTag;
+import org.apache.http.HttpStatus;
+import org.apache.knox.test.mock.MockServer;
+
+import java.io.IOException;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static io.restassured.RestAssured.given;
+import static org.apache.knox.test.TestUtils.LOG_ENTER;
+import static org.apache.knox.test.TestUtils.LOG_EXIT;
+import static org.hamcrest.CoreMatchers.is;
+
+/**
+ * Helper class that contains common code used by port mapping tests
+ */
+public abstract class PortMappingHelper {
+ // Specifies if the test requests should go through the gateway or directly to the services.
+ // This is frequently used to verify the behavior of the test both with and without the gateway.
+ private static final boolean USE_GATEWAY = true;
+ // Specifies if the test requests should be sent to mock services or the real services.
+ // This is frequently used to verify the behavior of the test both with and without mock services.
+ private static final boolean USE_MOCK_SERVICES = true;
+ static GatewayTestDriver driver = new GatewayTestDriver();
+ static MockServer masterServer;
+ static int eeriePort;
+
+ public PortMappingHelper() {
+ super();
+ }
+
+ /**
+ * Creates a deployment of a gateway instance that all test methods will
+ * share. This method also creates a registry of sorts for all of the
+ * services that will be used by the test methods. The createTopology method
+ * is used to create the topology file that would normally be read from disk.
+ * The driver.setupGateway invocation is where the creation of GATEWAY_HOME
+ * occurs.
+ * <p>
+ * This would normally be done once for this suite but the failure tests start
+ * affecting each other depending on the state the last 'active' url
+ *
+ * @throws Exception Thrown if any failure occurs.
+ */
+ public static void init(final String defaultTopologyName,
+ final ConcurrentHashMap<String, Integer> topologyPortMapping, final boolean isPortMappingEnabled)
+ throws Exception {
+ LOG_ENTER();
+
+ masterServer = new MockServer("master", true);
+ GatewayTestConfig config = new GatewayTestConfig();
+ config.setGatewayPath("gateway");
+
+ /* define default topology to be used */
+ if (defaultTopologyName != null) {
+ config.setDefaultTopologyName(defaultTopologyName);
+ }
+
+ if (topologyPortMapping != null) {
+ config.setTopologyPortMapping(topologyPortMapping);
+ }
+
+ config.setGatewayPortMappingEnabled(isPortMappingEnabled);
+
+ driver.setResourceBase(WebHdfsHaFuncTest.class);
+ driver.setupLdap(0);
+
+ driver.setupService("WEBHDFS", "http://vm.local:50070/webhdfs",
+ "/eerie/webhdfs", USE_MOCK_SERVICES);
+
+ driver.setupGateway(config, "eerie",
+ createTopology("WEBHDFS", driver.getLdapUrl(), masterServer.getPort()),
+ USE_GATEWAY);
+
+ LOG_EXIT();
+ }
+
+ public static void init(final String defaultTopologyName, final boolean isPortMappingEnabled)
+ throws Exception {
+ init(defaultTopologyName, null, isPortMappingEnabled);
+ }
+
+ public static void init(final String defaultTopologyName, final ConcurrentHashMap<String, Integer> topologyPortMapping)
+ throws Exception {
+ init(defaultTopologyName, topologyPortMapping, true);
+ }
+
+ /**
+ * Creates a topology that is deployed to the gateway instance for the test
+ * suite. Note that this topology is shared by all of the test methods in this
+ * suite.
+ *
+ * @param role role name
+ * @param ldapURL ldap url
+ * @param gatewayPort port for the gateway
+ * @return A populated XML structure for a topology file.
+ */
+ static XMLTag createTopology(final String role, final String ldapURL,
+ final int gatewayPort) {
+ return XMLDoc.newDocument(true).addRoot("topology").addTag("gateway")
+ .addTag("provider").addTag("role").addText("webappsec").addTag("name")
+ .addText("WebAppSec").addTag("enabled").addText("true").addTag("param")
+ .addTag("name").addText("csrf.enabled").addTag("value").addText("true")
+ .gotoParent().gotoParent().addTag("provider").addTag("role")
+ .addText("authentication").addTag("name").addText("ShiroProvider")
+ .addTag("enabled").addText("true").addTag("param").addTag("name")
+ .addText("main.ldapRealm").addTag("value")
+ .addText("org.apache.knox.gateway.shirorealm.KnoxLdapRealm")
+ .gotoParent().addTag("param").addTag("name")
+ .addText("main.ldapRealm.userDnTemplate").addTag("value")
+ .addText("uid={0},ou=people,dc=hadoop,dc=apache,dc=org").gotoParent()
+ .addTag("param").addTag("name")
+ .addText("main.ldapRealm.contextFactory.url").addTag("value")
+ .addText(ldapURL).gotoParent().addTag("param").addTag("name")
+ .addText("main.ldapRealm.contextFactory.authenticationMechanism")
+ .addTag("value").addText("simple").gotoParent().addTag("param")
+ .addTag("name").addText("urls./**").addTag("value")
+ .addText("authcBasic").gotoParent().gotoParent().addTag("provider")
+ .addTag("role").addText("identity-assertion").addTag("enabled")
+ .addText("true").addTag("name").addText("Default").gotoParent()
+ .addTag("provider").addTag("role").addText("authorization")
+ .addTag("enabled").addText("true").addTag("name").addText("AclsAuthz")
+ .gotoParent().addTag("param").addTag("name").addText("webhdfs-acl")
+ .addTag("value").addText("hdfs;*;*").gotoParent().addTag("provider")
+ .addTag("role").addText("ha").addTag("enabled").addText("true")
+ .addTag("name").addText("HaProvider").addTag("param").addTag("name")
+ .addText("WEBHDFS").addTag("value").addText(
+ "maxFailoverAttempts=3;failoverSleep=15;maxRetryAttempts=3;retrySleep=10;enabled=true")
+ .gotoParent().gotoRoot().addTag("service").addTag("role").addText(role)
+ .addTag("url").addText("http://localhost:" + gatewayPort + "/webhdfs")
+ .gotoRoot();
+ }
+
+ /**
+ * This utility method will return the next available port that can be used.
+ *
+ * @param min min port to check
+ * @param max max port to check
+ * @return Port that is available.
+ */
+ static int getAvailablePort(final int min, final int max) {
+
+ for (int i = min; i <= max; i++) {
+
+ if (!GatewayServer.isPortInUse(i)) {
+ return i;
+ }
+ }
+ // too bad
+ return -1;
+ }
+
+ void test(final String url) throws IOException {
+ String password = "hdfs-password";
+ String username = "hdfs";
+
+ masterServer.expect().method("GET").pathInfo("/webhdfs/v1/")
+ .queryParam("op", "LISTSTATUS").queryParam("user.name", username)
+ .respond().status(HttpStatus.SC_OK)
+ .content(driver.getResourceBytes("webhdfs-liststatus-success.json"))
+ .contentType("application/json");
+
+ given().auth().preemptive().basic(username, password)
+ .header("X-XSRF-Header", "jksdhfkhdsf").queryParam("op", "LISTSTATUS")
+ .then().log().ifError().statusCode(HttpStatus.SC_OK)
+ .body("FileStatuses.FileStatus[0].pathSuffix", is("app-logs")).when()
+ .get(url + "/v1/");
+ masterServer.isEmpty();
+ }
+}