From ae5def5d35b9364c577896a9e13d7adbc6913a02 Mon Sep 17 00:00:00 2001 From: Dilli Dorai Arumugam Date: Tue, 25 Mar 2014 21:45:14 -0700 Subject: [PATCH] BUG-15481/HIVE-6738: HiveServer2 secure Thrift/HTTP needs to accept doAs parameter from proxying intermediary --- .../hive/service/cli/session/SessionManager.java | 20 ++++++++++++++++++++ .../hive/service/cli/thrift/ThriftCLIService.java | 17 ++++++++++++++--- .../hive/service/cli/thrift/ThriftHttpServlet.java | 22 ++++++++++++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/service/src/java/org/apache/hive/service/cli/session/SessionManager.java b/service/src/java/org/apache/hive/service/cli/session/SessionManager.java index 840fd40..db209f1 100644 --- a/service/src/java/org/apache/hive/service/cli/session/SessionManager.java +++ b/service/src/java/org/apache/hive/service/cli/session/SessionManager.java @@ -183,6 +183,26 @@ public static void clearUserName() { threadLocalUserName.remove(); } + private static ThreadLocal threadLocalProxyUserName = new ThreadLocal(){ + @Override + protected synchronized String initialValue() { + return null; + } + }; + + public static void setProxyUserName(String userName) { + LOG.info("setting proxy user name based on query param to: " + userName); + threadLocalProxyUserName.set(userName); + } + + public static String getProxyUserName() { + return threadLocalProxyUserName.get(); + } + + public static void clearProxyUserName() { + threadLocalProxyUserName.remove(); + } + // execute session hooks private void executeSessionHooks(HiveSession session) throws Exception { List sessionHooks = HookUtils.getHooks(hiveConf, diff --git a/service/src/java/org/apache/hive/service/cli/thrift/ThriftCLIService.java b/service/src/java/org/apache/hive/service/cli/thrift/ThriftCLIService.java index 5186fe9..77f7670 100644 --- a/service/src/java/org/apache/hive/service/cli/thrift/ThriftCLIService.java +++ b/service/src/java/org/apache/hive/service/cli/thrift/ThriftCLIService.java @@ -541,12 +541,22 @@ public TFetchResultsResp FetchResults(TFetchResultsReq req) throws TException { */ private String getProxyUser(String realUser, Map sessionConf, String ipAddress) throws HiveSQLException { - if (sessionConf == null || !sessionConf.containsKey(HiveAuthFactory.HS2_PROXY_USER)) { + + String proxyUser = SessionManager.getProxyUserName(); + LOG.info("Proxy user from query string: " + proxyUser); + + if (sessionConf != null && sessionConf.containsKey(HiveAuthFactory.HS2_PROXY_USER)) { + String proxyUserFromThriftBody = sessionConf.get(HiveAuthFactory.HS2_PROXY_USER); + LOG.info("Proxy user from thrift body: " + proxyUserFromThriftBody); + if (proxyUser == null) { + proxyUser = proxyUserFromThriftBody; + } + } + + if (proxyUser == null) { return realUser; } - // Extract the proxy user name and check if we are allowed to do the substitution - String proxyUser = sessionConf.get(HiveAuthFactory.HS2_PROXY_USER); if (!hiveConf.getBoolVar(HiveConf.ConfVars.HIVE_SERVER2_ALLOW_USER_SUBSTITUTION)) { throw new HiveSQLException("Proxy user substitution is not allowed"); } @@ -559,6 +569,7 @@ private String getProxyUser(String realUser, Map sessionConf, // Verify proxy user privilege of the realUser for the proxyUser HiveAuthFactory.verifyProxyAccess(realUser, proxyUser, ipAddress, hiveConf); + LOG.info("Verified proxy user: " + proxyUser); return proxyUser; } } diff --git a/service/src/java/org/apache/hive/service/cli/thrift/ThriftHttpServlet.java b/service/src/java/org/apache/hive/service/cli/thrift/ThriftHttpServlet.java index c579db5..d971798 100644 --- a/service/src/java/org/apache/hive/service/cli/thrift/ThriftHttpServlet.java +++ b/service/src/java/org/apache/hive/service/cli/thrift/ThriftHttpServlet.java @@ -21,6 +21,9 @@ import java.io.IOException; import java.security.PrivilegedExceptionAction; +import java.util.Map; +import java.util.Set; + import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -76,6 +79,10 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) // For a kerberos setup if(isKerberosAuthMode(authType)) { clientUserName = doKerberosAuth(request); + String doAsQueryParam = getDoAsQueryParam(request.getQueryString()); + if (doAsQueryParam != null) { + SessionManager.setProxyUserName(doAsQueryParam); + } } else { clientUserName = doPasswdAuth(request, authType); @@ -99,6 +106,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) finally { // Clear the thread local username since we set it in each http request SessionManager.clearUserName(); + SessionManager.clearProxyUserName(); } } @@ -297,6 +305,20 @@ private boolean isKerberosAuthMode(String authType) { return authType.equalsIgnoreCase(HiveAuthFactory.AuthTypes.KERBEROS.toString()); } + private static String getDoAsQueryParam(String queryString) { + if (queryString == null) { + return null; + } + Map params = javax.servlet.http.HttpUtils.parseQueryString( queryString ); + Set keySet = params.keySet(); + for (String key: keySet) { + if (key.equalsIgnoreCase("doAs")) { + return params.get(key)[0]; + } + } + return null; + } + } -- 1.7.12.4 (Apple Git-37)