diff --git a/jdbc/src/java/org/apache/hive/jdbc/HiveConnection.java b/jdbc/src/java/org/apache/hive/jdbc/HiveConnection.java index 7a674ab..2b4be7f 100644 --- a/jdbc/src/java/org/apache/hive/jdbc/HiveConnection.java +++ b/jdbc/src/java/org/apache/hive/jdbc/HiveConnection.java @@ -21,6 +21,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.security.KeyStore; +import java.security.SecureRandom; import java.sql.Array; import java.sql.Blob; import java.sql.CallableStatement; @@ -47,6 +48,9 @@ import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; import javax.security.sasl.Sasl; import javax.security.sasl.SaslException; @@ -348,11 +352,13 @@ public long getRetryInterval() { httpClientBuilder.addInterceptorFirst(requestInterceptor); // Configure http client for SSL if (useSsl) { + String useTwoWaySSL = sessConfMap.get(JdbcConnectionParams.USE_TWO_WAY_SSL); String sslTrustStorePath = sessConfMap.get(JdbcConnectionParams.SSL_TRUST_STORE); String sslTrustStorePassword = sessConfMap.get( JdbcConnectionParams.SSL_TRUST_STORE_PASSWORD); KeyStore sslTrustStore; SSLSocketFactory socketFactory; + /** * The code within the try block throws: * 1. SSLInitializationException @@ -366,11 +372,13 @@ public long getRetryInterval() { * and throw a SQLException. */ try { - if (sslTrustStorePath == null || sslTrustStorePath.isEmpty()) { + if (useTwoWaySSL != null && + useTwoWaySSL.equalsIgnoreCase(JdbcConnectionParams.TRUE)) { + socketFactory = getTwoWaySSLSocketFactory(); + } else if (sslTrustStorePath == null || sslTrustStorePath.isEmpty()) { // Create a default socket factory based on standard JSSE trust material socketFactory = SSLSocketFactory.getSocketFactory(); - } - else { + } else { // Pick trust store config from the given path sslTrustStore = KeyStore.getInstance(JdbcConnectionParams.SSL_TRUST_STORE_TYPE); sslTrustStore.load(new FileInputStream(sslTrustStorePath), @@ -451,7 +459,9 @@ private TTransport createBinaryTransport() throws SQLException, TTransportExcept if (isSslConnection()) { // get SSL socket String sslTrustStore = sessConfMap.get(JdbcConnectionParams.SSL_TRUST_STORE); - String sslTrustStorePassword = sessConfMap.get(JdbcConnectionParams.SSL_TRUST_STORE_PASSWORD); + String sslTrustStorePassword = sessConfMap.get( + JdbcConnectionParams.SSL_TRUST_STORE_PASSWORD); + if (sslTrustStore == null || sslTrustStore.isEmpty()) { transport = HiveAuthFactory.getSSLSocket(host, port, loginTimeout); } else { @@ -477,6 +487,49 @@ private TTransport createBinaryTransport() throws SQLException, TTransportExcept return transport; } + SSLSocketFactory getTwoWaySSLSocketFactory() throws SQLException { + SSLSocketFactory socketFactory = null; + + try { + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance( + JdbcConnectionParams.SUNX509_ALGORITHM_STRING, + JdbcConnectionParams.SUNJSSE_ALGORITHM_STRING); + String keyStorePath = sessConfMap.get(JdbcConnectionParams.SSL_KEY_STORE); + String keyStorePassword = sessConfMap.get(JdbcConnectionParams.SSL_KEY_STORE_PASSWORD); + KeyStore sslKeyStore = KeyStore.getInstance(JdbcConnectionParams.SSL_KEY_STORE_TYPE); + + if (keyStorePath == null || keyStorePath.isEmpty()) { + throw new IllegalArgumentException(JdbcConnectionParams.SSL_KEY_STORE + + " Not configured for 2 way SSL connection, keyStorePath param is empty"); + } + sslKeyStore.load(new FileInputStream(keyStorePath), + keyStorePassword.toCharArray()); + keyManagerFactory.init(sslKeyStore, keyStorePassword.toCharArray()); + + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( + JdbcConnectionParams.SUNX509_ALGORITHM_STRING); + String trustStorePath = sessConfMap.get(JdbcConnectionParams.SSL_TRUST_STORE); + String trustStorePassword = sessConfMap.get( + JdbcConnectionParams.SSL_TRUST_STORE_PASSWORD); + KeyStore sslTrustStore = KeyStore.getInstance(JdbcConnectionParams.SSL_TRUST_STORE_TYPE); + + if (trustStorePath == null || trustStorePath.isEmpty()) { + throw new IllegalArgumentException(JdbcConnectionParams.SSL_TRUST_STORE + + " Not configured for 2 way SSL connection"); + } + sslTrustStore.load(new FileInputStream(trustStorePath), + trustStorePassword.toCharArray()); + trustManagerFactory.init(sslTrustStore); + SSLContext context = SSLContext.getInstance("TLS"); + context.init(keyManagerFactory.getKeyManagers(), + trustManagerFactory.getTrustManagers(), new SecureRandom()); + socketFactory = new SSLSocketFactory(context); + } catch (Exception e) { + throw new SQLException("Error while initializing 2 way ssl socket factory ", e); + } + return socketFactory; + } + // Lookup the delegation token. First in the connection URL, then Configuration private String getClientDelegationToken(Map jdbcConnConf) throws SQLException { diff --git a/jdbc/src/java/org/apache/hive/jdbc/Utils.java b/jdbc/src/java/org/apache/hive/jdbc/Utils.java index 04bba06..0e4693b 100644 --- a/jdbc/src/java/org/apache/hive/jdbc/Utils.java +++ b/jdbc/src/java/org/apache/hive/jdbc/Utils.java @@ -113,6 +113,17 @@ // The http header prefix for additional headers which have to be appended to the request static final String HTTP_HEADER_PREFIX = "http.header."; + // --------------- Begin 2 way ssl options ------------------------- + // Use two way ssl. This param will take effect only when ssl=true + static final String USE_TWO_WAY_SSL = "twoWay"; + static final String TRUE = "true"; + static final String SSL_KEY_STORE = "sslKeyStore"; + static final String SSL_KEY_STORE_PASSWORD = "keyStorePassword"; + static final String SSL_KEY_STORE_TYPE = "JKS"; + static final String SUNX509_ALGORITHM_STRING = "SunX509"; + static final String SUNJSSE_ALGORITHM_STRING = "SunJSSE"; + // --------------- End 2 way ssl options ---------------------------- + // Non-configurable params: // Currently supports JKS keystore format static final String SSL_TRUST_STORE_TYPE = "JKS";