diff --git a/jdbc/src/java/org/apache/hive/jdbc/HiveConnection.java b/jdbc/src/java/org/apache/hive/jdbc/HiveConnection.java index 458158e91b..a654b05425 100644 --- a/jdbc/src/java/org/apache/hive/jdbc/HiveConnection.java +++ b/jdbc/src/java/org/apache/hive/jdbc/HiveConnection.java @@ -70,6 +70,7 @@ import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; +import javax.security.auth.Subject; import javax.security.sasl.Sasl; import javax.security.sasl.SaslException; import java.io.BufferedReader; @@ -81,6 +82,8 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; +import java.security.AccessControlContext; +import java.security.AccessController; import java.security.KeyStore; import java.security.SecureRandom; import java.sql.Array; @@ -140,6 +143,7 @@ private String initFile = null; private String wmPool = null, wmApp = null; private Properties clientInfo; + private Subject loggedInSubject; /** * Get all direct HiveServer2 URLs from a ZooKeeper based HiveServer2 URL @@ -397,15 +401,24 @@ private CloseableHttpClient getHttpClient(Boolean useSsl) throws SQLException { } // Configure http client for kerberos/password based authentication if (isKerberosAuthMode()) { + if (assumeSubject) { + // With this option, we're assuming that the external application, + // using the JDBC driver has done a JAAS kerberos login already + AccessControlContext context = AccessController.getContext(); + loggedInSubject = Subject.getSubject(context); + if (loggedInSubject == null) { + throw new SQLException("The Subject is not set"); + } + } /** * Add an interceptor which sets the appropriate header in the request. * It does the kerberos authentication and get the final service ticket, * for sending to the server before every request. * In https mode, the entire information is encrypted */ - requestInterceptor = new HttpKerberosRequestInterceptor( - sessConfMap.get(JdbcConnectionParams.AUTH_PRINCIPAL), host, getServerHttpUrl(useSsl), - assumeSubject, cookieStore, cookieName, useSsl, additionalHttpHeaders, customCookies); + requestInterceptor = new HttpKerberosRequestInterceptor(sessConfMap.get(JdbcConnectionParams.AUTH_PRINCIPAL), + host, getServerHttpUrl(useSsl), loggedInSubject, cookieStore, cookieName, useSsl, additionalHttpHeaders, + customCookies); } else { // Check for delegation token, if present add it in the header String tokenStr = getClientDelegationToken(sessConfMap); diff --git a/jdbc/src/java/org/apache/hive/jdbc/HttpKerberosRequestInterceptor.java b/jdbc/src/java/org/apache/hive/jdbc/HttpKerberosRequestInterceptor.java index 28d42d73b1..516825fa45 100644 --- a/jdbc/src/java/org/apache/hive/jdbc/HttpKerberosRequestInterceptor.java +++ b/jdbc/src/java/org/apache/hive/jdbc/HttpKerberosRequestInterceptor.java @@ -21,6 +21,8 @@ import java.util.Map; import java.util.concurrent.locks.ReentrantLock; +import javax.security.auth.Subject; + import org.apache.hive.service.auth.HttpAuthUtils; import org.apache.http.HttpException; import org.apache.http.HttpRequest; @@ -37,33 +39,30 @@ String principal; String host; String serverHttpUrl; - boolean assumeSubject; + Subject loggedInSubject; // A fair reentrant lock private static ReentrantLock kerberosLock = new ReentrantLock(true); - public HttpKerberosRequestInterceptor(String principal, String host, String serverHttpUrl, - boolean assumeSubject, CookieStore cs, String cn, boolean isSSL, - Map additionalHeaders, Map customCookies) { + public HttpKerberosRequestInterceptor(String principal, String host, String serverHttpUrl, Subject loggedInSubject, + CookieStore cs, String cn, boolean isSSL, Map additionalHeaders, + Map customCookies) { super(cs, cn, isSSL, additionalHeaders, customCookies); this.principal = principal; this.host = host; this.serverHttpUrl = serverHttpUrl; - this.assumeSubject = assumeSubject; + this.loggedInSubject = loggedInSubject; } @Override - protected void addHttpAuthHeader(HttpRequest httpRequest, - HttpContext httpContext) throws Exception { - try { + protected void addHttpAuthHeader(HttpRequest httpRequest, HttpContext httpContext) throws Exception { + try { // Generate the service ticket for sending to the server. // Locking ensures the tokens are unique in case of concurrent requests kerberosLock.lock(); - String kerberosAuthHeader = HttpAuthUtils.getKerberosServiceTicket( - principal, host, serverHttpUrl, assumeSubject); + String kerberosAuthHeader = HttpAuthUtils.getKerberosServiceTicket(principal, host, serverHttpUrl, loggedInSubject); // Set the session key token (Base64 encoded) in the headers - httpRequest.addHeader(HttpAuthUtils.AUTHORIZATION + ": " + - HttpAuthUtils.NEGOTIATE + " ", kerberosAuthHeader); + httpRequest.addHeader(HttpAuthUtils.AUTHORIZATION + ": " + HttpAuthUtils.NEGOTIATE + " ", kerberosAuthHeader); } catch (Exception e) { throw new HttpException(e.getMessage(), e); } finally { diff --git a/service/src/java/org/apache/hive/service/auth/HttpAuthUtils.java b/service/src/java/org/apache/hive/service/auth/HttpAuthUtils.java index 12e63dae10..d18ac87a69 100644 --- a/service/src/java/org/apache/hive/service/auth/HttpAuthUtils.java +++ b/service/src/java/org/apache/hive/service/auth/HttpAuthUtils.java @@ -18,8 +18,6 @@ package org.apache.hive.service.auth; -import java.security.AccessControlContext; -import java.security.AccessController; import java.security.PrivilegedExceptionAction; import java.security.SecureRandom; import java.util.Arrays; @@ -33,7 +31,6 @@ import org.apache.commons.codec.binary.Base64; import org.apache.hadoop.hive.metastore.security.HadoopThriftAuthBridge; -import org.apache.hadoop.hive.shims.ShimLoader; import org.apache.hadoop.security.UserGroupInformation; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.HttpContext; @@ -64,23 +61,14 @@ * @return Stringified Base64 encoded kerberosAuthHeader on success * @throws Exception */ - public static String getKerberosServiceTicket(String principal, String host, - String serverHttpUrl, boolean assumeSubject) throws Exception { - String serverPrincipal = - HadoopThriftAuthBridge.getBridge().getServerPrincipal(principal, host); - if (assumeSubject) { - // With this option, we're assuming that the external application, - // using the JDBC driver has done a JAAS kerberos login already - AccessControlContext context = AccessController.getContext(); - Subject subject = Subject.getSubject(context); - if (subject == null) { - throw new Exception("The Subject is not set"); - } - return Subject.doAs(subject, new HttpKerberosClientAction(serverPrincipal, serverHttpUrl)); + public static String getKerberosServiceTicket(String principal, String host, String serverHttpUrl, + Subject loggedInSubject) throws Exception { + String serverPrincipal = HadoopThriftAuthBridge.getBridge().getServerPrincipal(principal, host); + if (loggedInSubject != null) { + return Subject.doAs(loggedInSubject, new HttpKerberosClientAction(serverPrincipal, serverHttpUrl)); } else { // JAAS login from ticket cache to setup the client UserGroupInformation - UserGroupInformation clientUGI = - HadoopThriftAuthBridge.getBridge().getCurrentUGIWithConf("kerberos"); + UserGroupInformation clientUGI = HadoopThriftAuthBridge.getBridge().getCurrentUGIWithConf("kerberos"); return clientUGI.doAs(new HttpKerberosClientAction(serverPrincipal, serverHttpUrl)); } }