This is an automated email from the ASF dual-hosted git repository.
prasanthj pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hive.git
The following commit(s) were added to refs/heads/master by this push:
new 0e4d16b HIVE-21009: Adding ability for user to set bind user (David
McGinnis reviewed by Prasanth Jayachandran)
0e4d16b is described below
commit 0e4d16b462bf9abd7ec58e60936e24ee4302736c
Author: David McGinnis <[email protected]>
AuthorDate: Wed Feb 6 14:52:16 2019 -0800
HIVE-21009: Adding ability for user to set bind user (David McGinnis
reviewed by Prasanth Jayachandran)
---
.../java/org/apache/hadoop/hive/conf/HiveConf.java | 10 ++
service/pom.xml | 11 ++
.../auth/LdapAuthenticationProviderImpl.java | 32 +++++-
.../auth/TestLdapAuthenticationProviderImpl.java | 113 +++++++++++++++++++++
4 files changed, 164 insertions(+), 2 deletions(-)
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 a3b03ca..2156ff1 100644
--- a/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java
+++ b/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java
@@ -3499,6 +3499,16 @@ public class HiveConf extends Configuration {
"For example:
(&(objectClass=group)(objectClass=top)(instanceType=4)(cn=Domain*)) \n" +
"(&(objectClass=person)(|(sAMAccountName=admin)(|(memberOf=CN=Domain
Admins,CN=Users,DC=domain,DC=com)" +
"(memberOf=CN=Administrators,CN=Builtin,DC=domain,DC=com))))"),
+
HIVE_SERVER2_PLAIN_LDAP_BIND_USER("hive.server2.authentication.ldap.binddn",
null,
+ "The user with which to bind to the LDAP server, and search for the
full domain name " +
+ "of the user being authenticated.\n" +
+ "This should be the full domain name of the user, and should have
search access across all " +
+ "users in the LDAP tree.\n" +
+ "If not specified, then the user being authenticated will be used as
the bind user.\n" +
+ "For example: CN=bindUser,CN=Users,DC=subdomain,DC=domain,DC=com"),
+
HIVE_SERVER2_PLAIN_LDAP_BIND_PASSWORD("hive.server2.authentication.ldap.bindpw",
null,
+ "The password for the bind user, to be used to search for the full
name of the user being authenticated.\n" +
+ "If the username is specified, this parameter must also be
specified."),
HIVE_SERVER2_CUSTOM_AUTHENTICATION_CLASS("hive.server2.custom.authentication.class",
null,
"Custom authentication class. Used when property\n" +
"'hive.server2.authentication' is set to 'CUSTOM'. Provided class\n" +
diff --git a/service/pom.xml b/service/pom.xml
index eca6f3b..30b7398 100644
--- a/service/pom.xml
+++ b/service/pom.xml
@@ -36,6 +36,17 @@
<!-- intra-project -->
<dependency>
<groupId>org.apache.hive</groupId>
+ <artifactId>hive-common</artifactId>
+ <version>${project.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.eclipse.jetty.aggregate</groupId>
+ <artifactId>jetty-all</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>${project.version}</version>
</dependency>
diff --git
a/service/src/java/org/apache/hive/service/auth/LdapAuthenticationProviderImpl.java
b/service/src/java/org/apache/hive/service/auth/LdapAuthenticationProviderImpl.java
index 73bbb6b..0120513 100644
---
a/service/src/java/org/apache/hive/service/auth/LdapAuthenticationProviderImpl.java
+++
b/service/src/java/org/apache/hive/service/auth/LdapAuthenticationProviderImpl.java
@@ -18,9 +18,10 @@
package org.apache.hive.service.auth;
import javax.security.sasl.AuthenticationException;
-
+import javax.naming.NamingException;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
+import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.lang.StringUtils;
@@ -68,9 +69,36 @@ public class LdapAuthenticationProviderImpl implements
PasswdAuthenticationProvi
@Override
public void Authenticate(String user, String password) throws
AuthenticationException {
DirSearch search = null;
+ String bindUser =
this.conf.getVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_BIND_USER);
+ String bindPassword = null;
+ try {
+ char[] rawPassword =
this.conf.getPassword(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_BIND_PASSWORD.toString());
+ if (rawPassword != null) {
+ bindPassword = new String(rawPassword);
+ }
+ } catch (IOException e) {
+ bindPassword = null;
+ }
+ boolean usedBind = bindUser != null && bindPassword != null;
+ if (!usedBind) {
+ // If no bind user or bind password was specified,
+ // we assume the user we are authenticating has the ability to search
+ // the LDAP tree, so we use it as the "binding" account.
+ // This is the way it worked before bind users were allowed in the LDAP
authenticator,
+ // so we keep existing systems working.
+ bindUser = user;
+ bindPassword = password;
+ }
try {
- search = createDirSearch(user, password);
+ search = createDirSearch(bindUser, bindPassword);
applyFilter(search, user);
+ if (usedBind) {
+ // If we used the bind user, then we need to authenticate again,
+ // this time using the full user name we got during the bind process.
+ createDirSearch(search.findUserDn(user), password);
+ }
+ } catch (NamingException e) {
+ throw new AuthenticationException("Unable to find the user in the LDAP
tree. " + e.getMessage());
} finally {
ServiceUtils.cleanup(LOG, search);
}
diff --git
a/service/src/test/org/apache/hive/service/auth/TestLdapAuthenticationProviderImpl.java
b/service/src/test/org/apache/hive/service/auth/TestLdapAuthenticationProviderImpl.java
index 43453fa..0396b74 100644
---
a/service/src/test/org/apache/hive/service/auth/TestLdapAuthenticationProviderImpl.java
+++
b/service/src/test/org/apache/hive/service/auth/TestLdapAuthenticationProviderImpl.java
@@ -22,6 +22,7 @@ import java.util.Arrays;
import javax.naming.NamingException;
import javax.security.sasl.AuthenticationException;
import org.apache.hadoop.hive.conf.HiveConf;
+import org.apache.hadoop.security.alias.CredentialProviderFactory;
import org.apache.hive.service.auth.ldap.DirSearch;
import org.apache.hive.service.auth.ldap.DirSearchFactory;
import org.apache.hive.service.auth.ldap.LdapSearchFactory;
@@ -324,6 +325,118 @@ public class TestLdapAuthenticationProviderImpl {
verify(search, atLeastOnce()).close();
}
+ @Test
+ public void testAuthenticateWithBindInCredentialFilePasses() throws
AuthenticationException, NamingException {
+ String bindUser = "cn=BindUser,ou=Users,ou=branch1,dc=mycorp,dc=com";
+ String bindPass = "testPassword";
+ String authFullUser = "cn=user1,ou=Users,ou=branch1,dc=mycorp,dc=com";
+ String authUser = "user1";
+ String authPass = "Blah";
+ String tmpDir = System.getProperty("build.dir");
+ String credentialsPath = "jceks://file" + tmpDir +
"/test-classes/creds/test.jceks";
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_BIND_USER, bindUser);
+ conf.set(CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH,
credentialsPath);
+
+ System.out.println(tmpDir);
+
+ when(search.findUserDn(eq(authUser))).thenReturn(authFullUser);
+
+ auth = new LdapAuthenticationProviderImpl(conf, factory);
+ auth.Authenticate(authUser, authPass);
+
+ verify(factory, times(1)).getInstance(isA(HiveConf.class), eq(bindUser),
eq(bindPass));
+ verify(factory, times(1)).getInstance(isA(HiveConf.class),
eq(authFullUser), eq(authPass));
+ verify(search, times(1)).findUserDn(eq(authUser));
+ }
+
+ @Test
+ public void testAuthenticateWithBindInMissingCredentialFilePasses() throws
AuthenticationException, NamingException {
+ String bindUser = "cn=BindUser,ou=Users,ou=branch1,dc=mycorp,dc=com";
+ String authUser = "user1";
+ String authPass = "Blah";
+ String tmpDir = System.getProperty("build.dir");
+ String credentialsPath = "jceks://file" + tmpDir +
"/test-classes/creds/nonExistent.jceks";
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_BIND_USER, bindUser);
+ conf.set(CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH,
credentialsPath);
+
+ auth = new LdapAuthenticationProviderImpl(conf, factory);
+ auth.Authenticate(authUser, authPass);
+
+ verify(factory, times(1)).getInstance(isA(HiveConf.class), eq(authUser),
eq(authPass));
+ }
+
+ @Test
+ public void testAuthenticateWithBindUserPasses() throws
AuthenticationException, NamingException {
+ String bindUser = "cn=BindUser,ou=Users,ou=branch1,dc=mycorp,dc=com";
+ String bindPass = "Blah";
+ String authFullUser = "cn=user1,ou=Users,ou=branch1,dc=mycorp,dc=com";
+ String authUser = "user1";
+ String authPass = "Blah2";
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_BIND_USER, bindUser);
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_BIND_PASSWORD,
bindPass);
+
+ when(search.findUserDn(eq(authUser))).thenReturn(authFullUser);
+
+ auth = new LdapAuthenticationProviderImpl(conf, factory);
+ auth.Authenticate(authUser, authPass);
+
+ verify(factory, times(1)).getInstance(isA(HiveConf.class), eq(bindUser),
eq(bindPass));
+ verify(factory, times(1)).getInstance(isA(HiveConf.class),
eq(authFullUser), eq(authPass));
+ verify(search, times(1)).findUserDn(eq(authUser));
+ }
+
+ @Test
+ public void testAuthenticateWithBindUserFailsOnAuthentication() throws
AuthenticationException, NamingException {
+ String bindUser = "cn=BindUser,ou=Users,ou=branch1,dc=mycorp,dc=com";
+ String bindPass = "Blah";
+ String authFullUser = "cn=user1,ou=Users,ou=branch1,dc=mycorp,dc=com";
+ String authUser = "user1";
+ String authPass = "Blah2";
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_BIND_USER, bindUser);
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_BIND_PASSWORD,
bindPass);
+
+ thrown.expect(AuthenticationException.class);
+ when(factory.getInstance(any(HiveConf.class), eq(authFullUser),
eq(authPass))).
+ thenThrow(AuthenticationException.class);
+ when(search.findUserDn(eq(authUser))).thenReturn(authFullUser);
+
+ auth = new LdapAuthenticationProviderImpl(conf, factory);
+ auth.Authenticate(authUser, authPass);
+ }
+
+ @Test
+ public void testAuthenticateWithBindUserFailsOnGettingDn() throws
AuthenticationException, NamingException {
+ String bindUser = "cn=BindUser,ou=Users,ou=branch1,dc=mycorp,dc=com";
+ String bindPass = "Blah";
+ String authFullUser = "cn=user1,ou=Users,ou=branch1,dc=mycorp,dc=com";
+ String authUser = "user1";
+ String authPass = "Blah2";
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_BIND_USER, bindUser);
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_BIND_PASSWORD,
bindPass);
+
+ thrown.expect(AuthenticationException.class);
+ when(search.findUserDn(eq(authUser))).thenThrow(NamingException.class);
+
+ auth = new LdapAuthenticationProviderImpl(conf, factory);
+ auth.Authenticate(authUser, authPass);
+ }
+
+ @Test
+ public void testAuthenticateWithBindUserFailsOnBinding() throws
AuthenticationException {
+ String bindUser = "cn=BindUser,ou=Users,ou=branch1,dc=mycorp,dc=com";
+ String bindPass = "Blah";
+ String authUser = "user1";
+ String authPass = "Blah2";
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_BIND_USER, bindUser);
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_BIND_PASSWORD,
bindPass);
+
+ thrown.expect(AuthenticationException.class);
+ when(factory.getInstance(any(HiveConf.class), eq(bindUser),
eq(bindPass))).thenThrow(AuthenticationException.class);
+
+ auth = new LdapAuthenticationProviderImpl(conf, factory);
+ auth.Authenticate(authUser, authPass);
+ }
+
private void expectAuthenticationExceptionForInvalidPassword() {
thrown.expect(AuthenticationException.class);
thrown.expectMessage("a null or blank password has been provided");