diff --git a/itests/hive-unit/src/main/java/org/apache/hive/jdbc/miniHS2/AbstractHiveService.java b/itests/hive-unit/src/main/java/org/apache/hive/jdbc/miniHS2/AbstractHiveService.java index 095b989..2c1cd07 100644 --- a/itests/hive-unit/src/main/java/org/apache/hive/jdbc/miniHS2/AbstractHiveService.java +++ b/itests/hive-unit/src/main/java/org/apache/hive/jdbc/miniHS2/AbstractHiveService.java @@ -106,7 +106,7 @@ public void setHost(String hostName) { } // get service host - protected String getHost() { + public String getHost() { return hostname; } @@ -127,12 +127,12 @@ public void setHttpPort(int portNum) { } // Get binary service port # - protected int getBinaryPort() { + public int getBinaryPort() { return binaryPort; } // Get http service port # - protected int getHttpPort() { + public int getHttpPort() { return httpPort; } diff --git a/itests/hive-unit/src/test/java/org/apache/hive/jdbc/TestSSL.java b/itests/hive-unit/src/test/java/org/apache/hive/jdbc/TestSSL.java index 0058cd3..357ad9e 100644 --- a/itests/hive-unit/src/test/java/org/apache/hive/jdbc/TestSSL.java +++ b/itests/hive-unit/src/test/java/org/apache/hive/jdbc/TestSSL.java @@ -30,15 +30,21 @@ import java.util.Map; import org.apache.hadoop.fs.Path; +import org.apache.hadoop.util.Shell; import org.apache.hadoop.hive.conf.HiveConf; import org.apache.hadoop.hive.conf.HiveConf.ConfVars; import org.apache.hive.jdbc.miniHS2.MiniHS2; import org.junit.After; +import org.junit.Assert; +import org.junit.Assume; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class TestSSL { + private static final Logger LOG = LoggerFactory.getLogger(TestSSL.class); private static final String KEY_STORE_NAME = "keystore.jks"; private static final String TRUST_STORE_NAME = "truststore.jks"; private static final String KEY_STORE_PASSWORD = "HiveJdbc"; @@ -86,6 +92,66 @@ public void tearDown() throws Exception { System.clearProperty(JAVA_TRUST_STORE_PASS_PROP); } + private int execCommand(String cmd) throws Exception { + int exitCode; + try { + String output = Shell.execCommand("bash", "-c", cmd); + LOG.info("Output from '" + cmd + "': " + output) ; + exitCode = 0; + } catch (Shell.ExitCodeException e) { + exitCode = e.getExitCode(); + LOG.info("Error executing '" + cmd + "', exitCode = " + exitCode, e); + } + return exitCode; + } + + /*** + * Tests to ensure SSLv2 and SSLv3 are disabled + */ + @Test + public void testSSLVersion() throws Exception { + Assume.assumeTrue(execCommand("which openssl") == 0); // we need openssl + Assume.assumeTrue(System.getProperty("os.name").toLowerCase() + .contains("linux")); // we depend on linux openssl exit codes + + setSslConfOverlay(confOverlay); + // Test in binary mode + setBinaryConfOverlay(confOverlay); + // Start HS2 with SSL + miniHS2.start(confOverlay); + + // make SSL connection + hs2Conn = DriverManager.getConnection(miniHS2.getJdbcURL() + ";ssl=true;sslTrustStore=" + + dataFileDir + File.separator + TRUST_STORE_NAME + ";trustStorePassword=" + + KEY_STORE_PASSWORD, System.getProperty("user.name"), "bar"); + hs2Conn.close(); + Assert.assertEquals("Expected exit code of 1", 1, + execCommand("openssl s_client -connect " + miniHS2.getHost() + ":" + miniHS2.getBinaryPort() + + " -ssl2 < /dev/null")); + Assert.assertEquals("Expected exit code of 1", 1, + execCommand("openssl s_client -connect " + miniHS2.getHost() + ":" + miniHS2.getBinaryPort() + + " -ssl3 < /dev/null")); + miniHS2.stop(); + + // Test in http mode + setHttpConfOverlay(confOverlay); + miniHS2.start(confOverlay); + // make SSL connection + hs2Conn = DriverManager.getConnection(miniHS2.getJdbcURL() + + ";ssl=true;sslTrustStore=" + dataFileDir + File.separator + + TRUST_STORE_NAME + ";trustStorePassword=" + KEY_STORE_PASSWORD + + "?hive.server2.transport.mode=" + HS2_HTTP_MODE + + ";hive.server2.thrift.http.path=" + HS2_HTTP_ENDPOINT, + System.getProperty("user.name"), "bar"); + hs2Conn.close(); + Assert.assertEquals("Expected exit code of 1", 1, + execCommand("openssl s_client -connect " + miniHS2.getHost() + ":" + miniHS2.getHttpPort() + + " -ssl2 < /dev/null")); + Assert.assertEquals("Expected exit code of 1", 1, + execCommand("openssl s_client -connect " + miniHS2.getHost() + ":" + miniHS2.getHttpPort() + + " -ssl3 < /dev/null")); + } + /*** * Test SSL client with non-SSL server fails * @throws Exception diff --git a/service/src/java/org/apache/hive/service/auth/HiveAuthFactory.java b/service/src/java/org/apache/hive/service/auth/HiveAuthFactory.java index ab34d2d..1458819 100644 --- a/service/src/java/org/apache/hive/service/auth/HiveAuthFactory.java +++ b/service/src/java/org/apache/hive/service/auth/HiveAuthFactory.java @@ -21,9 +21,13 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; +import javax.net.ssl.SSLServerSocket; import javax.security.auth.login.LoginException; import javax.security.sasl.Sasl; @@ -42,12 +46,16 @@ import org.apache.thrift.transport.TTransport; import org.apache.thrift.transport.TTransportException; import org.apache.thrift.transport.TTransportFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * This class helps in some aspects of authentication. It creates the proper Thrift classes for the * given configuration as well as helps with authenticating requests. */ public class HiveAuthFactory { + private static final Logger LOG = LoggerFactory.getLogger(HiveAuthFactory.class); + public enum AuthTypes { NOSASL("NOSASL"), @@ -228,7 +236,21 @@ public static TServerSocket getServerSSLSocket(String hiveHost, int portNum, Str } else { serverAddress = InetAddress.getByName(hiveHost); } - return TSSLTransportFactory.getServerSocket(portNum, 0, serverAddress, params); + TServerSocket thriftServerSocket = TSSLTransportFactory.getServerSocket(portNum, 0, serverAddress, params); + if (thriftServerSocket.getServerSocket() instanceof SSLServerSocket) { + SSLServerSocket sslServerSocket = (SSLServerSocket)thriftServerSocket.getServerSocket(); + List enabledProtocols = new ArrayList(); + for (String protocol : sslServerSocket.getEnabledProtocols()) { + if (protocol.toLowerCase().startsWith("ssl")) { + LOG.debug("Disabling SSL Protocol: " + protocol); + } else { + enabledProtocols.add(protocol); + } + } + sslServerSocket.setEnabledProtocols(enabledProtocols.toArray(new String[0])); + LOG.info("SSL Server Socket Enabled Protocols: " + Arrays.toString(sslServerSocket.getEnabledProtocols())); + } + return thriftServerSocket; } // retrieve delegation token for the given user diff --git a/service/src/java/org/apache/hive/service/cli/thrift/ThriftHttpCLIService.java b/service/src/java/org/apache/hive/service/cli/thrift/ThriftHttpCLIService.java index f7b1648..630555d 100644 --- a/service/src/java/org/apache/hive/service/cli/thrift/ThriftHttpCLIService.java +++ b/service/src/java/org/apache/hive/service/cli/thrift/ThriftHttpCLIService.java @@ -83,6 +83,7 @@ public void run() { + " Not configured for SSL connection"); } SslContextFactory sslContextFactory = new SslContextFactory(); + sslContextFactory.addExcludeProtocols("SSLv2", "SSLv3"); sslContextFactory.setKeyStorePath(keyStorePath); sslContextFactory.setKeyStorePassword(keyStorePassword); connector = new SslSelectChannelConnector(sslContextFactory);