mirror of
https://github.com/apache/sqoop.git
synced 2025-05-17 09:20:43 +08:00
SQOOP-2843: Sqoop2: Enable SSL/TLS for API calls
(Abraham Fine via Jarek Jarcec Cecho)
This commit is contained in:
parent
9aec8f965e
commit
96f3d9c195
@ -36,6 +36,13 @@ public final class SecurityConstants {
|
|||||||
public static final String PREFIX_AUTHENTICATION_CONFIG =
|
public static final String PREFIX_AUTHENTICATION_CONFIG =
|
||||||
PREFIX_SECURITY_CONFIG + "authentication.";
|
PREFIX_SECURITY_CONFIG + "authentication.";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All tls related configuration is prefixed with this:
|
||||||
|
* <tt>org.apache.sqoop.security.tls.</tt>
|
||||||
|
*/
|
||||||
|
public static final String PREFIX_TLS_CONFIG =
|
||||||
|
PREFIX_SECURITY_CONFIG + "tls.";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The config specifies the sqoop authentication type (SIMPLE, KERBEROS).
|
* The config specifies the sqoop authentication type (SIMPLE, KERBEROS).
|
||||||
* The default type is SIMPLE
|
* The default type is SIMPLE
|
||||||
@ -157,6 +164,42 @@ public final class SecurityConstants {
|
|||||||
public static final String SERVER_NAME =
|
public static final String SERVER_NAME =
|
||||||
PREFIX_AUTHORIZATION_CONFIG + "server_name";
|
PREFIX_AUTHORIZATION_CONFIG + "server_name";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The config specifies the whether the http server should use TLS.
|
||||||
|
* <tt>org.apache.sqoop.security.tls.enabled</tt>.
|
||||||
|
*/
|
||||||
|
public static final String TLS_ENABLED =
|
||||||
|
PREFIX_TLS_CONFIG + "enabled";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The config specifies the tls protocol version
|
||||||
|
* <tt>org.apache.sqoop.security.tls.protocol</tt>.
|
||||||
|
*/
|
||||||
|
public static final String TLS_PROTOCOL =
|
||||||
|
PREFIX_TLS_CONFIG + "protocol";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The config specifies the location of the JKS formatted keystore
|
||||||
|
* <tt>org.apache.sqoop.security.tls.keystore</tt>.
|
||||||
|
*/
|
||||||
|
public static final String KEYSTORE_LOCATION =
|
||||||
|
PREFIX_TLS_CONFIG + "keystore";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The config specifies the password of the JKS formatted keystore
|
||||||
|
* <tt>org.apache.sqoop.security.tls.keystorepassword</tt>.
|
||||||
|
*/
|
||||||
|
public static final String KEYSTORE_PASSWORD =
|
||||||
|
PREFIX_TLS_CONFIG + "keystore_password";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The config specifies the password for the private key in the JKS formatted
|
||||||
|
* keystore
|
||||||
|
* <tt>org.apache.sqoop.security.tls.keymanagerpassword</tt>.
|
||||||
|
*/
|
||||||
|
public static final String KEYMANAGER_PASSWORD =
|
||||||
|
PREFIX_TLS_CONFIG + "keymanager_password";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The config specifies the token kind in delegation token.
|
* The config specifies the token kind in delegation token.
|
||||||
*/
|
*/
|
||||||
|
9
dist/src/main/conf/sqoop.properties
vendored
9
dist/src/main/conf/sqoop.properties
vendored
@ -180,6 +180,15 @@ org.apache.sqoop.execution.engine=org.apache.sqoop.execution.mapreduce.Mapreduce
|
|||||||
#org.apache.sqoop.security.authorization.authentication_provider=org.apache.sqoop.security.authorization.DefaultAuthenticationProvider
|
#org.apache.sqoop.security.authorization.authentication_provider=org.apache.sqoop.security.authorization.DefaultAuthenticationProvider
|
||||||
#org.apache.sqoop.security.authorization.server_name=SqoopServer1
|
#org.apache.sqoop.security.authorization.server_name=SqoopServer1
|
||||||
|
|
||||||
|
#
|
||||||
|
# SSL/TLS configuration
|
||||||
|
#
|
||||||
|
#org.apache.sqoop.security.tls.enabled=false
|
||||||
|
#org.apache.sqoop.security.tls.protocol="TLSv1.2"
|
||||||
|
#org.apache.sqoop.security.tls.keystore=
|
||||||
|
#org.apache.sqoop.security.tls.keystore_password=
|
||||||
|
|
||||||
|
|
||||||
# External connectors load path
|
# External connectors load path
|
||||||
# "/path/to/external/connectors/": Add all the connector JARs in the specified folder
|
# "/path/to/external/connectors/": Add all the connector JARs in the specified folder
|
||||||
#
|
#
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.apache.sqoop.docs.generator.plugins.AbstractPlugin;
|
import org.apache.sqoop.docs.generator.plugins.AbstractPlugin;
|
||||||
import org.apache.sqoop.docs.generator.plugins.CopySourceToDestination;
|
import org.apache.sqoop.docs.generator.plugins.CopySourceToDestination;
|
||||||
|
import org.apache.sqoop.docs.generator.plugins.GenerateConnectorPages;
|
||||||
import org.apache.sqoop.utils.ClassUtils;
|
import org.apache.sqoop.utils.ClassUtils;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@ -36,6 +37,7 @@ public class DocPreprocessor {
|
|||||||
static {
|
static {
|
||||||
plugins = new LinkedList<>();
|
plugins = new LinkedList<>();
|
||||||
plugins.add(CopySourceToDestination.class);
|
plugins.add(CopySourceToDestination.class);
|
||||||
|
plugins.add(GenerateConnectorPages.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String []args) {
|
public static void main(String []args) {
|
||||||
|
@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* 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.sqoop.docs.generator.plugins;
|
||||||
|
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
import org.apache.sqoop.connector.ConnectorHandler;
|
||||||
|
import org.apache.sqoop.connector.ConnectorManagerUtils;
|
||||||
|
import org.apache.sqoop.connector.spi.SqoopConnector;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class GenerateConnectorPages extends AbstractPlugin {
|
||||||
|
|
||||||
|
private static final Logger LOG = Logger.getLogger(GenerateConnectorPages.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
runWithException();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Can't generate connector documentation", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runWithException() throws IOException {
|
||||||
|
List<URL> connectorUrls = ConnectorManagerUtils.getConnectorConfigs(Collections.<String>emptySet());
|
||||||
|
for (URL url : connectorUrls) {
|
||||||
|
SqoopConnector connector = new ConnectorHandler(url).getSqoopConnector();
|
||||||
|
LOG.info("Loaded " + connector.getConnectorName() + " from " + url.toString());
|
||||||
|
|
||||||
|
String connectorName = connector.getConnectorName();
|
||||||
|
|
||||||
|
File outputFile = FileUtils.getFile(getDestination(), "user", "connectors", connectorName + ".rst");
|
||||||
|
PrintWriter writer = new PrintWriter(outputFile);
|
||||||
|
|
||||||
|
// Writing headline
|
||||||
|
writer.println(connectorName);
|
||||||
|
writer.println(StringUtils.repeat("=", connectorName.length()));
|
||||||
|
|
||||||
|
writer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -19,12 +19,21 @@
|
|||||||
package org.apache.sqoop.server;
|
package org.apache.sqoop.server;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
import org.apache.sqoop.common.MapContext;
|
||||||
|
import org.apache.sqoop.common.SqoopException;
|
||||||
import org.apache.sqoop.core.SqoopConfiguration;
|
import org.apache.sqoop.core.SqoopConfiguration;
|
||||||
import org.apache.sqoop.core.SqoopServer;
|
import org.apache.sqoop.core.SqoopServer;
|
||||||
import org.apache.sqoop.filter.SqoopAuthenticationFilter;
|
import org.apache.sqoop.filter.SqoopAuthenticationFilter;
|
||||||
|
import org.apache.sqoop.security.SecurityConstants;
|
||||||
|
import org.apache.sqoop.server.common.ServerError;
|
||||||
import org.apache.sqoop.server.v1.*;
|
import org.apache.sqoop.server.v1.*;
|
||||||
|
import org.eclipse.jetty.server.HttpConfiguration;
|
||||||
|
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||||
|
import org.eclipse.jetty.server.SecureRequestCustomizer;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.server.SslConnectionFactory;
|
||||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||||
|
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||||
import org.eclipse.jetty.util.thread.ExecutorThreadPool;
|
import org.eclipse.jetty.util.thread.ExecutorThreadPool;
|
||||||
import org.eclipse.jetty.server.ServerConnector;
|
import org.eclipse.jetty.server.ServerConnector;
|
||||||
|
|
||||||
@ -58,7 +67,45 @@ public SqoopJettyServer() {
|
|||||||
webServer = new Server(threadPool);
|
webServer = new Server(threadPool);
|
||||||
|
|
||||||
// Connector configs
|
// Connector configs
|
||||||
ServerConnector connector = new ServerConnector(webServer);
|
ServerConnector connector;
|
||||||
|
|
||||||
|
MapContext configurationContext = SqoopConfiguration.getInstance().getContext();
|
||||||
|
|
||||||
|
if (configurationContext.getBoolean(SecurityConstants.TLS_ENABLED, false)) {
|
||||||
|
String keyStorePath = configurationContext.getString(SecurityConstants.KEYSTORE_LOCATION);
|
||||||
|
if (keyStorePath == null) {
|
||||||
|
throw new SqoopException(ServerError.SERVER_0007);
|
||||||
|
}
|
||||||
|
|
||||||
|
SslContextFactory sslContextFactory = new SslContextFactory();
|
||||||
|
sslContextFactory.setKeyStorePath(keyStorePath);
|
||||||
|
|
||||||
|
String protocol = configurationContext.getString(SecurityConstants.TLS_PROTOCOL);
|
||||||
|
if (protocol != null && protocol.length() > 0) {
|
||||||
|
sslContextFactory.setProtocol(protocol.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
String keyStorePassword = configurationContext.getString(SecurityConstants.KEYSTORE_PASSWORD);
|
||||||
|
if (keyStorePassword != null && keyStorePassword.length() > 0) {
|
||||||
|
sslContextFactory.setKeyStorePassword(keyStorePassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
String keyManagerPassword = configurationContext.getString(SecurityConstants.KEYMANAGER_PASSWORD);
|
||||||
|
if (keyManagerPassword != null && keyManagerPassword.length() > 0) {
|
||||||
|
sslContextFactory.setKeyManagerPassword(keyManagerPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpConfiguration https = new HttpConfiguration();
|
||||||
|
https.addCustomizer(new SecureRequestCustomizer());
|
||||||
|
|
||||||
|
connector = new ServerConnector(webServer,
|
||||||
|
new SslConnectionFactory(sslContextFactory, "http/1.1"),
|
||||||
|
new HttpConnectionFactory(https));
|
||||||
|
} else {
|
||||||
|
connector = new ServerConnector(webServer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
connector.setPort(sqoopJettyContext.getPort());
|
connector.setPort(sqoopJettyContext.getPort());
|
||||||
webServer.addConnector(connector);
|
webServer.addConnector(connector);
|
||||||
webServer.setHandler(createServletContextHandler());
|
webServer.setHandler(createServletContextHandler());
|
||||||
|
@ -38,6 +38,9 @@ public enum ServerError implements ErrorCode {
|
|||||||
|
|
||||||
/** Entity requested doesn't exist*/
|
/** Entity requested doesn't exist*/
|
||||||
SERVER_0006("Entity requested doesn't exist"),
|
SERVER_0006("Entity requested doesn't exist"),
|
||||||
|
|
||||||
|
/** TLS enabled but keystore location not set*/
|
||||||
|
SERVER_0007("TLS enabled but keystore location not set"),
|
||||||
;
|
;
|
||||||
|
|
||||||
private final String message;
|
private final String message;
|
||||||
|
@ -21,12 +21,14 @@
|
|||||||
import org.apache.sqoop.common.SqoopException;
|
import org.apache.sqoop.common.SqoopException;
|
||||||
import org.apache.sqoop.shell.core.ShellError;
|
import org.apache.sqoop.shell.core.ShellError;
|
||||||
import org.apache.sqoop.shell.core.Constants;
|
import org.apache.sqoop.shell.core.Constants;
|
||||||
|
import org.apache.sqoop.shell.utils.TableDisplayer;
|
||||||
import org.codehaus.groovy.tools.shell.IO;
|
import org.codehaus.groovy.tools.shell.IO;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
@ -57,6 +59,13 @@ private ShellEnvironment() {
|
|||||||
private static boolean interactive = false;
|
private static boolean interactive = false;
|
||||||
private static long pollTimeout = DEFAULT_POLL_TIMEOUT;
|
private static long pollTimeout = DEFAULT_POLL_TIMEOUT;
|
||||||
|
|
||||||
|
private static TableDisplayer tableDisplayer = new TableDisplayer(new TableDisplayer.TableDisplayerWriter() {
|
||||||
|
@Override
|
||||||
|
public void append(String text) {
|
||||||
|
print(text);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
static ResourceBundle resource = ResourceBundle.getBundle(Constants.RESOURCE_NAME, Locale.getDefault());
|
static ResourceBundle resource = ResourceBundle.getBundle(Constants.RESOURCE_NAME, Locale.getDefault());
|
||||||
static SqoopClient client = new SqoopClient(getServerUrl());
|
static SqoopClient client = new SqoopClient(getServerUrl());
|
||||||
static IO io;
|
static IO io;
|
||||||
@ -226,6 +235,10 @@ public static void print(String format, Object... args) {
|
|||||||
io.out.printf(format, args);
|
io.out.printf(format, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void displayTable(List<String> headers, List<String> ...columns) {
|
||||||
|
tableDisplayer.display(headers, columns);
|
||||||
|
}
|
||||||
|
|
||||||
// for tests only
|
// for tests only
|
||||||
public static void cleanup() {
|
public static void cleanup() {
|
||||||
serverHost = DEFAULT_SERVER_HOST;
|
serverHost = DEFAULT_SERVER_HOST;
|
||||||
|
@ -27,7 +27,6 @@
|
|||||||
import org.apache.sqoop.common.SqoopException;
|
import org.apache.sqoop.common.SqoopException;
|
||||||
import org.apache.sqoop.model.MConnector;
|
import org.apache.sqoop.model.MConnector;
|
||||||
import org.apache.sqoop.shell.core.Constants;
|
import org.apache.sqoop.shell.core.Constants;
|
||||||
import org.apache.sqoop.shell.utils.TableDisplayer;
|
|
||||||
import org.apache.sqoop.validation.Status;
|
import org.apache.sqoop.validation.Status;
|
||||||
|
|
||||||
import static org.apache.sqoop.shell.ShellEnvironment.*;
|
import static org.apache.sqoop.shell.ShellEnvironment.*;
|
||||||
@ -83,7 +82,7 @@ private void showSummary() {
|
|||||||
supportedDirections.add(connector.getSupportedDirections().toString());
|
supportedDirections.add(connector.getSupportedDirections().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
TableDisplayer.display(header, uniqueNames, versions, classes, supportedDirections);
|
displayTable(header, uniqueNames, versions, classes, supportedDirections);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showConnectors() {
|
private void showConnectors() {
|
||||||
|
@ -19,12 +19,8 @@
|
|||||||
|
|
||||||
import org.apache.commons.cli.CommandLine;
|
import org.apache.commons.cli.CommandLine;
|
||||||
import org.apache.commons.cli.OptionBuilder;
|
import org.apache.commons.cli.OptionBuilder;
|
||||||
import org.apache.sqoop.common.Direction;
|
|
||||||
import org.apache.sqoop.model.MConnector;
|
|
||||||
import org.apache.sqoop.model.MJob;
|
import org.apache.sqoop.model.MJob;
|
||||||
import org.apache.sqoop.model.MLink;
|
|
||||||
import org.apache.sqoop.shell.core.Constants;
|
import org.apache.sqoop.shell.core.Constants;
|
||||||
import org.apache.sqoop.shell.utils.TableDisplayer;
|
|
||||||
import org.apache.sqoop.validation.Status;
|
import org.apache.sqoop.validation.Status;
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
@ -97,7 +93,7 @@ private void showSummary() {
|
|||||||
availabilities.add(String.valueOf(job.getEnabled()));
|
availabilities.add(String.valueOf(job.getEnabled()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TableDisplayer.display(header, ids, names, fromConnectors, toConnectors, availabilities);
|
displayTable(header, ids, names, fromConnectors, toConnectors, availabilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showJobs(String jArg) {
|
private void showJobs(String jArg) {
|
||||||
|
@ -19,19 +19,13 @@
|
|||||||
|
|
||||||
import org.apache.commons.cli.CommandLine;
|
import org.apache.commons.cli.CommandLine;
|
||||||
import org.apache.commons.cli.OptionBuilder;
|
import org.apache.commons.cli.OptionBuilder;
|
||||||
import org.apache.sqoop.common.SqoopException;
|
|
||||||
import org.apache.sqoop.model.MConnector;
|
|
||||||
import org.apache.sqoop.model.MLink;
|
import org.apache.sqoop.model.MLink;
|
||||||
import org.apache.sqoop.shell.core.Constants;
|
import org.apache.sqoop.shell.core.Constants;
|
||||||
import org.apache.sqoop.shell.utils.TableDisplayer;
|
|
||||||
import org.apache.sqoop.validation.Status;
|
import org.apache.sqoop.validation.Status;
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static org.apache.sqoop.shell.ShellEnvironment.*;
|
import static org.apache.sqoop.shell.ShellEnvironment.*;
|
||||||
import static org.apache.sqoop.shell.utils.ConfigDisplayer.*;
|
import static org.apache.sqoop.shell.utils.ConfigDisplayer.*;
|
||||||
@ -86,7 +80,7 @@ private void showSummary() {
|
|||||||
availabilities.add(String.valueOf(link.getEnabled()));
|
availabilities.add(String.valueOf(link.getEnabled()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TableDisplayer.display(header, names, connectorNames, availabilities);
|
displayTable(header, names, connectorNames, availabilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showLinks() {
|
private void showLinks() {
|
||||||
|
@ -22,13 +22,13 @@
|
|||||||
import org.apache.sqoop.model.MPrincipal;
|
import org.apache.sqoop.model.MPrincipal;
|
||||||
import org.apache.sqoop.model.MRole;
|
import org.apache.sqoop.model.MRole;
|
||||||
import org.apache.sqoop.shell.core.Constants;
|
import org.apache.sqoop.shell.core.Constants;
|
||||||
import org.apache.sqoop.shell.utils.TableDisplayer;
|
|
||||||
import org.apache.sqoop.validation.Status;
|
import org.apache.sqoop.validation.Status;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.apache.sqoop.shell.ShellEnvironment.client;
|
import static org.apache.sqoop.shell.ShellEnvironment.client;
|
||||||
|
import static org.apache.sqoop.shell.ShellEnvironment.displayTable;
|
||||||
import static org.apache.sqoop.shell.ShellEnvironment.resourceString;
|
import static org.apache.sqoop.shell.ShellEnvironment.resourceString;
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
@ -70,6 +70,6 @@ private void showPrincipals(MRole role) {
|
|||||||
types.add(principal.getType());
|
types.add(principal.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
TableDisplayer.display(header, names, types);
|
displayTable(header, names, types);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,13 +25,13 @@
|
|||||||
import org.apache.sqoop.model.MResource;
|
import org.apache.sqoop.model.MResource;
|
||||||
import org.apache.sqoop.shell.core.Constants;
|
import org.apache.sqoop.shell.core.Constants;
|
||||||
import org.apache.sqoop.shell.core.ShellError;
|
import org.apache.sqoop.shell.core.ShellError;
|
||||||
import org.apache.sqoop.shell.utils.TableDisplayer;
|
|
||||||
import org.apache.sqoop.validation.Status;
|
import org.apache.sqoop.validation.Status;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.apache.sqoop.shell.ShellEnvironment.client;
|
import static org.apache.sqoop.shell.ShellEnvironment.client;
|
||||||
|
import static org.apache.sqoop.shell.ShellEnvironment.displayTable;
|
||||||
import static org.apache.sqoop.shell.ShellEnvironment.resourceString;
|
import static org.apache.sqoop.shell.ShellEnvironment.resourceString;
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
@ -108,6 +108,6 @@ private void showPrivileges(MPrincipal principal, MResource resource) {
|
|||||||
withGrant.add(Boolean.toString(privilege.isWith_grant_option()));
|
withGrant.add(Boolean.toString(privilege.isWith_grant_option()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TableDisplayer.display(header, actions, resourceNames, resourceTypes, withGrant);
|
displayTable(header, actions, resourceNames, resourceTypes, withGrant);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,13 +24,13 @@
|
|||||||
import org.apache.sqoop.model.MRole;
|
import org.apache.sqoop.model.MRole;
|
||||||
import org.apache.sqoop.shell.core.Constants;
|
import org.apache.sqoop.shell.core.Constants;
|
||||||
import org.apache.sqoop.shell.core.ShellError;
|
import org.apache.sqoop.shell.core.ShellError;
|
||||||
import org.apache.sqoop.shell.utils.TableDisplayer;
|
|
||||||
import org.apache.sqoop.validation.Status;
|
import org.apache.sqoop.validation.Status;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.apache.sqoop.shell.ShellEnvironment.client;
|
import static org.apache.sqoop.shell.ShellEnvironment.client;
|
||||||
|
import static org.apache.sqoop.shell.ShellEnvironment.displayTable;
|
||||||
import static org.apache.sqoop.shell.ShellEnvironment.resourceString;
|
import static org.apache.sqoop.shell.ShellEnvironment.resourceString;
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
@ -83,6 +83,6 @@ private void showRoles(MPrincipal principal) {
|
|||||||
names.add(role.getName());
|
names.add(role.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
TableDisplayer.display(header, names);
|
displayTable(header, names);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
import org.apache.sqoop.model.MSubmission;
|
import org.apache.sqoop.model.MSubmission;
|
||||||
import org.apache.sqoop.shell.core.Constants;
|
import org.apache.sqoop.shell.core.Constants;
|
||||||
import org.apache.sqoop.shell.utils.SubmissionDisplayer;
|
import org.apache.sqoop.shell.utils.SubmissionDisplayer;
|
||||||
import org.apache.sqoop.shell.utils.TableDisplayer;
|
|
||||||
import org.apache.sqoop.validation.Status;
|
import org.apache.sqoop.validation.Status;
|
||||||
|
|
||||||
import static org.apache.sqoop.shell.ShellEnvironment.*;
|
import static org.apache.sqoop.shell.ShellEnvironment.*;
|
||||||
@ -91,7 +90,7 @@ private void showSummary(String jArg) {
|
|||||||
dates.add(submission.getLastUpdateDate().toString());
|
dates.add(submission.getLastUpdateDate().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
TableDisplayer.display(header, jnames, eids, status, dates);
|
displayTable(header, jnames, eids, status, dates);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showSubmissions(String jArg) {
|
private void showSubmissions(String jArg) {
|
||||||
|
@ -22,23 +22,43 @@
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.apache.sqoop.shell.ShellEnvironment.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display table based data
|
* Display table based data
|
||||||
*/
|
*/
|
||||||
public class TableDisplayer {
|
public class TableDisplayer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface that this displayer will use to write out formatted text.
|
||||||
|
*/
|
||||||
|
public interface TableDisplayerWriter {
|
||||||
|
/**
|
||||||
|
* Print out addition formatted text to the output
|
||||||
|
*
|
||||||
|
* @param text
|
||||||
|
*/
|
||||||
|
void append(String text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TableDisplayer(TableDisplayerWriter writer) {
|
||||||
|
this.writer = writer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writer instance that we should use to write something out
|
||||||
|
*/
|
||||||
|
private TableDisplayerWriter writer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display given columns in nice table structure to given IO object.
|
* Display given columns in nice table structure to given IO object.
|
||||||
*
|
*
|
||||||
* @param headers List of headers
|
* @param headers List of headers
|
||||||
* @param columns Array of columns
|
* @param columns Array of columns
|
||||||
*/
|
*/
|
||||||
public static void display(List<String> headers, List<String> ...columns) {
|
public void display(List<String> headers, List<String> ...columns) {
|
||||||
assert headers != null;
|
assert headers != null;
|
||||||
assert columns != null;
|
assert columns != null;
|
||||||
assert headers.size() == columns.length;
|
assert headers.size() == columns.length;
|
||||||
|
assert writer != null;
|
||||||
|
|
||||||
// Count of columns
|
// Count of columns
|
||||||
int columnCount = headers.size();
|
int columnCount = headers.size();
|
||||||
@ -85,7 +105,7 @@ public static void display(List<String> headers, List<String> ...columns) {
|
|||||||
*
|
*
|
||||||
* @param widths List of widths of each column
|
* @param widths List of widths of each column
|
||||||
*/
|
*/
|
||||||
private static void drawLine(List<Integer> widths) {
|
private void drawLine(List<Integer> widths) {
|
||||||
int last = widths.size() - 1;
|
int last = widths.size() - 1;
|
||||||
print("+-");
|
print("+-");
|
||||||
for(int i = 0; i < widths.size(); i++) {
|
for(int i = 0; i < widths.size(); i++) {
|
||||||
@ -102,7 +122,7 @@ private static void drawLine(List<Integer> widths) {
|
|||||||
* @param column All column values
|
* @param column All column values
|
||||||
* @return Maximal
|
* @return Maximal
|
||||||
*/
|
*/
|
||||||
private static int getMaximalWidth(String header, List<String> column) {
|
private int getMaximalWidth(String header, List<String> column) {
|
||||||
assert header != null;
|
assert header != null;
|
||||||
assert column != null;
|
assert column != null;
|
||||||
|
|
||||||
@ -123,7 +143,7 @@ private static int getMaximalWidth(String header, List<String> column) {
|
|||||||
* @param columns Array with all column values
|
* @param columns Array with all column values
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private static int getMaximalRows(List<String>... columns) {
|
private int getMaximalRows(List<String>... columns) {
|
||||||
int max = 0;
|
int max = 0;
|
||||||
|
|
||||||
for(List<String> column : columns) {
|
for(List<String> column : columns) {
|
||||||
@ -135,7 +155,12 @@ private static int getMaximalRows(List<String>... columns) {
|
|||||||
return max;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TableDisplayer() {
|
private void print(String text) {
|
||||||
// Instantiation is prohibited
|
writer.append(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void println() {
|
||||||
|
writer.append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -274,17 +274,17 @@ limitations under the License.
|
|||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
<execution>
|
<execution>
|
||||||
<id>connector-loading-test</id>
|
<id>server-properties-test</id>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>test</goal>
|
<goal>test</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<phase>integration-test</phase>
|
<phase>integration-test</phase>
|
||||||
<configuration>
|
<configuration>
|
||||||
<suiteXmlFiles>
|
<suiteXmlFiles>
|
||||||
<suiteXmlFile>src/test/resources/connector-loading-tests-suite.xml</suiteXmlFile>
|
<suiteXmlFile>src/test/resources/server-properties-tests-suite.xml</suiteXmlFile>
|
||||||
</suiteXmlFiles>
|
</suiteXmlFiles>
|
||||||
<properties>
|
<properties>
|
||||||
<suitename>connector-loading-tests</suitename>
|
<suitename>server-properties-tests</suitename>
|
||||||
</properties>
|
</properties>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
|
@ -18,31 +18,12 @@
|
|||||||
package org.apache.sqoop.test.kdc;
|
package org.apache.sqoop.test.kdc;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
import java.security.InvalidKeyException;
|
|
||||||
import java.security.Key;
|
|
||||||
import java.security.KeyPair;
|
|
||||||
import java.security.KeyPairGenerator;
|
|
||||||
import java.security.KeyStore;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.NoSuchProviderException;
|
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
import java.security.PrivilegedActionException;
|
import java.security.PrivilegedActionException;
|
||||||
import java.security.PrivilegedExceptionAction;
|
import java.security.PrivilegedExceptionAction;
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.security.SignatureException;
|
|
||||||
import java.security.cert.Certificate;
|
|
||||||
import java.security.cert.CertificateEncodingException;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -53,19 +34,16 @@
|
|||||||
import javax.security.auth.Subject;
|
import javax.security.auth.Subject;
|
||||||
import javax.security.auth.login.AppConfigurationEntry;
|
import javax.security.auth.login.AppConfigurationEntry;
|
||||||
import javax.security.auth.login.LoginContext;
|
import javax.security.auth.login.LoginContext;
|
||||||
import javax.security.auth.x500.X500Principal;
|
|
||||||
|
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.minikdc.MiniKdc;
|
import org.apache.hadoop.minikdc.MiniKdc;
|
||||||
import org.apache.hadoop.security.ssl.FileBasedKeyStoresFactory;
|
|
||||||
import org.apache.hadoop.security.ssl.SSLFactory;
|
|
||||||
import org.apache.hadoop.security.token.delegation.web.DelegationTokenAuthenticatedURL;
|
import org.apache.hadoop.security.token.delegation.web.DelegationTokenAuthenticatedURL;
|
||||||
import org.apache.sqoop.client.SqoopClient;
|
import org.apache.sqoop.client.SqoopClient;
|
||||||
import org.apache.sqoop.model.MConnector;
|
import org.apache.sqoop.model.MConnector;
|
||||||
import org.apache.sqoop.test.utils.HdfsUtils;
|
import org.apache.sqoop.test.utils.HdfsUtils;
|
||||||
|
import org.apache.sqoop.test.utils.SecurityUtils;
|
||||||
import org.apache.sqoop.test.utils.SqoopUtils;
|
import org.apache.sqoop.test.utils.SqoopUtils;
|
||||||
import org.bouncycastle.x509.X509V1CertificateGenerator;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a Minikdc setup. Minikdc should be only used together with
|
* Represents a Minikdc setup. Minikdc should be only used together with
|
||||||
@ -107,17 +85,17 @@ public Configuration prepareHadoopConfiguration(Configuration config) throws Exc
|
|||||||
config.set("dfs.datanode.kerberos.principal", hadoopPrincipal);
|
config.set("dfs.datanode.kerberos.principal", hadoopPrincipal);
|
||||||
config.set("dfs.datanode.keytab.file", hadoopKeytabFile);
|
config.set("dfs.datanode.keytab.file", hadoopKeytabFile);
|
||||||
String sslKeystoresDir = getTemporaryPath() + "/ssl-keystore";
|
String sslKeystoresDir = getTemporaryPath() + "/ssl-keystore";
|
||||||
String sslConfDir = getClasspathDir(MiniKdcRunner.class);
|
String sslConfDir = SqoopUtils.getClasspathDir(MiniKdcRunner.class);
|
||||||
FileUtils.deleteDirectory(new File(sslKeystoresDir));
|
FileUtils.deleteDirectory(new File(sslKeystoresDir));
|
||||||
FileUtils.forceMkdir(new File(sslKeystoresDir));
|
FileUtils.forceMkdir(new File(sslKeystoresDir));
|
||||||
setupSSLConfig(sslKeystoresDir, sslConfDir, config, false, true);
|
SecurityUtils.setupSSLConfig(sslKeystoresDir, sslConfDir, config, false, true);
|
||||||
config.set("dfs.https.server.keystore.resource", getSSLConfigFileName("ssl-server"));
|
config.set("dfs.https.server.keystore.resource", SecurityUtils.getSSLConfigFileName("ssl-server"));
|
||||||
// Configurations used by both NameNode and DataNode
|
// Configurations used by both NameNode and DataNode
|
||||||
config.set("dfs.block.access.token.enable", "true");
|
config.set("dfs.block.access.token.enable", "true");
|
||||||
config.set("dfs.http.policy", "HTTPS_ONLY");
|
config.set("dfs.http.policy", "HTTPS_ONLY");
|
||||||
// Configurations used by DFSClient
|
// Configurations used by DFSClient
|
||||||
config.set("dfs.data.transfer.protection", "privacy");
|
config.set("dfs.data.transfer.protection", "privacy");
|
||||||
config.set("dfs.client.https.keystore.resource", getSSLConfigFileName("ssl-client"));
|
config.set("dfs.client.https.keystore.resource", SecurityUtils.getSSLConfigFileName("ssl-client"));
|
||||||
|
|
||||||
// YARN related configurations
|
// YARN related configurations
|
||||||
config.set("yarn.resourcemanager.principal", hadoopPrincipal);
|
config.set("yarn.resourcemanager.principal", hadoopPrincipal);
|
||||||
@ -331,219 +309,4 @@ public T run() throws Exception {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
private static String getClasspathDir(Class klass) throws Exception {
|
|
||||||
String file = klass.getName();
|
|
||||||
file = file.replace('.', '/') + ".class";
|
|
||||||
URL url = Thread.currentThread().getContextClassLoader().getResource(file);
|
|
||||||
String baseDir = url.toURI().getPath();
|
|
||||||
baseDir = baseDir.substring(0, baseDir.length() - file.length() - 1);
|
|
||||||
return baseDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs complete setup of SSL configuration. This includes keys, certs,
|
|
||||||
* keystores, truststores, the server SSL configuration file,
|
|
||||||
* the client SSL configuration file.
|
|
||||||
*
|
|
||||||
* @param keystoresDir String directory to save keystores
|
|
||||||
* @param sslConfDir String directory to save SSL configuration files
|
|
||||||
* @param conf Configuration
|
|
||||||
* @param useClientCert boolean true to make the client present a cert in the
|
|
||||||
* SSL handshake
|
|
||||||
* @param trustStore boolean true to create truststore, false not to create it
|
|
||||||
*/
|
|
||||||
private void setupSSLConfig(String keystoresDir, String sslConfDir,
|
|
||||||
Configuration conf, boolean useClientCert, boolean trustStore)
|
|
||||||
throws Exception {
|
|
||||||
String clientKS = keystoresDir + "/clientKS.jks";
|
|
||||||
String clientPassword = "clientP";
|
|
||||||
String serverKS = keystoresDir + "/serverKS.jks";
|
|
||||||
String serverPassword = "serverP";
|
|
||||||
String trustKS = null;
|
|
||||||
String trustPassword = "trustP";
|
|
||||||
|
|
||||||
File sslClientConfFile = new File(sslConfDir, getSSLConfigFileName("ssl-client"));
|
|
||||||
File sslServerConfFile = new File(sslConfDir, getSSLConfigFileName("ssl-server"));
|
|
||||||
|
|
||||||
Map<String, X509Certificate> certs = new HashMap<String, X509Certificate>();
|
|
||||||
|
|
||||||
if (useClientCert) {
|
|
||||||
KeyPair cKP = generateKeyPair("RSA");
|
|
||||||
X509Certificate cCert = generateCertificate("CN=localhost, O=client", cKP, 30, "SHA1withRSA");
|
|
||||||
createKeyStore(clientKS, clientPassword, "client", cKP.getPrivate(), cCert);
|
|
||||||
certs.put("client", cCert);
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyPair sKP = generateKeyPair("RSA");
|
|
||||||
X509Certificate sCert = generateCertificate("CN=localhost, O=server", sKP, 30, "SHA1withRSA");
|
|
||||||
createKeyStore(serverKS, serverPassword, "server", sKP.getPrivate(), sCert);
|
|
||||||
certs.put("server", sCert);
|
|
||||||
|
|
||||||
if (trustStore) {
|
|
||||||
trustKS = keystoresDir + "/trustKS.jks";
|
|
||||||
createTrustStore(trustKS, trustPassword, certs);
|
|
||||||
}
|
|
||||||
|
|
||||||
Configuration clientSSLConf = createSSLConfig(
|
|
||||||
SSLFactory.Mode.CLIENT, clientKS, clientPassword, clientPassword, trustKS);
|
|
||||||
Configuration serverSSLConf = createSSLConfig(
|
|
||||||
SSLFactory.Mode.SERVER, serverKS, serverPassword, serverPassword, trustKS);
|
|
||||||
|
|
||||||
saveConfig(sslClientConfFile, clientSSLConf);
|
|
||||||
saveConfig(sslServerConfFile, serverSSLConf);
|
|
||||||
|
|
||||||
conf.set(SSLFactory.SSL_HOSTNAME_VERIFIER_KEY, "ALLOW_ALL");
|
|
||||||
conf.set(SSLFactory.SSL_CLIENT_CONF_KEY, sslClientConfFile.getName());
|
|
||||||
conf.set(SSLFactory.SSL_SERVER_CONF_KEY, sslServerConfFile.getName());
|
|
||||||
conf.setBoolean(SSLFactory.SSL_REQUIRE_CLIENT_CERT_KEY, useClientCert);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an SSL configuration file name. Under parallel test
|
|
||||||
* execution, this file name is parameterized by a unique ID to ensure that
|
|
||||||
* concurrent tests don't collide on an SSL configuration file.
|
|
||||||
*
|
|
||||||
* @param base the base of the file name
|
|
||||||
* @return SSL configuration file name for base
|
|
||||||
*/
|
|
||||||
private static String getSSLConfigFileName(String base) {
|
|
||||||
String testUniqueForkId = System.getProperty("test.unique.fork.id");
|
|
||||||
String fileSuffix = testUniqueForkId != null ? "-" + testUniqueForkId : "";
|
|
||||||
return base + fileSuffix + ".xml";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates SSL configuration.
|
|
||||||
*
|
|
||||||
* @param mode SSLFactory.Mode mode to configure
|
|
||||||
* @param keystore String keystore file
|
|
||||||
* @param password String store password, or null to avoid setting store
|
|
||||||
* password
|
|
||||||
* @param keyPassword String key password, or null to avoid setting key
|
|
||||||
* password
|
|
||||||
* @param trustKS String truststore file
|
|
||||||
* @return Configuration for SSL
|
|
||||||
*/
|
|
||||||
private static Configuration createSSLConfig(SSLFactory.Mode mode,
|
|
||||||
String keystore, String password, String keyPassword, String trustKS) {
|
|
||||||
String trustPassword = "trustP";
|
|
||||||
|
|
||||||
Configuration sslConf = new Configuration(false);
|
|
||||||
if (keystore != null) {
|
|
||||||
sslConf.set(FileBasedKeyStoresFactory.resolvePropertyName(mode,
|
|
||||||
FileBasedKeyStoresFactory.SSL_KEYSTORE_LOCATION_TPL_KEY), keystore);
|
|
||||||
}
|
|
||||||
if (password != null) {
|
|
||||||
sslConf.set(FileBasedKeyStoresFactory.resolvePropertyName(mode,
|
|
||||||
FileBasedKeyStoresFactory.SSL_KEYSTORE_PASSWORD_TPL_KEY), password);
|
|
||||||
}
|
|
||||||
if (keyPassword != null) {
|
|
||||||
sslConf.set(FileBasedKeyStoresFactory.resolvePropertyName(mode,
|
|
||||||
FileBasedKeyStoresFactory.SSL_KEYSTORE_KEYPASSWORD_TPL_KEY),
|
|
||||||
keyPassword);
|
|
||||||
}
|
|
||||||
if (trustKS != null) {
|
|
||||||
sslConf.set(FileBasedKeyStoresFactory.resolvePropertyName(mode,
|
|
||||||
FileBasedKeyStoresFactory.SSL_TRUSTSTORE_LOCATION_TPL_KEY), trustKS);
|
|
||||||
}
|
|
||||||
sslConf.set(FileBasedKeyStoresFactory.resolvePropertyName(mode,
|
|
||||||
FileBasedKeyStoresFactory.SSL_TRUSTSTORE_PASSWORD_TPL_KEY),
|
|
||||||
trustPassword);
|
|
||||||
sslConf.set(FileBasedKeyStoresFactory.resolvePropertyName(mode,
|
|
||||||
FileBasedKeyStoresFactory.SSL_TRUSTSTORE_RELOAD_INTERVAL_TPL_KEY), "1000");
|
|
||||||
|
|
||||||
return sslConf;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static KeyPair generateKeyPair(String algorithm)
|
|
||||||
throws NoSuchAlgorithmException {
|
|
||||||
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm);
|
|
||||||
keyGen.initialize(1024);
|
|
||||||
return keyGen.genKeyPair();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a self-signed X.509 Certificate.
|
|
||||||
*
|
|
||||||
* @param dn the X.509 Distinguished Name, eg "CN=Test, L=London, C=GB"
|
|
||||||
* @param pair the KeyPair
|
|
||||||
* @param days how many days from now the Certificate is valid for
|
|
||||||
* @param algorithm the signing algorithm, eg "SHA1withRSA"
|
|
||||||
* @return the self-signed certificate
|
|
||||||
*/
|
|
||||||
private static X509Certificate generateCertificate(String dn, KeyPair pair, int days, String algorithm)
|
|
||||||
throws CertificateEncodingException,
|
|
||||||
InvalidKeyException,
|
|
||||||
IllegalStateException,
|
|
||||||
NoSuchProviderException, NoSuchAlgorithmException, SignatureException{
|
|
||||||
Date from = new Date();
|
|
||||||
Date to = new Date(from.getTime() + days * 86400000l);
|
|
||||||
BigInteger sn = new BigInteger(64, new SecureRandom());
|
|
||||||
KeyPair keyPair = pair;
|
|
||||||
X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
|
|
||||||
X500Principal dnName = new X500Principal(dn);
|
|
||||||
|
|
||||||
certGen.setSerialNumber(sn);
|
|
||||||
certGen.setIssuerDN(dnName);
|
|
||||||
certGen.setNotBefore(from);
|
|
||||||
certGen.setNotAfter(to);
|
|
||||||
certGen.setSubjectDN(dnName);
|
|
||||||
certGen.setPublicKey(keyPair.getPublic());
|
|
||||||
certGen.setSignatureAlgorithm(algorithm);
|
|
||||||
|
|
||||||
X509Certificate cert = certGen.generate(pair.getPrivate());
|
|
||||||
return cert;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void createKeyStore(String filename,
|
|
||||||
String password, String alias,
|
|
||||||
Key privateKey, Certificate cert)
|
|
||||||
throws GeneralSecurityException, IOException {
|
|
||||||
KeyStore ks = KeyStore.getInstance("JKS");
|
|
||||||
ks.load(null, null); // initialize
|
|
||||||
ks.setKeyEntry(alias, privateKey, password.toCharArray(),
|
|
||||||
new Certificate[]{cert});
|
|
||||||
saveKeyStore(ks, filename, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static <T extends Certificate> void createTrustStore(
|
|
||||||
String filename, String password, Map<String, T> certs)
|
|
||||||
throws GeneralSecurityException, IOException {
|
|
||||||
KeyStore ks = KeyStore.getInstance("JKS");
|
|
||||||
ks.load(null, null); // initialize
|
|
||||||
for (Map.Entry<String, T> cert : certs.entrySet()) {
|
|
||||||
ks.setCertificateEntry(cert.getKey(), cert.getValue());
|
|
||||||
}
|
|
||||||
saveKeyStore(ks, filename, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void saveKeyStore(KeyStore ks, String filename,
|
|
||||||
String password)
|
|
||||||
throws GeneralSecurityException, IOException {
|
|
||||||
FileOutputStream out = new FileOutputStream(filename);
|
|
||||||
try {
|
|
||||||
ks.store(out, password.toCharArray());
|
|
||||||
} finally {
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves configuration to a file.
|
|
||||||
*
|
|
||||||
* @param file File to save
|
|
||||||
* @param conf Configuration contents to write to file
|
|
||||||
* @throws IOException if there is an I/O error saving the file
|
|
||||||
*/
|
|
||||||
private static void saveConfig(File file, Configuration conf)
|
|
||||||
throws IOException {
|
|
||||||
Writer writer = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
|
|
||||||
try {
|
|
||||||
conf.writeXml(writer);
|
|
||||||
} finally {
|
|
||||||
writer.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,269 @@
|
|||||||
|
/**
|
||||||
|
* 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.sqoop.test.utils;
|
||||||
|
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.security.ssl.FileBasedKeyStoresFactory;
|
||||||
|
import org.apache.hadoop.security.ssl.SSLFactory;
|
||||||
|
import org.bouncycastle.x509.X509V1CertificateGenerator;
|
||||||
|
|
||||||
|
import javax.security.auth.x500.X500Principal;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.Key;
|
||||||
|
import java.security.KeyPair;
|
||||||
|
import java.security.KeyPairGenerator;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.NoSuchProviderException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.SignatureException;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
|
import java.security.cert.CertificateEncodingException;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class SecurityUtils {
|
||||||
|
|
||||||
|
public static final String CLIENT_KEYSTORE = "clientKS.jks";
|
||||||
|
public static final String SERVER_KEYSTORE = "serverKS.jks";
|
||||||
|
public static final String TRUSTSTORE = "trustKS.jks";
|
||||||
|
|
||||||
|
public static final String CLIENT_KEY_PASSWORD = "client_key";
|
||||||
|
public static final String CLIENT_KEY_STORE_PASSWORD = "client_keystore";
|
||||||
|
public static final String SERVER_KEY_PASSWORD = "server_key";
|
||||||
|
public static final String SERVER_KEY_STORE_PASSWORD = "server_keystore";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs complete setup of SSL configuration. This includes keys, certs,
|
||||||
|
* keystores, truststores, the server SSL configuration file,
|
||||||
|
* the client SSL configuration file.
|
||||||
|
*
|
||||||
|
* @param keystoresDir String directory to save keystores
|
||||||
|
* @param sslConfDir String directory to save SSL configuration files
|
||||||
|
* @param conf Configuration
|
||||||
|
* @param useClientCert boolean true to make the client present a cert in the
|
||||||
|
* SSL handshake
|
||||||
|
* @param trustStore boolean true to create truststore, false not to create it
|
||||||
|
*/
|
||||||
|
public static X509Certificate setupSSLConfig(String keystoresDir, String sslConfDir,
|
||||||
|
Configuration conf, boolean useClientCert, boolean trustStore)
|
||||||
|
throws Exception {
|
||||||
|
String clientKeyStorePath = keystoresDir + "/" + CLIENT_KEYSTORE;
|
||||||
|
String serverKeyStorePath = keystoresDir + "/" + SERVER_KEYSTORE;
|
||||||
|
String serverPassword = "serverP";
|
||||||
|
String trustKS = null;
|
||||||
|
String trustPassword = "trustP";
|
||||||
|
|
||||||
|
File sslClientConfFile = new File(sslConfDir, getSSLConfigFileName("ssl-client"));
|
||||||
|
File sslServerConfFile = new File(sslConfDir, getSSLConfigFileName("ssl-server"));
|
||||||
|
|
||||||
|
Map<String, X509Certificate> certs = new HashMap<String, X509Certificate>();
|
||||||
|
|
||||||
|
String hostname = SqoopUtils.getLocalHostName();
|
||||||
|
|
||||||
|
if (useClientCert) {
|
||||||
|
KeyPair cKP = generateKeyPair("RSA");
|
||||||
|
X509Certificate cCert = generateCertificate("CN=" + hostname + ", O=client", cKP, 30, "SHA1withRSA");
|
||||||
|
createKeyStore(clientKeyStorePath, CLIENT_KEY_PASSWORD, CLIENT_KEY_STORE_PASSWORD, "client", cKP.getPrivate(), cCert);
|
||||||
|
certs.put("client", cCert);
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyPair sKP = generateKeyPair("RSA");
|
||||||
|
X509Certificate sCert = generateCertificate("CN=" + hostname + ", O=server", sKP, 30, "SHA1withRSA");
|
||||||
|
createKeyStore(serverKeyStorePath, SERVER_KEY_PASSWORD, SERVER_KEY_STORE_PASSWORD, "server", sKP.getPrivate(), sCert);
|
||||||
|
certs.put("server", sCert);
|
||||||
|
|
||||||
|
if (trustStore) {
|
||||||
|
trustKS = keystoresDir + TRUSTSTORE;
|
||||||
|
createTrustStore(trustKS, trustPassword, certs);
|
||||||
|
}
|
||||||
|
|
||||||
|
Configuration clientSSLConf = createSSLConfig(
|
||||||
|
SSLFactory.Mode.CLIENT, clientKeyStorePath, CLIENT_KEY_STORE_PASSWORD, CLIENT_KEY_PASSWORD, trustKS);
|
||||||
|
Configuration serverSSLConf = createSSLConfig(
|
||||||
|
SSLFactory.Mode.SERVER, serverKeyStorePath, SERVER_KEY_STORE_PASSWORD, SERVER_KEY_PASSWORD, trustKS);
|
||||||
|
|
||||||
|
saveConfig(sslClientConfFile, clientSSLConf);
|
||||||
|
saveConfig(sslServerConfFile, serverSSLConf);
|
||||||
|
|
||||||
|
conf.set(SSLFactory.SSL_HOSTNAME_VERIFIER_KEY, "ALLOW_ALL");
|
||||||
|
conf.set(SSLFactory.SSL_CLIENT_CONF_KEY, sslClientConfFile.getName());
|
||||||
|
conf.set(SSLFactory.SSL_SERVER_CONF_KEY, sslServerConfFile.getName());
|
||||||
|
conf.setBoolean(SSLFactory.SSL_REQUIRE_CLIENT_CERT_KEY, useClientCert);
|
||||||
|
|
||||||
|
return sCert;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an SSL configuration file name. Under parallel test
|
||||||
|
* execution, this file name is parameterized by a unique ID to ensure that
|
||||||
|
* concurrent tests don't collide on an SSL configuration file.
|
||||||
|
*
|
||||||
|
* @param base the base of the file name
|
||||||
|
* @return SSL configuration file name for base
|
||||||
|
*/
|
||||||
|
public static String getSSLConfigFileName(String base) {
|
||||||
|
String testUniqueForkId = System.getProperty("test.unique.fork.id");
|
||||||
|
String fileSuffix = testUniqueForkId != null ? "-" + testUniqueForkId : "";
|
||||||
|
return base + fileSuffix + ".xml";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates SSL configuration.
|
||||||
|
*
|
||||||
|
* @param mode SSLFactory.Mode mode to configure
|
||||||
|
* @param keystore String keystore file
|
||||||
|
* @param keyStorePassword String store password, or null to avoid setting store
|
||||||
|
* password
|
||||||
|
* @param keyPassword String key password, or null to avoid setting key
|
||||||
|
* password
|
||||||
|
* @param trustKS String truststore file
|
||||||
|
* @return Configuration for SSL
|
||||||
|
*/
|
||||||
|
public static Configuration createSSLConfig(SSLFactory.Mode mode,
|
||||||
|
String keystore, String keyStorePassword,
|
||||||
|
String keyPassword, String trustKS) {
|
||||||
|
String trustPassword = "trustP";
|
||||||
|
|
||||||
|
Configuration sslConf = new Configuration(false);
|
||||||
|
if (keystore != null) {
|
||||||
|
sslConf.set(FileBasedKeyStoresFactory.resolvePropertyName(mode,
|
||||||
|
FileBasedKeyStoresFactory.SSL_KEYSTORE_LOCATION_TPL_KEY), keystore);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyStorePassword != null) {
|
||||||
|
sslConf.set(FileBasedKeyStoresFactory.resolvePropertyName(mode,
|
||||||
|
FileBasedKeyStoresFactory.SSL_KEYSTORE_PASSWORD_TPL_KEY), keyStorePassword);
|
||||||
|
}
|
||||||
|
if (keyPassword != null) {
|
||||||
|
sslConf.set(FileBasedKeyStoresFactory.resolvePropertyName(mode,
|
||||||
|
FileBasedKeyStoresFactory.SSL_KEYSTORE_KEYPASSWORD_TPL_KEY),
|
||||||
|
keyPassword);
|
||||||
|
}
|
||||||
|
if (trustKS != null) {
|
||||||
|
sslConf.set(FileBasedKeyStoresFactory.resolvePropertyName(mode,
|
||||||
|
FileBasedKeyStoresFactory.SSL_TRUSTSTORE_LOCATION_TPL_KEY), trustKS);
|
||||||
|
}
|
||||||
|
sslConf.set(FileBasedKeyStoresFactory.resolvePropertyName(mode,
|
||||||
|
FileBasedKeyStoresFactory.SSL_TRUSTSTORE_PASSWORD_TPL_KEY),
|
||||||
|
trustPassword);
|
||||||
|
sslConf.set(FileBasedKeyStoresFactory.resolvePropertyName(mode,
|
||||||
|
FileBasedKeyStoresFactory.SSL_TRUSTSTORE_RELOAD_INTERVAL_TPL_KEY), "1000");
|
||||||
|
|
||||||
|
return sslConf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyPair generateKeyPair(String algorithm)
|
||||||
|
throws NoSuchAlgorithmException {
|
||||||
|
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm);
|
||||||
|
keyGen.initialize(1024);
|
||||||
|
return keyGen.genKeyPair();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a self-signed X.509 Certificate.
|
||||||
|
*
|
||||||
|
* @param dn the X.509 Distinguished Name, eg "CN=Test, L=London, C=GB"
|
||||||
|
* @param pair the KeyPair
|
||||||
|
* @param days how many days from now the Certificate is valid for
|
||||||
|
* @param algorithm the signing algorithm, eg "SHA1withRSA"
|
||||||
|
* @return the self-signed certificate
|
||||||
|
*/
|
||||||
|
public static X509Certificate generateCertificate(String dn, KeyPair pair, int days, String algorithm)
|
||||||
|
throws CertificateEncodingException,
|
||||||
|
InvalidKeyException,
|
||||||
|
IllegalStateException,
|
||||||
|
NoSuchProviderException, NoSuchAlgorithmException, SignatureException {
|
||||||
|
Date from = new Date();
|
||||||
|
Date to = new Date(from.getTime() + days * 86400000l);
|
||||||
|
BigInteger sn = new BigInteger(64, new SecureRandom());
|
||||||
|
KeyPair keyPair = pair;
|
||||||
|
X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
|
||||||
|
X500Principal dnName = new X500Principal(dn);
|
||||||
|
|
||||||
|
certGen.setSerialNumber(sn);
|
||||||
|
certGen.setIssuerDN(dnName);
|
||||||
|
certGen.setNotBefore(from);
|
||||||
|
certGen.setNotAfter(to);
|
||||||
|
certGen.setSubjectDN(dnName);
|
||||||
|
certGen.setPublicKey(keyPair.getPublic());
|
||||||
|
certGen.setSignatureAlgorithm(algorithm);
|
||||||
|
|
||||||
|
X509Certificate cert = certGen.generate(pair.getPrivate());
|
||||||
|
return cert;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void createKeyStore(String filename,
|
||||||
|
String keyPassword, String keyStorePassword,
|
||||||
|
String alias, Key privateKey, Certificate cert)
|
||||||
|
throws GeneralSecurityException, IOException {
|
||||||
|
KeyStore ks = KeyStore.getInstance("JKS");
|
||||||
|
ks.load(null, null); // initialize
|
||||||
|
ks.setKeyEntry(alias, privateKey, keyPassword.toCharArray(),
|
||||||
|
new Certificate[]{cert});
|
||||||
|
saveKeyStore(ks, filename, keyStorePassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends Certificate> void createTrustStore(
|
||||||
|
String filename, String password, Map<String, T> certs)
|
||||||
|
throws GeneralSecurityException, IOException {
|
||||||
|
KeyStore ks = KeyStore.getInstance("JKS");
|
||||||
|
ks.load(null, null); // initialize
|
||||||
|
for (Map.Entry<String, T> cert : certs.entrySet()) {
|
||||||
|
ks.setCertificateEntry(cert.getKey(), cert.getValue());
|
||||||
|
}
|
||||||
|
saveKeyStore(ks, filename, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void saveKeyStore(KeyStore ks, String filename,
|
||||||
|
String password)
|
||||||
|
throws GeneralSecurityException, IOException {
|
||||||
|
FileOutputStream out = new FileOutputStream(filename);
|
||||||
|
try {
|
||||||
|
ks.store(out, password.toCharArray());
|
||||||
|
} finally {
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves configuration to a file.
|
||||||
|
*
|
||||||
|
* @param file File to save
|
||||||
|
* @param conf Configuration contents to write to file
|
||||||
|
* @throws IOException if there is an I/O error saving the file
|
||||||
|
*/
|
||||||
|
public static void saveConfig(File file, Configuration conf)
|
||||||
|
throws IOException {
|
||||||
|
Writer writer = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
|
||||||
|
try {
|
||||||
|
conf.writeXml(writer);
|
||||||
|
} finally {
|
||||||
|
writer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,7 @@
|
|||||||
package org.apache.sqoop.test.utils;
|
package org.apache.sqoop.test.utils;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
import java.net.URL;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
@ -54,4 +55,26 @@ public static String getLocalHostName() {
|
|||||||
}
|
}
|
||||||
return fqdn;
|
return fqdn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Retrieve the IP address of the current host
|
||||||
|
public static String getLocalIpAddress() {
|
||||||
|
String address;
|
||||||
|
try {
|
||||||
|
address = InetAddress.getLocalHost().getHostAddress();
|
||||||
|
} catch (UnknownHostException e1) {
|
||||||
|
address = "127.0.0.1";
|
||||||
|
}
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public static String getClasspathDir(Class klass) throws Exception {
|
||||||
|
String file = klass.getName();
|
||||||
|
file = file.replace('.', '/') + ".class";
|
||||||
|
URL url = Thread.currentThread().getContextClassLoader().getResource(file);
|
||||||
|
String baseDir = url.toURI().getPath();
|
||||||
|
baseDir = baseDir.substring(0, baseDir.length() - file.length() - 1);
|
||||||
|
return baseDir;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.apache.sqoop.integration.connectorloading;
|
package org.apache.sqoop.integration.serverproperties;
|
||||||
|
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.sqoop.common.SqoopException;
|
import org.apache.sqoop.common.SqoopException;
|
@ -16,7 +16,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.sqoop.integration.connectorloading;
|
package org.apache.sqoop.integration.serverproperties;
|
||||||
|
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.sqoop.core.ConfigurationConstants;
|
import org.apache.sqoop.core.ConfigurationConstants;
|
@ -16,7 +16,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.sqoop.integration.connectorloading;
|
package org.apache.sqoop.integration.serverproperties;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
@ -0,0 +1,164 @@
|
|||||||
|
/**
|
||||||
|
* 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.sqoop.integration.serverproperties;
|
||||||
|
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.security.authentication.client.PseudoAuthenticator;
|
||||||
|
import org.apache.hadoop.security.token.delegation.web.DelegationTokenAuthenticatedURL;
|
||||||
|
import org.apache.sqoop.security.SecurityConstants;
|
||||||
|
import org.apache.sqoop.test.infrastructure.Infrastructure;
|
||||||
|
import org.apache.sqoop.test.infrastructure.SqoopTestCase;
|
||||||
|
import org.apache.sqoop.test.infrastructure.providers.DatabaseInfrastructureProvider;
|
||||||
|
import org.apache.sqoop.test.infrastructure.providers.HadoopInfrastructureProvider;
|
||||||
|
import org.apache.sqoop.test.infrastructure.providers.KdcInfrastructureProvider;
|
||||||
|
import org.apache.sqoop.test.minicluster.JettySqoopMiniCluster;
|
||||||
|
import org.apache.sqoop.test.minicluster.SqoopMiniCluster;
|
||||||
|
import org.apache.sqoop.test.utils.HdfsUtils;
|
||||||
|
import org.apache.sqoop.test.utils.SecurityUtils;
|
||||||
|
import org.apache.sqoop.test.utils.SqoopUtils;
|
||||||
|
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||||
|
import org.testng.annotations.AfterMethod;
|
||||||
|
import org.testng.annotations.BeforeMethod;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import javax.net.ssl.HostnameVerifier;
|
||||||
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLSession;
|
||||||
|
import javax.ws.rs.HttpMethod;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
@Infrastructure(dependencies = {KdcInfrastructureProvider.class, HadoopInfrastructureProvider.class, DatabaseInfrastructureProvider.class})
|
||||||
|
@Test(groups = {"no-real-cluster"})
|
||||||
|
public class SslTest extends SqoopTestCase {
|
||||||
|
|
||||||
|
private SqoopMiniCluster sqoopMiniCluster;
|
||||||
|
private SSLContext defaultSslContext;
|
||||||
|
private HostnameVerifier defaultHostNameVerifier;
|
||||||
|
|
||||||
|
public static class SslSqoopMiniCluster extends JettySqoopMiniCluster {
|
||||||
|
|
||||||
|
private String keyStoreFilePath;
|
||||||
|
private String keyStorePassword;
|
||||||
|
private String keyManagerPassword;
|
||||||
|
|
||||||
|
public SslSqoopMiniCluster(String temporaryPath, Configuration configuration, String keyStoreFilePath, String keyStorePassword, String keyManagerPassword) throws Exception {
|
||||||
|
super(temporaryPath, configuration);
|
||||||
|
this.keyStoreFilePath = keyStoreFilePath;
|
||||||
|
this.keyStorePassword = keyStorePassword;
|
||||||
|
this.keyManagerPassword = keyManagerPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Map<String, String> getSecurityConfiguration() {
|
||||||
|
Map<String, String> properties = super.getSecurityConfiguration();
|
||||||
|
|
||||||
|
properties.put(SecurityConstants.TLS_ENABLED, String.valueOf(true));
|
||||||
|
properties.put(SecurityConstants.TLS_PROTOCOL, "TLSv1.2");
|
||||||
|
properties.put(SecurityConstants.KEYSTORE_LOCATION, keyStoreFilePath);
|
||||||
|
properties.put(SecurityConstants.KEYSTORE_PASSWORD, keyStorePassword);
|
||||||
|
properties.put(SecurityConstants.KEYMANAGER_PASSWORD, keyManagerPassword);
|
||||||
|
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeMethod
|
||||||
|
public void backupSslContext() throws Exception {
|
||||||
|
defaultSslContext = SSLContext.getDefault();
|
||||||
|
defaultHostNameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterMethod
|
||||||
|
public void restoreSslContext() {
|
||||||
|
SSLContext.setDefault(defaultSslContext);
|
||||||
|
HttpsURLConnection.setDefaultHostnameVerifier(defaultHostNameVerifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterMethod
|
||||||
|
public void stopCluster() throws Exception {
|
||||||
|
sqoopMiniCluster.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSslInUse() throws Exception {
|
||||||
|
String sslKeystoresDir = getTemporaryPath() + "ssl-keystore/";
|
||||||
|
String sslConfDir = SqoopUtils.getClasspathDir(SslTest.class);
|
||||||
|
FileUtils.deleteDirectory(new File(sslKeystoresDir));
|
||||||
|
FileUtils.forceMkdir(new File(sslKeystoresDir));
|
||||||
|
X509Certificate serverCertificate = SecurityUtils.setupSSLConfig(
|
||||||
|
sslKeystoresDir, sslConfDir, new Configuration(), false, true);
|
||||||
|
|
||||||
|
sqoopMiniCluster =
|
||||||
|
new SslSqoopMiniCluster(HdfsUtils.joinPathFragments(getTemporaryPath(), getTestName()), getHadoopConf(), sslKeystoresDir + SecurityUtils.SERVER_KEYSTORE, SecurityUtils.SERVER_KEY_STORE_PASSWORD, SecurityUtils.SERVER_KEY_PASSWORD);
|
||||||
|
|
||||||
|
KdcInfrastructureProvider kdcProvider = getInfrastructureProvider(KdcInfrastructureProvider.class);
|
||||||
|
if (kdcProvider != null) {
|
||||||
|
sqoopMiniCluster.setKdc(kdcProvider.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
sqoopMiniCluster.start();
|
||||||
|
|
||||||
|
// Bypass hostname verification
|
||||||
|
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
|
||||||
|
public boolean verify(String hostname, SSLSession session) {
|
||||||
|
try {
|
||||||
|
if (hostname.equals((new URL(sqoopMiniCluster.getServerUrl())).getHost())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
SslContextFactory sslContextFactory = new SslContextFactory();
|
||||||
|
sslContextFactory.setKeyStorePath(sslKeystoresDir + SecurityUtils.TRUSTSTORE);
|
||||||
|
|
||||||
|
sslContextFactory.start();
|
||||||
|
|
||||||
|
SSLContext.setDefault(sslContextFactory.getSslContext());
|
||||||
|
|
||||||
|
initSqoopClient(sqoopMiniCluster.getServerUrl());
|
||||||
|
|
||||||
|
// Make a request and check the cert
|
||||||
|
URL url = new URL(sqoopMiniCluster.getServerUrl() + "version?" +
|
||||||
|
PseudoAuthenticator.USER_NAME + "=" + System.getProperty("user.name"));
|
||||||
|
HttpURLConnection conn = new DelegationTokenAuthenticatedURL().openConnection(url, getAuthToken());
|
||||||
|
conn.setRequestMethod(HttpMethod.GET);
|
||||||
|
conn.setRequestProperty("Accept", MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
|
assertEquals(conn.getResponseCode(), 200);
|
||||||
|
|
||||||
|
HttpsURLConnection secured = (HttpsURLConnection) conn;
|
||||||
|
Certificate actualCertificate = secured.getServerCertificates()[0];
|
||||||
|
assertEquals(actualCertificate, serverCertificate);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -18,16 +18,16 @@ limitations under the License.
|
|||||||
|
|
||||||
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
|
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
|
||||||
|
|
||||||
<suite name="ConnectorLoadingTests" verbose="2" parallel="false">
|
<suite name="ServerPropertiesTests" verbose="2" parallel="false">
|
||||||
|
|
||||||
<listeners>
|
<listeners>
|
||||||
<listener class-name="org.apache.sqoop.test.testng.SqoopTestListener" />
|
<listener class-name="org.apache.sqoop.test.testng.SqoopTestListener" />
|
||||||
<listener class-name="org.apache.sqoop.test.testng.ReconfigureLogListener" />
|
<listener class-name="org.apache.sqoop.test.testng.ReconfigureLogListener" />
|
||||||
</listeners>
|
</listeners>
|
||||||
|
|
||||||
<test name="ConnectorLoadingTests">
|
<test name="ServerPropertiesTests">
|
||||||
<packages>
|
<packages>
|
||||||
<package name="org.apache.sqoop.integration.connectorloading"/>
|
<package name="org.apache.sqoop.integration.serverproperties"/>
|
||||||
</packages>
|
</packages>
|
||||||
</test>
|
</test>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user