diff --git a/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java b/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java index 391cdc1c83..3ccc7da7af 100644 --- a/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java +++ b/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java @@ -3486,6 +3486,13 @@ private static void populateLlapDaemonVarsSet(Set llapDaemonVarsSetLocal " it is empty, which means that all the connections to HiveServer2 are authenticated. " + "When it is non-empty, the client has to provide a Hive user name. Any password, if " + "provided, will not be used when authentication is skipped."), + HIVE_SERVER2_TRUSTED_DOMAIN_USE_XFF_HEADER("hive.server2.trusted.domain.use.xff.header", false, + "When trusted domain authentication is enabled, the clients connecting to the HS2 could pass" + + "through many layers of proxy. Some proxies append its own ip address to 'X-Forwarded-For' header" + + "before passing on the request to another proxy or HS2. Some proxies also connect on behalf of client" + + "and may create a separate connection to HS2 without binding using client IP. For such environments, instead" + + "of looking at client IP from the request, if this config is set and if 'X-Forwarded-For' is present," + + "trusted domain authentication will use left most ip address from X-Forwarded-For header."), HIVE_SERVER2_ALLOW_USER_SUBSTITUTION("hive.server2.allow.user.substitution", true, "Allow alternate user to be specified as part of HiveServer2 open connection request."), HIVE_SERVER2_KERBEROS_KEYTAB("hive.server2.authentication.kerberos.keytab", "", 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 292723ec6e..f5411c625b 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 @@ -150,16 +150,36 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) LOG.info("Could not validate cookie sent, will try to generate a new cookie"); } } + + // Set the thread local ip address + SessionManager.setIpAddress(clientIpAddress); + + // get forwarded hosts address + String forwarded_for = request.getHeader(X_FORWARDED_FOR); + if (forwarded_for != null) { + LOG.debug("{}:{}", X_FORWARDED_FOR, forwarded_for); + List forwardedAddresses = Arrays.asList(forwarded_for.split(",")); + SessionManager.setForwardedAddresses(forwardedAddresses); + } else { + SessionManager.setForwardedAddresses(Collections.emptyList()); + } + // If the cookie based authentication is not enabled or the request does not have a valid // cookie, use authentication depending on the server setup. if (clientUserName == null) { String trustedDomain = HiveConf.getVar(hiveConf, ConfVars.HIVE_SERVER2_TRUSTED_DOMAIN).trim(); - + final boolean useXff = HiveConf.getBoolVar(hiveConf, ConfVars.HIVE_SERVER2_TRUSTED_DOMAIN_USE_XFF_HEADER); + if (useXff && !trustedDomain.isEmpty() && + SessionManager.getForwardedAddresses() != null && !SessionManager.getForwardedAddresses().isEmpty()) { + // general format of XFF header is 'X-Forwarded-For: client, proxy1, proxy2' where left most being the client + clientIpAddress = SessionManager.getForwardedAddresses().get(0); + LOG.info("Trusted domain authN is enabled. clientIp from X-Forwarded-For header: {}", clientIpAddress); + } // Skip authentication if the connection is from the trusted domain, if specified. // getRemoteHost may or may not return the FQDN of the remote host depending upon the // HTTP server configuration. So, force a reverse DNS lookup. String remoteHostName = - InetAddress.getByName(request.getRemoteHost()).getCanonicalHostName(); + InetAddress.getByName(clientIpAddress).getCanonicalHostName(); if (!trustedDomain.isEmpty() && PlainSaslHelper.isHostFromTrustedDomain(remoteHostName, trustedDomain)) { LOG.info("No authentication performed because the connecting host " + remoteHostName + @@ -197,18 +217,6 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) SessionManager.setProxyUserName(doAsQueryParam); } - // Set the thread local ip address - SessionManager.setIpAddress(clientIpAddress); - - // get forwarded hosts address - String forwarded_for = request.getHeader(X_FORWARDED_FOR); - if (forwarded_for != null) { - LOG.debug("{}:{}", X_FORWARDED_FOR, forwarded_for); - List forwardedAddresses = Arrays.asList(forwarded_for.split(",")); - SessionManager.setForwardedAddresses(forwardedAddresses); - } else { - SessionManager.setForwardedAddresses(Collections.emptyList()); - } // Generate new cookie and add it to the response if (requireNewCookie &&