From 27b30409ec0f69245f75734d7567d3850c4f0eba Mon Sep 17 00:00:00 2001 From: Dilli Dorai Arumugam Date: Fri, 28 Mar 2014 13:04:06 -0700 Subject: [PATCH] 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 | 23 ++++++++++++++++++++++ 3 files changed, 57 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 7f6687e..d7d3126 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 String getUserName() { return threadLocalUserName.get(); } + private static ThreadLocal threadLocalProxyUserName = new ThreadLocal(){ + @Override + protected synchronized String initialValue() { + return null; + } + }; + + public static void setProxyUserName(String userName) { + LOG.debug("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 58f3e3b..046e4d9 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 @@ -539,12 +539,21 @@ 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.debug("Proxy user from query string: " + proxyUser); + + if (proxyUser == null && sessionConf != null && sessionConf.containsKey(HiveAuthFactory.HS2_PROXY_USER)) { + String proxyUserFromThriftBody = sessionConf.get(HiveAuthFactory.HS2_PROXY_USER); + LOG.debug("Proxy user from thrift body: " + proxyUserFromThriftBody); + 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); + // check whether substitution is allowed if (!hiveConf.getBoolVar(HiveConf.ConfVars.HIVE_SERVER2_ALLOW_USER_SUBSTITUTION)) { throw new HiveSQLException("Proxy user substitution is not allowed"); } @@ -557,7 +566,9 @@ private String getProxyUser(String realUser, Map sessionConf, // Verify proxy user privilege of the realUser for the proxyUser HiveAuthFactory.verifyProxyAccess(realUser, proxyUser, ipAddress, hiveConf); + LOG.debug("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..2bda9a4 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,11 @@ 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 +107,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 +306,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)