Repository: hive
Updated Branches:
  refs/heads/master 39f1e82ad -> fdd8fabdc


HIVE-18447: JDBC: Provide a way for JDBC users to pass cookie info via 
connection string (Vaibhav Gumashta reviewed by Thejas Nair)


Project: http://git-wip-us.apache.org/repos/asf/hive/repo
Commit: http://git-wip-us.apache.org/repos/asf/hive/commit/fdd8fabd
Tree: http://git-wip-us.apache.org/repos/asf/hive/tree/fdd8fabd
Diff: http://git-wip-us.apache.org/repos/asf/hive/diff/fdd8fabd

Branch: refs/heads/master
Commit: fdd8fabdcc5f8eb6ce749f55ec4637a0b96b4423
Parents: 39f1e82
Author: Vaibhav Gumashta <vgumas...@hortonworks.com>
Authored: Fri Feb 2 10:22:18 2018 -0800
Committer: Vaibhav Gumashta <vgumas...@hortonworks.com>
Committed: Fri Feb 2 10:22:18 2018 -0800

----------------------------------------------------------------------
 .../TestThriftHttpCLIServiceFeatures.java       | 70 +++++++++++++++-----
 .../org/apache/hive/jdbc/HiveConnection.java    | 23 ++++---
 .../hive/jdbc/HttpBasicAuthInterceptor.java     | 13 ++--
 .../jdbc/HttpKerberosRequestInterceptor.java    |  8 +--
 .../hive/jdbc/HttpRequestInterceptorBase.java   | 20 +++++-
 .../hive/jdbc/HttpTokenAuthInterceptor.java     |  6 +-
 jdbc/src/java/org/apache/hive/jdbc/Utils.java   |  8 ++-
 7 files changed, 105 insertions(+), 43 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hive/blob/fdd8fabd/itests/hive-unit/src/test/java/org/apache/hive/service/cli/thrift/TestThriftHttpCLIServiceFeatures.java
----------------------------------------------------------------------
diff --git 
a/itests/hive-unit/src/test/java/org/apache/hive/service/cli/thrift/TestThriftHttpCLIServiceFeatures.java
 
