You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by sd...@apache.org on 2015/08/14 09:28:43 UTC

[09/50] [abbrv] incubator-sentry git commit: SENTRY-647: Add e2e tests for Sqoop Sentry integration (Guoquan Shen, reviewed by Dapeng Sun)

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/98761811/sentry-tests/sentry-tests-sqoop/src/test/java/org/apache/sentry/tests/e2e/sqoop/TestServerScopeEndToEnd.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-sqoop/src/test/java/org/apache/sentry/tests/e2e/sqoop/TestServerScopeEndToEnd.java b/sentry-tests/sentry-tests-sqoop/src/test/java/org/apache/sentry/tests/e2e/sqoop/TestServerScopeEndToEnd.java
new file mode 100644
index 0000000..85bae92
--- /dev/null
+++ b/sentry-tests/sentry-tests-sqoop/src/test/java/org/apache/sentry/tests/e2e/sqoop/TestServerScopeEndToEnd.java
@@ -0,0 +1,185 @@
+/*
+ * 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.sentry.tests.e2e.sqoop;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.apache.sentry.core.model.sqoop.SqoopActionConstant;
+import org.apache.sqoop.client.SqoopClient;
+import org.apache.sqoop.model.MJob;
+import org.apache.sqoop.model.MLink;
+import org.apache.sqoop.model.MPrincipal;
+import org.apache.sqoop.model.MPrivilege;
+import org.apache.sqoop.model.MResource;
+import org.apache.sqoop.model.MRole;
+import org.apache.sqoop.security.SecurityError;
+import org.junit.Test;
+
+import com.google.common.collect.Lists;
+
+public class TestServerScopeEndToEnd extends AbstractSqoopSentryTestBase {
+
+  @Test
+  public void testServerScopePrivilege() throws Exception {
+    /**
+     * ADMIN_USER create two links and one job
+     */
+    SqoopClient client = sqoopServerRunner.getSqoopClient(ADMIN_USER);
+    MLink rdbmsLink = client.createLink("generic-jdbc-connector");
+    sqoopServerRunner.fillRdbmsLinkConfig(rdbmsLink);
+    sqoopServerRunner.saveLink(client, rdbmsLink);
+
+    MLink hdfsLink = client.createLink("hdfs-connector");
+    sqoopServerRunner.fillHdfsLink(hdfsLink);
+    sqoopServerRunner.saveLink(client, hdfsLink);
+
+    MJob job1 = client.createJob(hdfsLink.getPersistenceId(), rdbmsLink.getPersistenceId());
+    // set HDFS "FROM" config for the job, since the connector test case base class only has utilities for HDFS!
+    sqoopServerRunner.fillHdfsFromConfig(job1);
+    // set the RDBM "TO" config here
+    sqoopServerRunner.fillRdbmsToConfig(job1);
+    // create job
+    sqoopServerRunner.saveJob(client, job1);
+
+
+    MResource  sqoopServer1 = new MResource(SQOOP_SERVER_NAME, MResource.TYPE.SERVER);
+    /**
+     * ADMIN_USER grant read privilege on server SQOOP_SERVER_NAME to role1
+     */
+    MRole role1 = new MRole(ROLE1);
+    MPrincipal group1 = new MPrincipal(GROUP1, MPrincipal.TYPE.GROUP);
+    MPrivilege readPrivilege = new MPrivilege(sqoopServer1,SqoopActionConstant.READ, false);
+    client.createRole(role1);
+    client.grantRole(Lists.newArrayList(role1), Lists.newArrayList(group1));
+    client.grantPrivilege(Lists.newArrayList(new MPrincipal(role1.getName(), MPrincipal.TYPE.ROLE)),
+        Lists.newArrayList(readPrivilege));
+
+    /**
+     * ADMIN_USER grant write privilege on server SQOOP_SERVER_NAME to role2
+     * ADMIN_USER grant read privilege on connector all to role2 (for update link required)
+     * ADMIN_USER grant read privilege on link all to role2 (for update job required)
+     */
+    MRole role2 = new MRole(ROLE2);
+    MPrincipal group2 = new MPrincipal(GROUP2, MPrincipal.TYPE.GROUP);
+    MPrivilege writePrivilege = new MPrivilege(sqoopServer1,SqoopActionConstant.WRITE, false);
+    client.createRole(role2);
+
+    MResource allConnector = new MResource(SqoopActionConstant.ALL, MResource.TYPE.CONNECTOR);
+    MResource allLink = new MResource(SqoopActionConstant.ALL, MResource.TYPE.LINK);
+    MPrivilege readAllConPriv = new MPrivilege(allConnector,SqoopActionConstant.READ, false);
+    MPrivilege readAllLinkPriv = new MPrivilege(allLink,SqoopActionConstant.READ, false);
+
+    client.grantRole(Lists.newArrayList(role2), Lists.newArrayList(group2));
+    client.grantPrivilege(Lists.newArrayList(new MPrincipal(role2.getName(), MPrincipal.TYPE.ROLE)),
+        Lists.newArrayList(writePrivilege, readAllConPriv, readAllLinkPriv));
+
+    /**
+     * ADMIN_USER grant all privilege on server SQOOP_SERVER_NAME to role3
+     */
+    MRole role3 = new MRole(ROLE3);
+    MPrincipal group3 = new MPrincipal(GROUP3, MPrincipal.TYPE.GROUP);
+    MPrivilege allPrivilege = new MPrivilege(sqoopServer1,SqoopActionConstant.ALL_NAME, false);
+    client.createRole(role3);
+    client.grantRole(Lists.newArrayList(role3), Lists.newArrayList(group3));
+    client.grantPrivilege(Lists.newArrayList(new MPrincipal(role3.getName(), MPrincipal.TYPE.ROLE)),
+        Lists.newArrayList(allPrivilege));
+
+    /**
+     * user1 has only the read privilege on server SQOOP_SERVER_NAME to role1,
+     * so user1 can show connector, link and jobs. The user1 can't update the link and
+     * job
+     */
+    client = sqoopServerRunner.getSqoopClient(USER1);
+    try {
+      // show connector
+      assertTrue(client.getConnector("generic-jdbc-connector") != null);
+      assertTrue(client.getConnector("hdfs-connector") != null);
+      assertTrue(client.getConnectors().size() > 0);
+      // show link
+      assertTrue(client.getLink(hdfsLink.getPersistenceId()) != null);
+      assertTrue(client.getLink(rdbmsLink.getPersistenceId()) != null);
+      assertTrue(client.getLinks().size() == 2);
+      // show job
+      assertTrue(client.getJob(job1.getPersistenceId()) != null);
+      assertTrue(client.getJobs().size() == 1);
+    } catch (Exception e) {
+      fail("unexpected Authorization exception happend");
+    }
+    // user1 can't update link and job
+    try {
+      hdfsLink.setName("hdfs1_update_user1");
+      client.updateLink(hdfsLink);
+      fail("expected Authorization exception happend");
+    } catch (Exception e) {
+      assertCausedMessage(e, SecurityError.AUTH_0014.getMessage());
+    }
+
+    try {
+      job1.setName("job1_update_user1");
+      client.updateJob(job1);
+      fail("expected Authorization exception happend");
+    } catch (Exception e) {
+      assertCausedMessage(e, SecurityError.AUTH_0014.getMessage());
+    }
+
+    /**
+     * user2 has the write privilege on server SQOOP_SERVER_NAME to role2. In order to update link and job,
+     * user2 also has the read privilege on connector all and link all
+     * user2 can update link and jobs. The user2 can't show job
+     */
+    client = sqoopServerRunner.getSqoopClient(USER2);
+    try {
+      // update link and job
+      hdfsLink.setName("hdfs1_update_user2");
+      client.updateLink(hdfsLink);
+      job1.setName("job1_update_user2");
+      client.updateJob(job1);
+    } catch (Exception e) {
+      fail("unexpected Authorization exception happend");
+    }
+    // user2 can't show job
+    assertTrue(client.getJobs().size() == 0);
+
+    /**
+     * user3 has the all privilege on server SQOOP_SERVER_NAME to role3.
+     * user3 can do any operation on any sqoop resource
+     */
+    client = sqoopServerRunner.getSqoopClient(USER3);
+    try {
+      // show connector
+      assertTrue(client.getConnector("generic-jdbc-connector") != null);
+      assertTrue(client.getConnector("hdfs-connector") != null);
+      assertTrue(client.getConnectors().size() > 0);
+      // show link
+      assertTrue(client.getLink(hdfsLink.getPersistenceId()) != null);
+      assertTrue(client.getLink(rdbmsLink.getPersistenceId()) != null);
+      assertTrue(client.getLinks().size() == 2);
+      // show job
+      assertTrue(client.getJob(job1.getPersistenceId()) != null);
+      assertTrue(client.getJobs().size() == 1);
+      // update link
+      hdfsLink.setName("hdfs1_update_user3");
+      client.updateLink(hdfsLink);
+      // update job
+      job1.setName("job1_update_user3");
+      client.updateJob(job1);
+    } catch (Exception e) {
+      fail("unexpected Authorization exception happend");
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/98761811/sentry-tests/sentry-tests-sqoop/src/test/java/org/apache/sentry/tests/e2e/sqoop/TestShowPrivilege.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-sqoop/src/test/java/org/apache/sentry/tests/e2e/sqoop/TestShowPrivilege.java b/sentry-tests/sentry-tests-sqoop/src/test/java/org/apache/sentry/tests/e2e/sqoop/TestShowPrivilege.java
new file mode 100644
index 0000000..609239f
--- /dev/null
+++ b/sentry-tests/sentry-tests-sqoop/src/test/java/org/apache/sentry/tests/e2e/sqoop/TestShowPrivilege.java
@@ -0,0 +1,92 @@
+/*
+ * 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.sentry.tests.e2e.sqoop;
+
+import org.apache.sentry.core.model.sqoop.SqoopActionConstant;
+import org.apache.sentry.sqoop.SentrySqoopError;
+import org.apache.sqoop.client.SqoopClient;
+import org.apache.sqoop.model.MPrincipal;
+import org.apache.sqoop.model.MPrivilege;
+import org.apache.sqoop.model.MResource;
+import org.apache.sqoop.model.MRole;
+import org.junit.Test;
+
+import com.google.common.collect.Lists;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class TestShowPrivilege extends AbstractSqoopSentryTestBase {
+
+  @Test
+  public void testNotSupportShowOnUser() throws Exception {
+    SqoopClient client = sqoopServerRunner.getSqoopClient(ADMIN_USER);
+    MPrincipal user1 = new MPrincipal("not_support_user1", MPrincipal.TYPE.USER);
+    MResource resource1 = new MResource("all", MResource.TYPE.CONNECTOR);
+    try {
+      client.getPrivilegesByPrincipal(user1, resource1);
+      fail("expected not support exception happend");
+    } catch (Exception e) {
+      assertCausedMessage(e, SentrySqoopError.SHOW_PRIVILEGE_NOT_SUPPORTED_FOR_PRINCIPAL);
+    }
+  }
+
+  @Test
+  public void testNotSupportShowOnGroup() throws Exception {
+    SqoopClient client = sqoopServerRunner.getSqoopClient(ADMIN_USER);
+    MPrincipal group1 = new MPrincipal("not_support_group1", MPrincipal.TYPE.GROUP);
+    MResource resource1 = new MResource("all", MResource.TYPE.CONNECTOR);
+    try {
+      client.getPrivilegesByPrincipal(group1, resource1);
+      fail("expected not support exception happend");
+    } catch (Exception e) {
+      assertCausedMessage(e, SentrySqoopError.SHOW_PRIVILEGE_NOT_SUPPORTED_FOR_PRINCIPAL);
+    }
+  }
+
+  @Test
+  public void testShowPrivileges() throws Exception {
+    /**
+     * user1 belongs to group group1
+     * admin user grant role role1 to group group1
+     * admin user grant read privilege on connector all to role role1
+     */
+    SqoopClient client = sqoopServerRunner.getSqoopClient(ADMIN_USER);
+    MRole role1 = new MRole(ROLE1);
+    MPrincipal group1Princ = new MPrincipal(GROUP1, MPrincipal.TYPE.GROUP);
+    MPrincipal role1Princ = new MPrincipal(ROLE1, MPrincipal.TYPE.ROLE);
+    MResource allConnector = new MResource(SqoopActionConstant.ALL, MResource.TYPE.CONNECTOR);
+    MPrivilege readPriv = new MPrivilege(allConnector, SqoopActionConstant.READ, false);
+    client.createRole(role1);
+    client.grantRole(Lists.newArrayList(role1), Lists.newArrayList(group1Princ));
+    client.grantPrivilege(Lists.newArrayList(role1Princ), Lists.newArrayList(readPriv));
+
+    // user1 show privilege on role1
+    client = sqoopServerRunner.getSqoopClient(USER1);
+    assertTrue(client.getPrivilegesByPrincipal(role1Princ, allConnector).size() == 1);
+
+    // user2 can't show privilege on role1, because user2 doesn't belong to role1
+    client = sqoopServerRunner.getSqoopClient(USER2);
+    try {
+      client.getPrivilegesByPrincipal(role1Princ, allConnector);
+      fail("expected SentryAccessDeniedException happend");
+    } catch (Exception e) {
+      assertCausedMessage(e, "SentryAccessDeniedException");
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/98761811/sentry-tests/sentry-tests-sqoop/src/test/java/org/apache/sentry/tests/e2e/sqoop/TomcatSqoopRunner.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-sqoop/src/test/java/org/apache/sentry/tests/e2e/sqoop/TomcatSqoopRunner.java b/sentry-tests/sentry-tests-sqoop/src/test/java/org/apache/sentry/tests/e2e/sqoop/TomcatSqoopRunner.java
new file mode 100644
index 0000000..0d50574
--- /dev/null
+++ b/sentry-tests/sentry-tests-sqoop/src/test/java/org/apache/sentry/tests/e2e/sqoop/TomcatSqoopRunner.java
@@ -0,0 +1,320 @@
+/*
+ * 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.sentry.tests.e2e.sqoop;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import org.apache.sqoop.client.SqoopClient;
+import org.apache.sqoop.common.test.db.DatabaseProvider;
+import org.apache.sqoop.common.test.db.DatabaseProviderFactory;
+import org.apache.sqoop.common.test.db.TableName;
+import org.apache.sqoop.common.test.utils.NetworkUtils;
+import org.apache.sqoop.model.MConfigList;
+import org.apache.sqoop.model.MJob;
+import org.apache.sqoop.model.MLink;
+import org.apache.sqoop.model.MPersistableEntity;
+import org.apache.sqoop.test.minicluster.SqoopMiniCluster;
+import org.apache.sqoop.validation.Status;
+import org.codehaus.cargo.container.ContainerType;
+import org.codehaus.cargo.container.InstalledLocalContainer;
+import org.codehaus.cargo.container.configuration.ConfigurationType;
+import org.codehaus.cargo.container.configuration.LocalConfiguration;
+import org.codehaus.cargo.container.deployable.WAR;
+import org.codehaus.cargo.container.installer.Installer;
+import org.codehaus.cargo.container.installer.ZipURLInstaller;
+import org.codehaus.cargo.container.property.GeneralPropertySet;
+import org.codehaus.cargo.container.property.ServletPropertySet;
+import org.codehaus.cargo.container.tomcat.TomcatPropertySet;
+import org.codehaus.cargo.generic.DefaultContainerFactory;
+import org.codehaus.cargo.generic.configuration.DefaultConfigurationFactory;
+
+import com.google.common.base.Joiner;
+
+public class TomcatSqoopRunner {
+  private static final Logger LOG = Logger.getLogger(TomcatSqoopRunner.class);
+  private SqoopServerEnableSentry server;
+  private DatabaseProvider provider;
+  private String temporaryPath;
+
+  public TomcatSqoopRunner(String temporaryPath, String serverName, String sentrySite)
+      throws Exception {
+    this.temporaryPath = temporaryPath;
+    this.server = new SqoopServerEnableSentry(temporaryPath, serverName, sentrySite);
+    this.provider = DatabaseProviderFactory.getProvider(System.getProperties());
+  }
+
+  public void start() throws Exception {
+    server.start();
+    provider.start();
+  }
+
+  public void stop() throws Exception {
+    server.stop();
+    provider.stop();
+  }
+
+
+  /**
+   * create link.
+   *
+   * With asserts to make sure that it was created correctly.
+   * @param sqoopClient
+   * @param link
+   */
+  public void saveLink(SqoopClient client, MLink link) {
+    assertEquals(Status.OK, client.saveLink(link));
+    assertNotSame(MPersistableEntity.PERSISTANCE_ID_DEFAULT, link.getPersistenceId());
+  }
+
+  /**
+   * create link.
+   *
+   * With asserts to make sure that it was created correctly.
+   * @param sqoopClient
+   * @param link
+   */
+  public void updateLink(SqoopClient client, MLink link) {
+    assertEquals(Status.OK, client.updateLink(link));
+    assertNotSame(MPersistableEntity.PERSISTANCE_ID_DEFAULT, link.getPersistenceId());
+  }
+
+  /**
+   * Create job.
+   *
+   * With asserts to make sure that it was created correctly.
+   *
+   * @param job
+   */
+  public void saveJob(SqoopClient client, MJob job) {
+    assertEquals(Status.OK, client.saveJob(job));
+    assertNotSame(MPersistableEntity.PERSISTANCE_ID_DEFAULT, job.getPersistenceId());
+  }
+
+  /**
+   * fill link.
+   *
+   * With asserts to make sure that it was filled correctly.
+   *
+   * @param link
+   */
+  public void fillHdfsLink(MLink link) {
+    MConfigList configs = link.getConnectorLinkConfig();
+    configs.getStringInput("linkConfig.confDir").setValue(server.getConfigurationPath());
+  }
+
+  /**
+   * Fill link config based on currently active provider.
+   *
+   * @param link MLink object to fill
+   */
+  public void fillRdbmsLinkConfig(MLink link) {
+    MConfigList configs = link.getConnectorLinkConfig();
+    configs.getStringInput("linkConfig.jdbcDriver").setValue(provider.getJdbcDriver());
+    configs.getStringInput("linkConfig.connectionString").setValue(provider.getConnectionUrl());
+    configs.getStringInput("linkConfig.username").setValue(provider.getConnectionUsername());
+    configs.getStringInput("linkConfig.password").setValue(provider.getConnectionPassword());
+  }
+
+  public void fillHdfsFromConfig(MJob job) {
+    MConfigList fromConfig = job.getFromJobConfig();
+    fromConfig.getStringInput("fromJobConfig.inputDirectory").setValue(temporaryPath + "/output");
+  }
+
+  public void fillRdbmsToConfig(MJob job) {
+    MConfigList toConfig = job.getToJobConfig();
+    toConfig.getStringInput("toJobConfig.tableName").setValue(provider.
+        escapeTableName(new TableName(getClass().getSimpleName()).getTableName()));
+  }
+
+  /**
+   * get a sqoopClient for specific user
+   * @param user
+   */
+  public SqoopClient getSqoopClient(String user) {
+    setAuthenticationUser(user);
+    return new SqoopClient(server.getServerUrl());
+  }
+
+  /**
+   * Set the mock user in the Sqoop simple authentication
+   * @param user
+   */
+  private void setAuthenticationUser(String user) {
+    System.setProperty("user.name", user);
+  }
+
+  private static class SqoopServerEnableSentry extends SqoopMiniCluster {
+    private static final String WAR_PATH = "thirdparty/sqoop.war";
+    private static final String TOMCAT_PATH = "thirdparty/apache-tomcat-6.0.36.zip";
+
+    private InstalledLocalContainer container = null;
+    private Integer port;
+    private Integer ajpPort;
+    private String sentrySite;
+    private String serverName;
+
+    SqoopServerEnableSentry(String temporaryPath, String serverName, String sentrySite)
+        throws Exception {
+      super(temporaryPath);
+      this.serverName = serverName;
+      this.sentrySite = sentrySite;
+      // Random port
+      this.port = NetworkUtils.findAvailablePort();
+      this.ajpPort = NetworkUtils.findAvailablePort();
+    }
+
+    @Override
+    public Map<String, String> getSecurityConfiguration() {
+      Map<String, String> properties = new HashMap<String, String>();
+      configureAuthentication(properties);
+      configureSentryAuthorization(properties);
+      return properties;
+    }
+
+    private void configureAuthentication(Map<String, String> properties) {
+      /** Simple Authentication */
+      properties.put("org.apache.sqoop.authentication.type", "SIMPLE");
+      properties.put("org.apache.sqoop.authentication.handler",
+          "org.apache.sqoop.security.SimpleAuthenticationHandler");
+    }
+
+    private void configureSentryAuthorization(Map<String, String> properties) {
+      properties.put("org.apache.sqoop.security.authorization.handler",
+          "org.apache.sentry.sqoop.authz.SentryAuthorizationHander");
+      properties.put("org.apache.sqoop.security.authorization.access_controller",
+          "org.apache.sentry.sqoop.authz.SentryAccessController");
+      properties.put("org.apache.sqoop.security.authorization.validator",
+          "org.apache.sentry.sqoop.authz.SentryAuthorizationValidator");
+      properties.put("org.apache.sqoop.security.authorization.server_name", serverName);
+      properties.put("sentry.sqoop.site.url", sentrySite);
+      /** set Sentry related jars into classpath */
+      List<String> extraClassPath = new LinkedList<String>();
+      for (String jar : System.getProperty("java.class.path").split(":")) {
+        if ((jar.contains("sentry") || jar.contains("shiro-core") || jar.contains("libthrift"))
+            && jar.endsWith("jar")) {
+          extraClassPath.add(jar);
+        }
+      }
+      properties.put("org.apache.sqoop.classpath.extra",Joiner.on(":").join(extraClassPath));
+    }
+
+    @Override
+    public void start() throws Exception {
+      // Container has already been started
+      if (container != null) {
+        return;
+      }
+      prepareTemporaryPath();
+
+      // Source: http://cargo.codehaus.org/Functional+testing
+      String tomcatPath = getTemporaryPath() + "/tomcat";
+      String extractPath = tomcatPath + "/extract";
+      String confPath = tomcatPath + "/conf";
+
+      Installer installer = new ZipURLInstaller(new File(TOMCAT_PATH).toURI().toURL(), null, extractPath);
+      installer.install();
+
+      LocalConfiguration configuration = (LocalConfiguration) new DefaultConfigurationFactory()
+          .createConfiguration("tomcat6x", ContainerType.INSTALLED, ConfigurationType.STANDALONE,
+              confPath);
+      container = (InstalledLocalContainer) new DefaultContainerFactory().createContainer("tomcat6x",
+          ContainerType.INSTALLED, configuration);
+
+      // Set home to our installed tomcat instance
+      container.setHome(installer.getHome());
+
+      // Store tomcat logs into file as they are quite handy for debugging
+      container.setOutput(getTemporaryPath() + "/log/tomcat.log");
+
+      // Propagate system properties to the container
+      Map<String, String> map = new HashMap<String, String>((Map) System.getProperties());
+      container.setSystemProperties(map);
+
+      // Propagate Hadoop jars to the container classpath
+      // In real world, they would be installed manually by user
+      List<String> extraClassPath = new LinkedList<String>();
+      String[] classpath = System.getProperty("java.class.path").split(":");
+      for (String jar : classpath) {
+        if (jar.contains("hadoop-") || // Hadoop jars
+            jar.contains("hive-") || // Hive jars
+            jar.contains("commons-") || // Apache Commons libraries
+            jar.contains("httpcore-") || // Apache Http Core libraries
+            jar.contains("httpclient-") || // Apache Http Client libraries
+            jar.contains("htrace-") || // htrace-core libraries, new added in
+                                       // Hadoop 2.6.0
+            jar.contains("zookeeper-") || // zookeeper libraries, new added in
+                                          // Hadoop 2.6.0
+            jar.contains("curator-") || // curator libraries, new added in Hadoop
+                                        // 2.6.0
+            jar.contains("log4j-") || // Log4j
+            jar.contains("slf4j-") || // Slf4j
+            jar.contains("jackson-") || // Jackson
+            jar.contains("derby") || // Derby drivers
+            jar.contains("avro-") || // Avro
+            jar.contains("parquet-") || // Parquet
+            jar.contains("mysql") || // MySQL JDBC driver
+            jar.contains("postgre") || // PostgreSQL JDBC driver
+            jar.contains("oracle") || // Oracle driver
+            jar.contains("terajdbc") || // Teradata driver
+            jar.contains("tdgs") || // Teradata driver
+            jar.contains("nzjdbc") || // Netezza driver
+            jar.contains("sqljdbc") || // Microsoft SQL Server driver
+            jar.contains("libfb303") || // Facebook thrift lib
+            jar.contains("datanucleus-") || // Data nucleus libs
+            jar.contains("google") // Google libraries (guava, ...)
+        ) {
+          extraClassPath.add(jar);
+        }
+      }
+      container.setExtraClasspath(extraClassPath.toArray(new String[extraClassPath.size()]));
+
+      // Finally deploy Sqoop server war file
+      configuration.addDeployable(new WAR(WAR_PATH));
+      configuration.setProperty(ServletPropertySet.PORT, port.toString());
+      configuration.setProperty(TomcatPropertySet.AJP_PORT, ajpPort.toString());
+      //configuration.setProperty(GeneralPropertySet.JVMARGS, "\"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8006\"");
+      LOG.info("Tomcat extract path: " + extractPath);
+      LOG.info("Tomcat home path: " + installer.getHome());
+      LOG.info("Tomcat config home path: " + confPath);
+      LOG.info("Starting tomcat server on port " + port);
+      container.start();
+    }
+
+    @Override
+    public void stop() throws Exception {
+      if (container != null) {
+        container.stop();
+      }
+    }
+
+    /**
+     * Return server URL.
+     */
+    public String getServerUrl() {
+      // We're not doing any changes, so return default URL
+      return "http://localhost:" + port + "/sqoop/";
+    }
+  }
+}