b/itests/hive-unit/src/test/java/org/apache/hive/service/cli/thrift/TestThriftHttpCLIServiceFeatures.java
index 93b10fb..9012867 100644
--- 
a/itests/hive-unit/src/test/java/org/apache/hive/service/cli/thrift/TestThriftHttpCLIServiceFeatures.java
+++ 
b/itests/hive-unit/src/test/java/org/apache/hive/service/cli/thrift/TestThriftHttpCLIServiceFeatures.java
@@ -90,18 +90,19 @@ public class TestThriftHttpCLIServiceFeatures  {
    */
   public class HttpBasicAuthInterceptorWithLogging extends 
HttpBasicAuthInterceptor {
 
-   ArrayList<String> requestHeaders;
+    ArrayList<String> requestHeaders;
+    String cookieHeader;
 
-   public HttpBasicAuthInterceptorWithLogging(String username,
-      String password, CookieStore cookieStore, String cn, boolean isSSL,
-      Map<String, String> additionalHeaders) {
-      super(username, password, cookieStore, cn, isSSL, additionalHeaders);
+    public HttpBasicAuthInterceptorWithLogging(String username, String 
password,
+        CookieStore cookieStore, String cn, boolean isSSL, Map<String, String> 
additionalHeaders,
+        Map<String, String> customCookies) {
+      super(username, password, cookieStore, cn, isSSL, additionalHeaders, 
customCookies);
       requestHeaders = new ArrayList<String>();
     }
 
     @Override
     public void process(HttpRequest httpRequest, HttpContext httpContext)
-      throws HttpException, IOException {
+        throws HttpException, IOException {
       super.process(httpRequest, httpContext);
 
       String currHeaders = "";
@@ -110,11 +111,21 @@ public class TestThriftHttpCLIServiceFeatures  {
         currHeaders += h.getName() + ":" + h.getValue() + " ";
       }
       requestHeaders.add(currHeaders);
+
+      Header[] headers = httpRequest.getHeaders("Cookie");
+      cookieHeader = "";
+      for (Header h : headers) {
+        cookieHeader = cookieHeader + h.getName() + ":" + h.getValue();
+      }
     }
 
-    public ArrayList<String>  getRequestHeaders() {
+    public ArrayList<String> getRequestHeaders() {
       return requestHeaders;
     }
+
+    public String getCookieHeader() {
+      return cookieHeader;
+    }
   }
 
 
@@ -130,7 +141,7 @@ public class TestThriftHttpCLIServiceFeatures  {
     assertNotNull(ThriftCLIServiceTest.hiveServer2);
     assertNotNull(ThriftCLIServiceTest.hiveConf);
     HiveConf hiveConf = ThriftCLIServiceTest.hiveConf;
-    
+
     hiveConf.setBoolVar(ConfVars.HIVE_SERVER2_ENABLE_DOAS, false);
     hiveConf.setVar(ConfVars.HIVE_SERVER2_THRIFT_BIND_HOST, 
ThriftCLIServiceTest.host);
     hiveConf.setIntVar(ConfVars.HIVE_SERVER2_THRIFT_HTTP_PORT, 
ThriftCLIServiceTest.port);
@@ -219,7 +230,7 @@ public class TestThriftHttpCLIServiceFeatures  {
     String httpUrl = getHttpUrl();
     httpClient.addRequestInterceptor(
         new HttpBasicAuthInterceptor(ThriftCLIServiceTest.USERNAME, 
ThriftCLIServiceTest.PASSWORD,
-            null, null, false, null));
+            null, null, false, null, null));
     return new THttpClient(httpUrl, httpClient);
   }
 
@@ -243,7 +254,7 @@ public class TestThriftHttpCLIServiceFeatures  {
     additionalHeaders.put("key2", "value2");
     HttpBasicAuthInterceptorWithLogging authInt =
       new HttpBasicAuthInterceptorWithLogging(ThriftCLIServiceTest.USERNAME, 
ThriftCLIServiceTest.PASSWORD, null, null,
-      false, additionalHeaders);
+      false, additionalHeaders, null);
     hClient.addRequestInterceptor(authInt);
     transport = new THttpClient(httpUrl, hClient);
     TCLIService.Client httpClient = getClient(transport);
@@ -260,6 +271,35 @@ public class TestThriftHttpCLIServiceFeatures  {
   }
 
   /**
+   * Test additional http headers passed to request interceptor.
+   * @throws Exception
+   */
+  @Test
+  public void testCustomCookies() throws Exception {
+    TTransport transport;
+    DefaultHttpClient hClient = new DefaultHttpClient();
+    String httpUrl = getHttpUrl();
+    Map<String, String> additionalHeaders = new HashMap<String, String>();
+    Map<String, String> cookieHeaders = new HashMap<String, String>();
+    cookieHeaders.put("key1", "value1");
+    cookieHeaders.put("key2", "value2");
+    HttpBasicAuthInterceptorWithLogging authInt =
+      new HttpBasicAuthInterceptorWithLogging(ThriftCLIServiceTest.USERNAME, 
ThriftCLIServiceTest.PASSWORD, null, null,
+      false, additionalHeaders, cookieHeaders);
+    hClient.addRequestInterceptor(authInt);
+    transport = new THttpClient(httpUrl, hClient);
+    TCLIService.Client httpClient = getClient(transport);
+
+    // Create a new open session request object
+    TOpenSessionReq openReq = new TOpenSessionReq();
+    httpClient.OpenSession(openReq).getSessionHandle();
+    String cookieHeader = authInt.getCookieHeader();
+    assertTrue(cookieHeader.contains("key1=value1"));
+    assertTrue(cookieHeader.contains("key2=value2"));
+  }
+
+
+  /**
    * This factory creates a mocked HiveAuthorizer class.
    * Use the mocked class to capture the argument passed to it in the test 
case.
    */
@@ -299,9 +339,9 @@ public class TestThriftHttpCLIServiceFeatures  {
     // interceptor for adding username, pwd
     HttpBasicAuthInterceptor authInt = new 
HttpBasicAuthInterceptor(ThriftCLIServiceTest.USERNAME,
         ThriftCLIServiceTest.PASSWORD, null, null,
-        false, null);
+        false, null, null);
     hClient.addRequestInterceptor(authInt);
-    
+
     transport = new THttpClient(httpUrl, hClient);
     TCLIService.Client httpClient = getClient(transport);
 
@@ -327,9 +367,9 @@ public class TestThriftHttpCLIServiceFeatures  {
     List<String> auditIPAddresses = new 
ArrayList<String>(context.getForwardedAddresses());
     Collections.sort(auditIPAddresses);
     Collections.sort(headerIPs);
-    
+
     Assert.assertEquals("Checking forwarded IP Address" , headerIPs, 
auditIPAddresses);
   }
-  
-  
+
+
 }

http://git-wip-us.apache.org/repos/asf/hive/blob/fdd8fabd/jdbc/src/java/org/apache/hive/jdbc/HiveConnection.java
----------------------------------------------------------------------
diff --git a/jdbc/src/java/org/apache/hive/jdbc/HiveConnection.java 
b/jdbc/src/java/org/apache/hive/jdbc/HiveConnection.java
index cb2f09c..c3f9c63 100644
--- a/jdbc/src/java/org/apache/hive/jdbc/HiveConnection.java
+++ b/jdbc/src/java/org/apache/hive/jdbc/HiveConnection.java
@@ -378,15 +378,19 @@ public class HiveConnection implements 
java.sql.Connection {
     // Request interceptor for any request pre-processing logic
     HttpRequestInterceptor requestInterceptor;
     Map<String, String> additionalHttpHeaders = new HashMap<String, String>();
+    Map<String, String> customCookies = new HashMap<String, String>();
 
     // Retrieve the additional HttpHeaders
     for (Map.Entry<String, String> entry : sessConfMap.entrySet()) {
       String key = entry.getKey();
-
       if (key.startsWith(JdbcConnectionParams.HTTP_HEADER_PREFIX)) {
         
additionalHttpHeaders.put(key.substring(JdbcConnectionParams.HTTP_HEADER_PREFIX.length()),
           entry.getValue());
       }
+      if (key.startsWith(JdbcConnectionParams.HTTP_COOKIE_PREFIX)) {
+        
customCookies.put(key.substring(JdbcConnectionParams.HTTP_COOKIE_PREFIX.length()),
+          entry.getValue());
+      }
     }
     // Configure http client for kerberos/password based authentication
     if (isKerberosAuthMode()) {
@@ -396,25 +400,22 @@ public class HiveConnection implements 
java.sql.Connection {
        * 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);
+      requestInterceptor = new HttpKerberosRequestInterceptor(
+          sessConfMap.get(JdbcConnectionParams.AUTH_PRINCIPAL), host, 
getServerHttpUrl(useSsl),
+          assumeSubject, cookieStore, cookieName, useSsl, 
additionalHttpHeaders, customCookies);
     } else {
       // Check for delegation token, if present add it in the header
       String tokenStr = getClientDelegationToken(sessConfMap);
       if (tokenStr != null) {
-        requestInterceptor =
-            new HttpTokenAuthInterceptor(tokenStr, cookieStore, cookieName, 
useSsl,
-                additionalHttpHeaders);
+        requestInterceptor = new HttpTokenAuthInterceptor(tokenStr, 
cookieStore, cookieName, useSsl,
+            additionalHttpHeaders, customCookies);
       } else {
       /**
        * Add an interceptor to pass username/password in the header.
        * In https mode, the entire information is encrypted
        */
-        requestInterceptor =
-            new HttpBasicAuthInterceptor(getUserName(), getPassword(), 
cookieStore, cookieName,
-                useSsl, additionalHttpHeaders);
+        requestInterceptor = new HttpBasicAuthInterceptor(getUserName(), 
getPassword(), cookieStore,
+            cookieName, useSsl, additionalHttpHeaders, customCookies);
       }
     }
     // Configure http client for cookie based authentication

http://git-wip-us.apache.org/repos/asf/hive/blob/fdd8fabd/jdbc/src/java/org/apache/hive/jdbc/HttpBasicAuthInterceptor.java
----------------------------------------------------------------------
diff --git a/jdbc/src/java/org/apache/hive/jdbc/HttpBasicAuthInterceptor.java 
b/jdbc/src/java/org/apache/hive/jdbc/HttpBasicAuthInterceptor.java
index 5d2ddb5..1887e07 100644
--- a/jdbc/src/java/org/apache/hive/jdbc/HttpBasicAuthInterceptor.java
+++ b/jdbc/src/java/org/apache/hive/jdbc/HttpBasicAuthInterceptor.java
@@ -29,8 +29,8 @@ import org.apache.http.impl.auth.BasicScheme;
 import org.apache.http.protocol.HttpContext;
 
 /**
- * The class is instantiated with the username and password, it is then
- * used to add header with these credentials to HTTP requests
+ * The class is instantiated with the username and password, it is then used 
to add header with
+ * these credentials to HTTP requests
  *
  */
 public class HttpBasicAuthInterceptor extends HttpRequestInterceptorBase {
@@ -38,17 +38,18 @@ public class HttpBasicAuthInterceptor extends 
HttpRequestInterceptorBase {
   AuthSchemeBase authScheme;
 
   public HttpBasicAuthInterceptor(String username, String password, 
CookieStore cookieStore,
-                           String cn, boolean isSSL, Map<String, String> 
additionalHeaders) {
-    super(cookieStore, cn, isSSL, additionalHeaders);
+      String cn, boolean isSSL, Map<String, String> additionalHeaders,
+      Map<String, String> customCookies) {
+    super(cookieStore, cn, isSSL, additionalHeaders, customCookies);
     this.authScheme = new BasicScheme();
-    if (username != null){
+    if (username != null) {
       this.credentials = new UsernamePasswordCredentials(username, password);
     }
   }
 
   @Override
   protected void addHttpAuthHeader(HttpRequest httpRequest, HttpContext 
httpContext)
-    throws Exception {
+      throws Exception {
     Header basicAuthHeader = authScheme.authenticate(credentials, httpRequest, 
httpContext);
     httpRequest.addHeader(basicAuthHeader);
   }

http://git-wip-us.apache.org/repos/asf/hive/blob/fdd8fabd/jdbc/src/java/org/apache/hive/jdbc/HttpKerberosRequestInterceptor.java
----------------------------------------------------------------------
diff --git 
a/jdbc/src/java/org/apache/hive/jdbc/HttpKerberosRequestInterceptor.java 
b/jdbc/src/java/org/apache/hive/jdbc/HttpKerberosRequestInterceptor.java
index 37862be..28d42d7 100644
--- a/jdbc/src/java/org/apache/hive/jdbc/HttpKerberosRequestInterceptor.java
+++ b/jdbc/src/java/org/apache/hive/jdbc/HttpKerberosRequestInterceptor.java
@@ -42,10 +42,10 @@ public class HttpKerberosRequestInterceptor extends 
HttpRequestInterceptorBase {
   // 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<String, String> additionalHeaders) {
-    super(cs, cn, isSSL, additionalHeaders);
+  public HttpKerberosRequestInterceptor(String principal, String host, String 
serverHttpUrl,
+      boolean assumeSubject, CookieStore cs, String cn, boolean isSSL,
+      Map<String, String> additionalHeaders, Map<String, String> 
customCookies) {
+    super(cs, cn, isSSL, additionalHeaders, customCookies);
     this.principal = principal;
     this.host = host;
     this.serverHttpUrl = serverHttpUrl;

http://git-wip-us.apache.org/repos/asf/hive/blob/fdd8fabd/jdbc/src/java/org/apache/hive/jdbc/HttpRequestInterceptorBase.java
----------------------------------------------------------------------
diff --git a/jdbc/src/java/org/apache/hive/jdbc/HttpRequestInterceptorBase.java 
b/jdbc/src/java/org/apache/hive/jdbc/HttpRequestInterceptorBase.java
index cf1a11e..1ef0ab1 100644
--- a/jdbc/src/java/org/apache/hive/jdbc/HttpRequestInterceptorBase.java
+++ b/jdbc/src/java/org/apache/hive/jdbc/HttpRequestInterceptorBase.java
@@ -22,6 +22,7 @@ import java.io.IOException;
 import java.util.Map;
 import java.util.concurrent.locks.ReentrantLock;
 
+import org.apache.http.Header;
 import org.apache.http.HttpException;
 import org.apache.http.HttpRequest;
 import org.apache.http.HttpRequestInterceptor;
@@ -35,18 +36,20 @@ public abstract class HttpRequestInterceptorBase implements 
HttpRequestIntercept
   String cookieName;
   boolean isSSL;
   Map<String, String> additionalHeaders;
+  Map<String, String> customCookies;
 
   // Abstract function to add HttpAuth Header
   protected abstract void addHttpAuthHeader(HttpRequest httpRequest, 
HttpContext httpContext)
     throws Exception;
 
   public HttpRequestInterceptorBase(CookieStore cs, String cn, boolean isSSL,
-    Map<String, String> additionalHeaders) {
+      Map<String, String> additionalHeaders, Map<String, String> 
customCookies) {
     this.cookieStore = cs;
     this.isCookieEnabled = (cs != null);
     this.cookieName = cn;
     this.isSSL = isSSL;
     this.additionalHeaders = additionalHeaders;
+    this.customCookies = customCookies;
   }
 
   @Override
@@ -82,6 +85,21 @@ public abstract class HttpRequestInterceptorBase implements 
HttpRequestIntercept
           httpRequest.addHeader(entry.getKey(), entry.getValue());
         }
       }
+      // Add custom cookies if passed to the jdbc driver
+      if (customCookies != null) {
+        String cookieHeaderKeyValues = "";
+        Header cookieHeaderServer = httpRequest.getFirstHeader("Cookie");
+        if ((cookieHeaderServer != null) && (cookieHeaderServer.getValue() != 
null)) {
+          cookieHeaderKeyValues = cookieHeaderServer.getValue();
+        }
+        for (Map.Entry<String, String> entry : customCookies.entrySet()) {
+          cookieHeaderKeyValues += ";" + entry.getKey() + "=" + 
entry.getValue();
+        }
+        if (cookieHeaderKeyValues.startsWith(";")) {
+          cookieHeaderKeyValues = cookieHeaderKeyValues.substring(1);
+        }
+        httpRequest.addHeader("Cookie", cookieHeaderKeyValues);
+      }
     } catch (Exception e) {
       throw new HttpException(e.getMessage(), e);
     }

http://git-wip-us.apache.org/repos/asf/hive/blob/fdd8fabd/jdbc/src/java/org/apache/hive/jdbc/HttpTokenAuthInterceptor.java
----------------------------------------------------------------------
diff --git a/jdbc/src/java/org/apache/hive/jdbc/HttpTokenAuthInterceptor.java 
b/jdbc/src/java/org/apache/hive/jdbc/HttpTokenAuthInterceptor.java
index 59a91dd..fbfa7f6 100644
--- a/jdbc/src/java/org/apache/hive/jdbc/HttpTokenAuthInterceptor.java
+++ b/jdbc/src/java/org/apache/hive/jdbc/HttpTokenAuthInterceptor.java
@@ -32,10 +32,10 @@ import org.apache.http.protocol.HttpContext;
 public class HttpTokenAuthInterceptor extends HttpRequestInterceptorBase {
   private String tokenStr;
   private static final String HIVE_DELEGATION_TOKEN_HEADER =  
"X-Hive-Delegation-Token";
-  
+
   public HttpTokenAuthInterceptor(String tokenStr, CookieStore cookieStore, 
String cn,
-      boolean isSSL, Map<String, String> additionalHeaders) {
-    super(cookieStore, cn, isSSL, additionalHeaders);
+      boolean isSSL, Map<String, String> additionalHeaders, Map<String, 
String> customCookies) {
+    super(cookieStore, cn, isSSL, additionalHeaders, customCookies);
     this.tokenStr = tokenStr;
   }
 

http://git-wip-us.apache.org/repos/asf/hive/blob/fdd8fabd/jdbc/src/java/org/apache/hive/jdbc/Utils.java
----------------------------------------------------------------------
diff --git a/jdbc/src/java/org/apache/hive/jdbc/Utils.java 
b/jdbc/src/java/org/apache/hive/jdbc/Utils.java
index f7f3854..9a12977 100644
--- a/jdbc/src/java/org/apache/hive/jdbc/Utils.java
+++ b/jdbc/src/java/org/apache/hive/jdbc/Utils.java
@@ -124,9 +124,11 @@ public class Utils {
     static final String FETCH_SIZE = "fetchSize";
     static final String INIT_FILE = "initFile";
     static final String WM_POOL = "wmPool";
+    // Cookie prefix
+    static final String HTTP_COOKIE_PREFIX = "http.cookie.";
 
     // We support ways to specify application name modeled after some existing 
DBs, since
-    // there's no standard approach. 
+    // there's no standard approach.
     // MSSQL: applicationName 
https://docs.microsoft.com/en-us/sql/connect/jdbc/building-the-connection-url
     // Postgres 9~: ApplicationName 
https://jdbc.postgresql.org/documentation/91/connect.html
     // Note: various ODBC names used include "Application Name", "APP", etc. 
Add those?
@@ -164,7 +166,7 @@ public class Utils {
 
     public JdbcConnectionParams() {
     }
-    
+
     public JdbcConnectionParams(JdbcConnectionParams params) {
       this.host = params.host;
       this.port = params.port;
@@ -404,7 +406,7 @@ public class Utils {
         connParams.getHiveVars().put(varMatcher.group(1), varMatcher.group(2));
       }
     }
-    
+
     // Apply configs supplied in the JDBC connection properties object
     for (Map.Entry<Object, Object> kv : info.entrySet()) {
       if ((kv.getKey() instanceof String)) {

Reply via email to