hive-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ser...@apache.org
Subject [19/44] hive git commit: HIVE-14713: LDAP Authentication Provider should be covered with unit tests (Illya Yalovyy, reviewed by Chaoyu Tang, Szehon Ho)
Date Sat, 01 Oct 2016 01:09:01 GMT
http://git-wip-us.apache.org/repos/asf/hive/blob/990927e3/service/src/java/org/apache/hive/service/auth/ldap/UserSearchFilterFactory.java
----------------------------------------------------------------------
diff --git a/service/src/java/org/apache/hive/service/auth/ldap/UserSearchFilterFactory.java b/service/src/java/org/apache/hive/service/auth/ldap/UserSearchFilterFactory.java
new file mode 100644
index 0000000..3218875
--- /dev/null
+++ b/service/src/java/org/apache/hive/service/auth/ldap/UserSearchFilterFactory.java
@@ -0,0 +1,65 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hive.service.auth.ldap;
+
+import java.util.Collection;
+import javax.naming.NamingException;
+import javax.security.sasl.AuthenticationException;
+import org.apache.hadoop.hive.conf.HiveConf;
+
+/**
+ * A factory for a {@link Filter} that check whether provided user could be found in the directory.
+ * <br>
+ * The produced filter object filters out all users that are not found in the directory.
+ */
+public final class UserSearchFilterFactory implements FilterFactory {
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Filter getInstance(HiveConf conf) {
+    Collection<String> groupFilter = conf.getStringCollection(
+        HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPFILTER.varname);
+    Collection<String> userFilter = conf.getStringCollection(
+        HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERFILTER.varname);
+
+    if (groupFilter.isEmpty() && userFilter.isEmpty()) {
+      return null;
+    }
+
+    return new UserSearchFilter();
+  }
+
+  private static final class UserSearchFilter implements Filter {
+    @Override
+    public void apply(DirSearch client, String user) throws AuthenticationException {
+      try {
+        String userDn = client.findUserDn(user);
+
+        // This should not be null because we were allowed to bind with this username
+        // safe check in case we were able to bind anonymously.
+        if (userDn == null) {
+          throw new AuthenticationException("Authentication failed: User search failed");
+        }
+      } catch (NamingException e) {
+        throw new AuthenticationException("LDAP Authentication failed for user", e);
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/hive/blob/990927e3/service/src/test/org/apache/hive/service/auth/TestLdapAtnProviderWithMiniDS.java
----------------------------------------------------------------------
diff --git a/service/src/test/org/apache/hive/service/auth/TestLdapAtnProviderWithMiniDS.java b/service/src/test/org/apache/hive/service/auth/TestLdapAtnProviderWithMiniDS.java
index 089a059..23a048a 100644
--- a/service/src/test/org/apache/hive/service/auth/TestLdapAtnProviderWithMiniDS.java
+++ b/service/src/test/org/apache/hive/service/auth/TestLdapAtnProviderWithMiniDS.java
@@ -225,7 +225,6 @@ public class TestLdapAtnProviderWithMiniDS extends AbstractLdapTestUnit {
     hiveConf = new HiveConf();
 
     ldapProvider = new LdapAuthenticationProviderImpl(hiveConf);
-    ldapProvider.init(hiveConf);
   }
 
   @AfterClass
@@ -259,7 +258,7 @@ public class TestLdapAtnProviderWithMiniDS extends AbstractLdapTestUnit {
       }
     }
 
-    ldapProvider.init(hiveConf);
+    ldapProvider = new LdapAuthenticationProviderImpl(hiveConf);
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/hive/blob/990927e3/service/src/test/org/apache/hive/service/auth/TestLdapAuthenticationProviderImpl.java
----------------------------------------------------------------------
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 f276906..4fad755 100644
--- a/service/src/test/org/apache/hive/service/auth/TestLdapAuthenticationProviderImpl.java
+++ b/service/src/test/org/apache/hive/service/auth/TestLdapAuthenticationProviderImpl.java
@@ -15,51 +15,260 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.hive.service.auth;
 
+import java.io.IOException;
+import java.util.Arrays;
+import javax.naming.NamingException;
 import javax.security.sasl.AuthenticationException;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-
-import junit.framework.TestCase;
 import org.apache.hadoop.hive.conf.HiveConf;
+import org.apache.hive.service.auth.ldap.DirSearch;
+import org.apache.hive.service.auth.ldap.DirSearchFactory;
+import org.apache.hive.service.auth.ldap.LdapSearchFactory;
+import org.junit.Test;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class TestLdapAuthenticationProviderImpl {
+
+  @Rule
+  public ExpectedException thrown = ExpectedException.none();
 
-public class TestLdapAuthenticationProviderImpl extends TestCase {
+  public HiveConf conf;
+  public LdapAuthenticationProviderImpl auth;
 
-  private static HiveConf hiveConf;
-  private static byte[] hiveConfBackup;
+  @Mock
+  public DirSearchFactory factory;
 
-  @Override
-  public void setUp() throws Exception {
-      hiveConf = new HiveConf();
-      ByteArrayOutputStream baos = new ByteArrayOutputStream();
-      hiveConf.writeXml(baos);
-      baos.close();
-      hiveConfBackup = baos.toByteArray();
-      hiveConf.set("hive.server2.authentication.ldap.url", "localhost");
-      FileOutputStream fos = new FileOutputStream(new File(hiveConf.getHiveSiteLocation().toURI()));
-      hiveConf.writeXml(fos);
-      fos.close();
+  @Mock
+  public DirSearch search;
+
+  @Before
+  public void setup() throws AuthenticationException {
+    conf = new HiveConf();
+    conf.set("hive.root.logger", "DEBUG,console");
+    conf.set("hive.server2.authentication.ldap.url", "localhost");
+    when(factory.getInstance(any(HiveConf.class), anyString(), anyString())).thenReturn(search);
   }
 
-  public void testLdapEmptyPassword() {
-    LdapAuthenticationProviderImpl ldapImpl = new LdapAuthenticationProviderImpl(hiveConf);
-    try {
-      ldapImpl.Authenticate("user", "");
-      assertFalse(true);
-    } catch (AuthenticationException e) {
-      assertTrue(e.getMessage(), e.getMessage().contains("a null or blank password has been provided"));
-    }
+  @Test
+  public void authenticateGivenBlankPassword() throws Exception {
+    auth = new LdapAuthenticationProviderImpl(conf, new LdapSearchFactory());
+    expectAuthenticationExceptionForInvalidPassword();
+    auth.Authenticate("user", "");
+  }
+
+  @Test
+  public void authenticateGivenStringWithNullCharacterForPassword() throws Exception {
+    auth = new LdapAuthenticationProviderImpl(conf, new LdapSearchFactory());
+    expectAuthenticationExceptionForInvalidPassword();
+    auth.Authenticate("user", "\0");
+  }
+
+  @Test
+  public void authenticateGivenNullForPassword() throws Exception {
+    auth = new LdapAuthenticationProviderImpl(conf, new LdapSearchFactory());
+    expectAuthenticationExceptionForInvalidPassword();
+    auth.Authenticate("user", null);
+  }
+
+  @Test
+  public void testAuthenticateNoUserOrGroupFilter() throws NamingException, AuthenticationException, IOException {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERDNPATTERN,
+        "cn=%s,ou=Users,dc=mycorp,dc=com:cn=%s,ou=PowerUsers,dc=mycorp,dc=com");
+
+    DirSearchFactory factory = mock(DirSearchFactory.class);
+
+    when(search.findUserDn("user1")).thenReturn("cn=user1,ou=PowerUsers,dc=mycorp,dc=com");
+
+    when(factory.getInstance(conf, "cn=user1,ou=PowerUsers,dc=mycorp,dc=com", "Blah")).thenReturn(search);
+    when(factory.getInstance(conf, "cn=user1,ou=Users,dc=mycorp,dc=com", "Blah")).thenThrow(AuthenticationException.class);
+
+    auth = new LdapAuthenticationProviderImpl(conf, factory);
+    auth.Authenticate("user1", "Blah");
+
+    verify(factory, times(2)).getInstance(isA(HiveConf.class), anyString(), eq("Blah"));
+    verify(search, atLeastOnce()).close();
   }
 
-  @Override
-  public void tearDown() throws Exception {
-    if(hiveConf != null && hiveConfBackup != null) {
-      FileOutputStream fos = new FileOutputStream(new File(hiveConf.getHiveSiteLocation().toURI()));
-      fos.write(hiveConfBackup);
-      fos.close();
+  @Test
+  public void testAuthenticateWhenUserFilterPasses() throws NamingException, AuthenticationException, IOException {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERFILTER,
+        "user1,user2");
+
+    when(search.findUserDn("user1")).thenReturn("cn=user1,ou=PowerUsers,dc=mycorp,dc=com");
+    when(search.findUserDn("user2")).thenReturn("cn=user2,ou=PowerUsers,dc=mycorp,dc=com");
+
+    authenticateUserAndCheckSearchIsClosed("user1");
+    authenticateUserAndCheckSearchIsClosed("user2");
+  }
+
+  @Test
+  public void testAuthenticateWhenLoginWithDomainAndUserFilterPasses() throws NamingException, AuthenticationException, IOException {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERFILTER,
+        "user1");
+
+    when(search.findUserDn("user1")).thenReturn("cn=user1,ou=PowerUsers,dc=mycorp,dc=com");
+
+    authenticateUserAndCheckSearchIsClosed("user1@mydomain.com");
+  }
+
+  @Test
+  public void testAuthenticateWhenLoginWithDnAndUserFilterPasses() throws NamingException, AuthenticationException, IOException {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERFILTER,
+        "user1");
+
+    when(search.findUserDn("cn=user1,ou=PowerUsers,dc=mycorp,dc=com")).thenReturn("cn=user1,ou=PowerUsers,dc=mycorp,dc=com");
+
+    authenticateUserAndCheckSearchIsClosed("cn=user1,ou=PowerUsers,dc=mycorp,dc=com");
+  }
+
+  @Test
+  public void testAuthenticateWhenUserSearchFails() throws NamingException, AuthenticationException, IOException {
+    thrown.expect(AuthenticationException.class);
+
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERFILTER, "user1,user2");
+
+    when(search.findUserDn("user1")).thenReturn(null);
+
+    authenticateUserAndCheckSearchIsClosed("user1");
+  }
+
+  @Test
+  public void testAuthenticateWhenUserFilterFails() throws NamingException, AuthenticationException, IOException {
+    thrown.expect(AuthenticationException.class);
+
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERFILTER, "user1,user2");
+
+    when(search.findUserDn("user3")).thenReturn("cn=user3,ou=PowerUsers,dc=mycorp,dc=com");
+
+    authenticateUserAndCheckSearchIsClosed("user3");
+  }
+
+  @Test
+  public void testAuthenticateWhenGroupFilterPasses() throws NamingException, AuthenticationException, IOException {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPFILTER, "group1,group2");
+
+    when(search.findUserDn("user1")).thenReturn("cn=user1,ou=PowerUsers,dc=mycorp,dc=com");
+    when(search.findUserDn("user2")).thenReturn("cn=user2,ou=PowerUsers,dc=mycorp,dc=com");
+
+    when(search.findGroupsForUser("cn=user1,ou=PowerUsers,dc=mycorp,dc=com"))
+        .thenReturn(Arrays.asList(
+            "cn=testGroup,ou=Groups,dc=mycorp,dc=com",
+            "cn=group1,ou=Groups,dc=mycorp,dc=com"));
+    when(search.findGroupsForUser("cn=user2,ou=PowerUsers,dc=mycorp,dc=com"))
+        .thenReturn(Arrays.asList(
+            "cn=testGroup,ou=Groups,dc=mycorp,dc=com",
+            "cn=group2,ou=Groups,dc=mycorp,dc=com"));
+
+    authenticateUserAndCheckSearchIsClosed("user1");
+    authenticateUserAndCheckSearchIsClosed("user2");
+  }
+
+  @Test
+  public void testAuthenticateWhenUserAndGroupFiltersPass() throws NamingException, AuthenticationException, IOException {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPFILTER, "group1,group2");
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERFILTER, "user1,user2");
+
+    when(search.findUserDn("user1")).thenReturn("cn=user1,ou=PowerUsers,dc=mycorp,dc=com");
+    when(search.findUserDn("user2")).thenReturn("cn=user2,ou=PowerUsers,dc=mycorp,dc=com");
+
+    when(search.findGroupsForUser("cn=user1,ou=PowerUsers,dc=mycorp,dc=com"))
+        .thenReturn(Arrays.asList(
+            "cn=testGroup,ou=Groups,dc=mycorp,dc=com",
+            "cn=group1,ou=Groups,dc=mycorp,dc=com"));
+    when(search.findGroupsForUser("cn=user2,ou=PowerUsers,dc=mycorp,dc=com"))
+        .thenReturn(Arrays.asList(
+            "cn=testGroup,ou=Groups,dc=mycorp,dc=com",
+            "cn=group2,ou=Groups,dc=mycorp,dc=com"));
+
+    authenticateUserAndCheckSearchIsClosed("user1");
+    authenticateUserAndCheckSearchIsClosed("user2");
+  }
+
+  @Test
+  public void testAuthenticateWhenUserFilterPassesAndGroupFilterFails()
+      throws NamingException, AuthenticationException, IOException {
+    thrown.expect(AuthenticationException.class);
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPFILTER, "group1,group2");
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERFILTER, "user1,user2");
+
+    when(search.findUserDn("user1")).thenReturn("cn=user1,ou=PowerUsers,dc=mycorp,dc=com");
+
+    when(search.findGroupsForUser("cn=user1,ou=PowerUsers,dc=mycorp,dc=com"))
+        .thenReturn(Arrays.asList(
+            "cn=testGroup,ou=Groups,dc=mycorp,dc=com",
+            "cn=OtherGroup,ou=Groups,dc=mycorp,dc=com"));
+
+    authenticateUserAndCheckSearchIsClosed("user1");
+  }
+
+  @Test
+  public void testAuthenticateWhenUserFilterFailsAndGroupFilterPasses()
+      throws NamingException, AuthenticationException, IOException {
+    thrown.expect(AuthenticationException.class);
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPFILTER, "group3");
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERFILTER, "user1,user2");
+
+    when(search.findUserDn("user3")).thenReturn("cn=user3,ou=PowerUsers,dc=mycorp,dc=com");
+
+    when(search.findGroupsForUser("cn=user3,ou=PowerUsers,dc=mycorp,dc=com"))
+        .thenReturn(Arrays.asList(
+            "cn=testGroup,ou=Groups,dc=mycorp,dc=com",
+            "cn=group3,ou=Groups,dc=mycorp,dc=com"));
+
+    authenticateUserAndCheckSearchIsClosed("user3");
+  }
+
+  @Test
+  public void testAuthenticateWhenCustomQueryFilterPasses() throws NamingException, AuthenticationException, IOException {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_BASEDN, "dc=mycorp,dc=com");
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_CUSTOMLDAPQUERY,
+        "(&(objectClass=person)(|(memberOf=CN=Domain Admins,CN=Users,DC=apache,DC=org)(memberOf=CN=Administrators,CN=Builtin,DC=apache,DC=org)))");
+
+    when(search.executeCustomQuery(anyString())).thenReturn(Arrays.asList(
+        "cn=user1,ou=PowerUsers,dc=mycorp,dc=com",
+        "cn=user2,ou=PowerUsers,dc=mycorp,dc=com"));
+
+    authenticateUserAndCheckSearchIsClosed("user1");
+  }
+
+  @Test
+  public void testAuthenticateWhenCustomQueryFilterFailsAndUserFilterPasses() throws NamingException, AuthenticationException, IOException {
+    thrown.expect(AuthenticationException.class);
+
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_BASEDN, "dc=mycorp,dc=com");
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_CUSTOMLDAPQUERY,
+        "(&(objectClass=person)(|(memberOf=CN=Domain Admins,CN=Users,DC=apache,DC=org)(memberOf=CN=Administrators,CN=Builtin,DC=apache,DC=org)))");
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERFILTER, "user3");
+
+    when(search.findUserDn("user3")).thenReturn("cn=user3,ou=PowerUsers,dc=mycorp,dc=com");
+    when(search.executeCustomQuery(anyString())).thenReturn(Arrays.asList(
+        "cn=user1,ou=PowerUsers,dc=mycorp,dc=com",
+        "cn=user2,ou=PowerUsers,dc=mycorp,dc=com"));
+
+    authenticateUserAndCheckSearchIsClosed("user3");
+  }
+
+  private void expectAuthenticationExceptionForInvalidPassword() {
+    thrown.expect(AuthenticationException.class);
+    thrown.expectMessage("a null or blank password has been provided");
+  }
+
+  private void authenticateUserAndCheckSearchIsClosed(String user) throws IOException {
+    auth = new LdapAuthenticationProviderImpl(conf, factory);
+    try {
+      auth.Authenticate(user, "password doesn't matter");
+    } finally {
+      verify(search, atLeastOnce()).close();
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/hive/blob/990927e3/service/src/test/org/apache/hive/service/auth/ldap/Credentials.java
----------------------------------------------------------------------
diff --git a/service/src/test/org/apache/hive/service/auth/ldap/Credentials.java b/service/src/test/org/apache/hive/service/auth/ldap/Credentials.java
new file mode 100644
index 0000000..ce22b8e
--- /dev/null
+++ b/service/src/test/org/apache/hive/service/auth/ldap/Credentials.java
@@ -0,0 +1,41 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hive.service.auth.ldap;
+
+public final class Credentials {
+
+  private final String user;
+  private final String password;
+
+  private Credentials(String user, String password) {
+    this.user = user;
+    this.password = password;
+  }
+
+  public static Credentials of(String user, String password) {
+    return new Credentials(user, password);
+  }
+
+  public String getUser() {
+    return user;
+  }
+
+  public String getPassword() {
+    return password;
+  }
+}

http://git-wip-us.apache.org/repos/asf/hive/blob/990927e3/service/src/test/org/apache/hive/service/auth/ldap/LdapTestUtils.java
----------------------------------------------------------------------
diff --git a/service/src/test/org/apache/hive/service/auth/ldap/LdapTestUtils.java b/service/src/test/org/apache/hive/service/auth/ldap/LdapTestUtils.java
new file mode 100644
index 0000000..d4e034f
--- /dev/null
+++ b/service/src/test/org/apache/hive/service/auth/ldap/LdapTestUtils.java
@@ -0,0 +1,126 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hive.service.auth.ldap;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.directory.SearchResult;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import org.mockito.stubbing.OngoingStubbing;
+
+public final class LdapTestUtils {
+
+  private LdapTestUtils() {
+  }
+
+  public static NamingEnumeration<SearchResult> mockEmptyNamingEnumeration() throws NamingException {
+    return mockNamingEnumeration(new SearchResult[0]);
+  }
+
+  public static NamingEnumeration<SearchResult> mockNamingEnumeration(String... dns) throws NamingException {
+    return mockNamingEnumeration(mockSearchResults(dns).toArray(new SearchResult[0]));
+  }
+
+  public static NamingEnumeration<SearchResult> mockNamingEnumeration(SearchResult... searchResults) throws NamingException {
+    NamingEnumeration<SearchResult> ne =
+        (NamingEnumeration<SearchResult>) mock(NamingEnumeration.class);
+    mockHasMoreMethod(ne, searchResults.length);
+    if (searchResults.length > 0) {
+      List<SearchResult> mockedResults = Arrays.asList(searchResults);
+      mockNextMethod(ne, mockedResults);
+    }
+    return ne;
+  }
+
+  public static void mockHasMoreMethod(NamingEnumeration<SearchResult> ne, int length) throws NamingException {
+    OngoingStubbing<Boolean> hasMoreStub = when(ne.hasMore());
+    for (int i = 0; i < length; i++) {
+      hasMoreStub = hasMoreStub.thenReturn(true);
+    }
+    hasMoreStub.thenReturn(false);
+  }
+
+  public static void mockNextMethod(NamingEnumeration<SearchResult> ne, List<SearchResult> searchResults) throws NamingException {
+    OngoingStubbing<SearchResult> nextStub = when(ne.next());
+    for (SearchResult searchResult : searchResults) {
+      nextStub = nextStub.thenReturn(searchResult);
+    }
+  }
+
+  public static List<SearchResult> mockSearchResults(String[] dns) {
+    List<SearchResult> list = new ArrayList<>();
+    for (String dn : dns) {
+      list.add(mockSearchResult(dn, null));
+    }
+    return list;
+  }
+
+  public static SearchResult mockSearchResult(String dn, Attributes attributes) {
+    SearchResult searchResult = mock(SearchResult.class);
+    when(searchResult.getNameInNamespace()).thenReturn(dn);
+    when(searchResult.getAttributes()).thenReturn(attributes);
+    return searchResult;
+  }
+
+  public static Attributes mockEmptyAttributes() throws NamingException {
+    return mockAttributes();
+  }
+
+  public static Attributes mockAttributes(String name, String value) throws NamingException {
+    return mockAttributes(new NameValues(name, value));
+  }
+
+  public static Attributes mockAttributes(String name1, String value1, String name2, String value2) throws NamingException {
+    if (name1.equals(name2)) {
+      return mockAttributes(new NameValues(name1, value1, value2));
+    } else {
+      return mockAttributes(new NameValues(name1, value1), new NameValues(name2, value2));
+    }
+  }
+
+  private static Attributes mockAttributes(NameValues... namedValues) throws NamingException {
+    Attributes attributes =  new BasicAttributes();
+    for (NameValues namedValue : namedValues) {
+      Attribute attr = new BasicAttribute(namedValue.name);
+      for (String value : namedValue.values) {
+        attr.add(value);
+      }
+      attributes.put(attr);
+    }
+    return attributes;
+  }
+
+  private static final class NameValues {
+    final String name;
+    final String[] values;
+
+    public NameValues(String name, String... values) {
+      this.name = name;
+      this.values = values;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/hive/blob/990927e3/service/src/test/org/apache/hive/service/auth/ldap/TestChainFilter.java
----------------------------------------------------------------------
diff --git a/service/src/test/org/apache/hive/service/auth/ldap/TestChainFilter.java b/service/src/test/org/apache/hive/service/auth/ldap/TestChainFilter.java
new file mode 100644
index 0000000..9caa233
--- /dev/null
+++ b/service/src/test/org/apache/hive/service/auth/ldap/TestChainFilter.java
@@ -0,0 +1,103 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hive.service.auth.ldap;
+
+import java.io.IOException;
+import javax.naming.NamingException;
+import javax.security.sasl.AuthenticationException;
+import org.apache.hadoop.hive.conf.HiveConf;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import org.junit.Before;
+import org.mockito.Mock;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class TestChainFilter {
+
+  private FilterFactory factory;
+  private HiveConf conf;
+
+  @Mock
+  public Filter filter1;
+
+  @Mock
+  public Filter filter2;
+
+  @Mock
+  public Filter filter3;
+
+  @Mock
+  public FilterFactory factory1;
+
+  @Mock
+  public FilterFactory factory2;
+
+  @Mock
+  public FilterFactory factory3;
+
+  @Mock
+  private DirSearch search;
+
+  @Before
+  public void setup() {
+    conf = new HiveConf();
+    factory = new ChainFilterFactory(factory1, factory2, factory3);
+  }
+
+  @Test
+  public void testFactoryAllNull() {
+    assertNull(factory.getInstance(conf));
+  }
+
+  @Test
+  public void testFactoryAllEmpty() {
+    FilterFactory emptyFactory = new ChainFilterFactory();
+    assertNull(emptyFactory.getInstance(conf));
+  }
+
+  @Test
+  public void testFactory() throws AuthenticationException {
+    when(factory1.getInstance(any(HiveConf.class))).thenReturn(filter1);
+    when(factory2.getInstance(any(HiveConf.class))).thenReturn(filter2);
+    when(factory3.getInstance(any(HiveConf.class))).thenReturn(filter3);
+
+    Filter filter = factory.getInstance(conf);
+
+    filter.apply(search, "User");
+    verify(filter1, times(1)).apply(search, "User");
+    verify(filter2, times(1)).apply(search, "User");
+    verify(filter3, times(1)).apply(search, "User");
+  }
+
+  @Test(expected = AuthenticationException.class)
+  public void testApplyNegative() throws AuthenticationException, NamingException, IOException {
+    doThrow(AuthenticationException.class).when(filter3).apply((DirSearch) anyObject(), anyString());
+
+    when(factory1.getInstance(any(HiveConf.class))).thenReturn(filter1);
+    when(factory3.getInstance(any(HiveConf.class))).thenReturn(filter3);
+
+    Filter filter = factory.getInstance(conf);
+
+    filter.apply(search, "User");
+  }
+}

http://git-wip-us.apache.org/repos/asf/hive/blob/990927e3/service/src/test/org/apache/hive/service/auth/ldap/TestCustomQueryFilter.java
----------------------------------------------------------------------
diff --git a/service/src/test/org/apache/hive/service/auth/ldap/TestCustomQueryFilter.java b/service/src/test/org/apache/hive/service/auth/ldap/TestCustomQueryFilter.java
new file mode 100644
index 0000000..fd4b898
--- /dev/null
+++ b/service/src/test/org/apache/hive/service/auth/ldap/TestCustomQueryFilter.java
@@ -0,0 +1,85 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hive.service.auth.ldap;
+
+import java.io.IOException;
+import java.util.Arrays;
+import javax.naming.NamingException;
+import javax.security.sasl.AuthenticationException;
+import org.apache.hadoop.hive.conf.HiveConf;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import org.junit.Before;
+import org.mockito.Mock;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class TestCustomQueryFilter {
+
+  private static final String USER2_DN = "uid=user2,ou=People,dc=example,dc=com";
+  private static final String USER1_DN = "uid=user1,ou=People,dc=example,dc=com";
+  private static final String CUSTOM_QUERY = "(&(objectClass=person)(|(uid=user1)(uid=user2)))";
+
+  private FilterFactory factory;
+  private HiveConf conf;
+
+  @Mock
+  private DirSearch search;
+
+  @Before
+  public void setup() {
+    conf = new HiveConf();
+    conf.set("hive.root.logger", "DEBUG,console");
+    factory = new CustomQueryFilterFactory();
+  }
+
+  @Test
+  public void testFactory() {
+    conf.unset(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_CUSTOMLDAPQUERY.varname);
+    assertNull(factory.getInstance(conf));
+
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_CUSTOMLDAPQUERY, CUSTOM_QUERY);
+    assertNotNull(factory.getInstance(conf));
+  }
+
+  @Test
+  public void testApplyPositive() throws AuthenticationException, NamingException, IOException {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_CUSTOMLDAPQUERY, CUSTOM_QUERY);
+
+    when(search.executeCustomQuery(eq(CUSTOM_QUERY))).thenReturn(Arrays.asList(USER1_DN, USER2_DN));
+
+    Filter filter = factory.getInstance(conf);
+    filter.apply(search, "user1");
+    filter.apply(search, "user2");
+  }
+
+
+  @Test(expected = AuthenticationException.class)
+  public void testApplyNegative() throws AuthenticationException, NamingException, IOException {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_CUSTOMLDAPQUERY, CUSTOM_QUERY);
+
+    when(search.executeCustomQuery(eq(CUSTOM_QUERY))).thenReturn(Arrays.asList(USER1_DN, USER2_DN));
+
+    Filter filter = factory.getInstance(conf);
+    filter.apply(search, "user3");
+  }
+}

http://git-wip-us.apache.org/repos/asf/hive/blob/990927e3/service/src/test/org/apache/hive/service/auth/ldap/TestGroupFilter.java
----------------------------------------------------------------------
diff --git a/service/src/test/org/apache/hive/service/auth/ldap/TestGroupFilter.java b/service/src/test/org/apache/hive/service/auth/ldap/TestGroupFilter.java
new file mode 100644
index 0000000..0cc2ead
--- /dev/null
+++ b/service/src/test/org/apache/hive/service/auth/ldap/TestGroupFilter.java
@@ -0,0 +1,101 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hive.service.auth.ldap;
+
+import java.io.IOException;
+import java.util.Arrays;
+import javax.naming.NamingException;
+import javax.security.sasl.AuthenticationException;
+import org.apache.hadoop.hive.conf.HiveConf;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import org.junit.Before;
+import org.mockito.Mock;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class TestGroupFilter {
+
+  private FilterFactory factory;
+  private HiveConf conf;
+
+  @Mock
+  private DirSearch search;
+
+  @Before
+  public void setup() {
+    conf = new HiveConf();
+    conf.set("hive.root.logger", "DEBUG,console");
+    factory = new GroupFilterFactory();
+  }
+
+  @Test
+  public void testFactory() {
+    conf.unset(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPFILTER.varname);
+    assertNull(factory.getInstance(conf));
+
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPFILTER, "G1");
+    assertNotNull(factory.getInstance(conf));
+  }
+
+  @Test
+  public void testApplyPositive() throws AuthenticationException, NamingException, IOException {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPFILTER, "HiveUsers");
+
+    when(search.findUserDn(eq("user1")))
+        .thenReturn("cn=user1,ou=People,dc=example,dc=com");
+    when(search.findUserDn(eq("cn=user2,dc=example,dc=com")))
+        .thenReturn("cn=user2,ou=People,dc=example,dc=com");
+    when(search.findUserDn(eq("user3@mydomain.com")))
+        .thenReturn("cn=user3,ou=People,dc=example,dc=com");
+
+    when(search.findGroupsForUser(eq("cn=user1,ou=People,dc=example,dc=com")))
+        .thenReturn(Arrays.asList(
+            "cn=SuperUsers,ou=Groups,dc=example,dc=com",
+            "cn=Office1,ou=Groups,dc=example,dc=com",
+            "cn=HiveUsers,ou=Groups,dc=example,dc=com",
+            "cn=G1,ou=Groups,dc=example,dc=com"));
+    when(search.findGroupsForUser(eq("cn=user2,ou=People,dc=example,dc=com")))
+        .thenReturn(Arrays.asList(
+            "cn=HiveUsers,ou=Groups,dc=example,dc=com"));
+    when(search.findGroupsForUser(eq("cn=user3,ou=People,dc=example,dc=com")))
+        .thenReturn(Arrays.asList(
+            "cn=HiveUsers,ou=Groups,dc=example,dc=com",
+            "cn=G1,ou=Groups,dc=example,dc=com",
+            "cn=G2,ou=Groups,dc=example,dc=com"));
+
+    Filter filter = factory.getInstance(conf);
+    filter.apply(search, "user1");
+    filter.apply(search, "cn=user2,dc=example,dc=com");
+    filter.apply(search, "user3@mydomain.com");
+  }
+
+  @Test(expected = AuthenticationException.class)
+  public void testApplyNegative() throws AuthenticationException, NamingException, IOException {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPFILTER, "HiveUsers");
+
+    when(search.findGroupsForUser(eq("user1"))).thenReturn(Arrays.asList("SuperUsers", "Office1", "G1", "G2"));
+
+    Filter filter = factory.getInstance(conf);
+    filter.apply(search, "user1");
+  }
+}

http://git-wip-us.apache.org/repos/asf/hive/blob/990927e3/service/src/test/org/apache/hive/service/auth/ldap/TestLdapSearch.java
----------------------------------------------------------------------
diff --git a/service/src/test/org/apache/hive/service/auth/ldap/TestLdapSearch.java b/service/src/test/org/apache/hive/service/auth/ldap/TestLdapSearch.java
new file mode 100644
index 0000000..499b624
--- /dev/null
+++ b/service/src/test/org/apache/hive/service/auth/ldap/TestLdapSearch.java
@@ -0,0 +1,209 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hive.service.auth.ldap;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import org.apache.hadoop.hive.conf.HiveConf;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+import static org.apache.hive.service.auth.ldap.LdapTestUtils.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class TestLdapSearch {
+
+  @Mock
+  private DirContext ctx;
+
+  private HiveConf conf;
+  private LdapSearch search;
+
+  @Before
+  public void setup() {
+    conf = new HiveConf();
+  }
+
+  @Test
+  public void testClose() throws NamingException {
+    search = new LdapSearch(conf, ctx);
+    search.close();
+    verify(ctx, atLeastOnce()).close();
+  }
+
+  @Test
+  public void testFindUserDnWhenUserDnPositive() throws NamingException {
+    NamingEnumeration<SearchResult> searchResult = mockNamingEnumeration("CN=User1,OU=org1,DC=foo,DC=bar");
+    when(ctx.search(anyString(), anyString(), any(SearchControls.class)))
+        .thenReturn(searchResult)
+        .thenThrow(NamingException.class);
+    search = new LdapSearch(conf, ctx);
+    String expected = "CN=User1,OU=org1,DC=foo,DC=bar";
+    String actual = search.findUserDn("CN=User1,OU=org1");
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testFindUserDnWhenUserDnNegativeDuplicates() throws NamingException {
+    NamingEnumeration<SearchResult> searchResult = mockNamingEnumeration(
+            "CN=User1,OU=org1,DC=foo,DC=bar",
+            "CN=User1,OU=org2,DC=foo,DC=bar");
+    when(ctx.search(anyString(), anyString(), any(SearchControls.class))).thenReturn(searchResult);
+    search = new LdapSearch(conf, ctx);
+    assertNull(search.findUserDn("CN=User1,DC=foo,DC=bar"));
+  }
+
+  @Test
+  public void testFindUserDnWhenUserDnNegativeNone() throws NamingException {
+    NamingEnumeration<SearchResult> searchResult = mockEmptyNamingEnumeration();
+    when(ctx.search(anyString(), anyString(), any(SearchControls.class))).thenReturn(searchResult);
+    search = new LdapSearch(conf, ctx);
+    assertNull(search.findUserDn("CN=User1,DC=foo,DC=bar"));
+  }
+
+  @Test
+  public void testFindUserDnWhenUserPatternFoundBySecondPattern() throws NamingException {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERDNPATTERN,
+        "CN=%s,OU=org1,DC=foo,DC=bar:CN=%s,OU=org2,DC=foo,DC=bar");
+    NamingEnumeration<SearchResult> emptyResult = mockEmptyNamingEnumeration();
+    NamingEnumeration<SearchResult> validResult = mockNamingEnumeration("CN=User1,OU=org2,DC=foo,DC=bar");
+    when(ctx.search(anyString(), anyString(), any(SearchControls.class)))
+        .thenReturn(emptyResult)
+        .thenReturn(validResult);
+    search = new LdapSearch(conf, ctx);
+    String expected = "CN=User1,OU=org2,DC=foo,DC=bar";
+    String actual = search.findUserDn("User1");
+    assertEquals(expected, actual);
+    verify(ctx).search(eq("OU=org1,DC=foo,DC=bar"), contains("CN=User1"), any(SearchControls.class));
+    verify(ctx).search(eq("OU=org2,DC=foo,DC=bar"), contains("CN=User1"), any(SearchControls.class));
+  }
+
+  @Test
+  public void testFindUserDnWhenUserPatternFoundByFirstPattern() throws NamingException {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERDNPATTERN,
+        "CN=%s,OU=org1,DC=foo,DC=bar:CN=%s,OU=org2,DC=foo,DC=bar");
+    NamingEnumeration<SearchResult> emptyResult = mockEmptyNamingEnumeration();
+    NamingEnumeration<SearchResult> validResult = mockNamingEnumeration("CN=User1,OU=org2,DC=foo,DC=bar");
+    when(ctx.search(anyString(), anyString(), any(SearchControls.class)))
+        .thenReturn(validResult)
+        .thenReturn(emptyResult);
+    search = new LdapSearch(conf, ctx);
+    String expected = "CN=User1,OU=org2,DC=foo,DC=bar";
+    String actual = search.findUserDn("User1");
+    assertEquals(expected, actual);
+    verify(ctx).search(eq("OU=org1,DC=foo,DC=bar"), contains("CN=User1"), any(SearchControls.class));
+  }
+
+  @Test
+  public void testFindUserDnWhenUserPatternFoundByUniqueIdentifier() throws NamingException {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERDNPATTERN,
+        "CN=%s,OU=org1,DC=foo,DC=bar");
+    NamingEnumeration<SearchResult> validResult = mockNamingEnumeration("CN=User1,OU=org1,DC=foo,DC=bar");
+    when(ctx.search(anyString(), anyString(), any(SearchControls.class)))
+        .thenReturn(null)
+        .thenReturn(validResult);
+    search = new LdapSearch(conf, ctx);
+    String expected = "CN=User1,OU=org1,DC=foo,DC=bar";
+    String actual = search.findUserDn("User1");
+    assertEquals(expected, actual);
+    verify(ctx).search(eq("OU=org1,DC=foo,DC=bar"), contains("CN=User1"), any(SearchControls.class));
+    verify(ctx).search(eq("OU=org1,DC=foo,DC=bar"), contains("uid=User1"), any(SearchControls.class));
+  }
+
+  @Test
+  public void testFindUserDnWhenUserPatternFoundByUniqueIdentifierNegativeNone() throws NamingException {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERDNPATTERN,
+        "CN=%s,OU=org1,DC=foo,DC=bar");
+    when(ctx.search(anyString(), anyString(), any(SearchControls.class)))
+        .thenReturn(null)
+        .thenReturn(null);
+    search = new LdapSearch(conf, ctx);
+    assertNull(search.findUserDn("User1"));
+  }
+
+  @Test
+  public void testFindUserDnWhenUserPatternFoundByUniqueIdentifierNegativeMany() throws NamingException {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERDNPATTERN,
+        "CN=%s,OU=org1,DC=foo,DC=bar");
+    NamingEnumeration<SearchResult> manyResult = mockNamingEnumeration(
+        "CN=User1,OU=org1,DC=foo,DC=bar",
+        "CN=User12,OU=org1,DC=foo,DC=bar");
+    when(ctx.search(anyString(), anyString(), any(SearchControls.class)))
+        .thenReturn(null)
+        .thenReturn(manyResult);
+    search = new LdapSearch(conf, ctx);
+    assertNull(search.findUserDn("User1"));
+  }
+
+  @Test
+  public void testFindGroupsForUser() throws NamingException {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPDNPATTERN,
+        "CN=%s,OU=org1,DC=foo,DC=bar");
+
+    NamingEnumeration<SearchResult> groupsResult = mockNamingEnumeration("CN=Group1,OU=org1,DC=foo,DC=bar");
+    when(ctx.search(eq("OU=org1,DC=foo,DC=bar"), contains("User1"), any(SearchControls.class)))
+        .thenReturn(groupsResult);
+
+    search = new LdapSearch(conf, ctx);
+
+    List<String> expected = Arrays.asList("CN=Group1,OU=org1,DC=foo,DC=bar");
+    List<String> actual = search.findGroupsForUser("CN=User1,OU=org1,DC=foo,DC=bar");
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testExecuteCustomQuery() throws NamingException {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_BASEDN, "dc=example,dc=com");
+
+    NamingEnumeration<SearchResult> customQueryResult = mockNamingEnumeration(
+        mockSearchResult(
+            "uid=group1,ou=Groups,dc=example,dc=com",
+            mockAttributes("member", "uid=user1,ou=People,dc=example,dc=com")),
+        mockSearchResult(
+            "uid=group2,ou=Groups,dc=example,dc=com",
+            mockAttributes("member", "uid=user2,ou=People,dc=example,dc=com"))
+        );
+
+    when(ctx.search(eq("dc=example,dc=com"), anyString(), any(SearchControls.class)))
+        .thenReturn(customQueryResult);
+
+    search = new LdapSearch(conf, ctx);
+
+    List<String> expected = Arrays.asList(
+        "uid=group1,ou=Groups,dc=example,dc=com",
+        "uid=user1,ou=People,dc=example,dc=com",
+        "uid=group2,ou=Groups,dc=example,dc=com",
+        "uid=user2,ou=People,dc=example,dc=com");
+    List<String> actual = search.executeCustomQuery("(&(objectClass=groupOfNames)(|(cn=group1)(cn=group2)))");
+    Collections.sort(expected);
+    Collections.sort(actual);
+    assertEquals(expected, actual);
+  }
+}

http://git-wip-us.apache.org/repos/asf/hive/blob/990927e3/service/src/test/org/apache/hive/service/auth/ldap/TestLdapUtils.java
----------------------------------------------------------------------
diff --git a/service/src/test/org/apache/hive/service/auth/ldap/TestLdapUtils.java b/service/src/test/org/apache/hive/service/auth/ldap/TestLdapUtils.java
new file mode 100644
index 0000000..661aff4
--- /dev/null
+++ b/service/src/test/org/apache/hive/service/auth/ldap/TestLdapUtils.java
@@ -0,0 +1,103 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hive.service.auth.ldap;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.apache.hadoop.hive.conf.HiveConf;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class TestLdapUtils {
+
+  @Test
+  public void testCreateCandidatePrincipalsForUserDn() {
+    HiveConf conf = new HiveConf();
+    String userDn = "cn=user1,ou=CORP,dc=mycompany,dc=com";
+    List<String> expected = Arrays.asList(userDn);
+    List<String> actual = LdapUtils.createCandidatePrincipals(conf, userDn);
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testCreateCandidatePrincipalsForUserWithDomain() {
+    HiveConf conf = new HiveConf();
+    String userWithDomain = "user1@mycompany.com";
+    List<String> expected = Arrays.asList(userWithDomain);
+    List<String> actual = LdapUtils.createCandidatePrincipals(conf, userWithDomain);
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testCreateCandidatePrincipalsLdapDomain() {
+    HiveConf conf = new HiveConf();
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_DOMAIN, "mycompany.com");
+    List<String> expected = Arrays.asList("user1@mycompany.com");
+    List<String> actual = LdapUtils.createCandidatePrincipals(conf, "user1");
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testCreateCandidatePrincipalsUserPatternsDefaultBaseDn() {
+    HiveConf conf = new HiveConf();
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GUIDKEY, "sAMAccountName");
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_BASEDN, "dc=mycompany,dc=com");
+    List<String> expected = Arrays.asList("sAMAccountName=user1,dc=mycompany,dc=com");
+    List<String> actual = LdapUtils.createCandidatePrincipals(conf, "user1");
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testCreateCandidatePrincipals() {
+    HiveConf conf = new HiveConf();
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_BASEDN, "dc=mycompany,dc=com");
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERDNPATTERN,
+        "cn=%s,ou=CORP1,dc=mycompany,dc=com:cn=%s,ou=CORP2,dc=mycompany,dc=com");
+    List<String> expected = Arrays.asList(
+        "cn=user1,ou=CORP1,dc=mycompany,dc=com",
+        "cn=user1,ou=CORP2,dc=mycompany,dc=com");
+    List<String> actual = LdapUtils.createCandidatePrincipals(conf, "user1");
+    Collections.sort(expected);
+    Collections.sort(actual);
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testExtractFirstRdn() {
+    String dn = "cn=user1,ou=CORP1,dc=mycompany,dc=com";
+    String expected = "cn=user1";
+    String actual = LdapUtils.extractFirstRdn(dn);
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testExtractBaseDn() {
+    String dn = "cn=user1,ou=CORP1,dc=mycompany,dc=com";
+    String expected = "ou=CORP1,dc=mycompany,dc=com";
+    String actual = LdapUtils.extractBaseDn(dn);
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testExtractBaseDnNegative() {
+    String dn = "cn=user1";
+    assertNull(LdapUtils.extractBaseDn(dn));
+  }
+}

http://git-wip-us.apache.org/repos/asf/hive/blob/990927e3/service/src/test/org/apache/hive/service/auth/ldap/TestQuery.java
----------------------------------------------------------------------
diff --git a/service/src/test/org/apache/hive/service/auth/ldap/TestQuery.java b/service/src/test/org/apache/hive/service/auth/ldap/TestQuery.java
new file mode 100644
index 0000000..1f4bb1a
--- /dev/null
+++ b/service/src/test/org/apache/hive/service/auth/ldap/TestQuery.java
@@ -0,0 +1,59 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hive.service.auth.ldap;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class TestQuery {
+
+  @Test
+  public void testQueryBuilderFilter() {
+    Query q = Query.builder()
+        .filter("test <uid_attr>=<value> query")
+        .map("uid_attr", "uid")
+        .map("value", "Hello!")
+        .build();
+    assertEquals("test uid=Hello! query", q.getFilter());
+    assertEquals(0, q.getControls().getCountLimit());
+  }
+
+  @Test
+  public void testQueryBuilderLimit() {
+    Query q = Query.builder()
+        .filter("<key1>,<key2>")
+        .map("key1", "value1")
+        .map("key2", "value2")
+        .limit(8)
+        .build();
+    assertEquals("value1,value2", q.getFilter());
+    assertEquals(8, q.getControls().getCountLimit());
+  }
+
+  @Test
+  public void testQueryBuilderReturningAttributes() {
+    Query q = Query.builder()
+        .filter("(query)")
+        .returnAttribute("attr1")
+        .returnAttribute("attr2")
+        .build();
+    assertEquals("(query)", q.getFilter());
+    assertArrayEquals(new String[] {"attr1", "attr2"}, q.getControls().getReturningAttributes());
+  }
+}

http://git-wip-us.apache.org/repos/asf/hive/blob/990927e3/service/src/test/org/apache/hive/service/auth/ldap/TestQueryFactory.java
----------------------------------------------------------------------
diff --git a/service/src/test/org/apache/hive/service/auth/ldap/TestQueryFactory.java b/service/src/test/org/apache/hive/service/auth/ldap/TestQueryFactory.java
new file mode 100644
index 0000000..3054e33
--- /dev/null
+++ b/service/src/test/org/apache/hive/service/auth/ldap/TestQueryFactory.java
@@ -0,0 +1,79 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hive.service.auth.ldap;
+
+import org.apache.hadoop.hive.conf.HiveConf;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class TestQueryFactory {
+
+  private QueryFactory queries;
+  private HiveConf conf;
+
+  @Before
+  public void setup() {
+    conf = new HiveConf();
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GUIDKEY, "guid");
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPCLASS_KEY, "superGroups");
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPMEMBERSHIP_KEY, "member");
+    queries = new QueryFactory(conf);
+  }
+
+  @Test
+  public void testFindGroupDnById() {
+    Query q = queries.findGroupDnById("unique_group_id");
+    String expected = "(&(objectClass=superGroups)(guid=unique_group_id))";
+    String actual = q.getFilter();
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testFindUserDnByRdn() {
+    Query q = queries.findUserDnByRdn("cn=User1");
+    String expected = "(&(|(objectClass=person)(objectClass=user)(objectClass=inetOrgPerson))(cn=User1))";
+    String actual = q.getFilter();
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testFindDnByPattern() {
+    Query q = queries.findDnByPattern("cn=User1");
+    String expected = "(cn=User1)";
+    String actual = q.getFilter();
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testFindUserDnByName() {
+    Query q = queries.findUserDnByName("unique_user_id");
+    String expected = "(&(|(objectClass=person)(objectClass=user)(objectClass=inetOrgPerson))(|(uid=unique_user_id)(sAMAccountName=unique_user_id)))";
+    String actual = q.getFilter();
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testFindGroupsForUser() {
+    Query q = queries.findGroupsForUser("user_name", "user_Dn");
+    String expected = "(&(objectClass=superGroups)(|(member=user_Dn)(member=user_name)))";
+    String actual = q.getFilter();
+    assertEquals(expected, actual);
+  }
+}

http://git-wip-us.apache.org/repos/asf/hive/blob/990927e3/service/src/test/org/apache/hive/service/auth/ldap/TestSearchResultHandler.java
----------------------------------------------------------------------
diff --git a/service/src/test/org/apache/hive/service/auth/ldap/TestSearchResultHandler.java b/service/src/test/org/apache/hive/service/auth/ldap/TestSearchResultHandler.java
new file mode 100644
index 0000000..2615680
--- /dev/null
+++ b/service/src/test/org/apache/hive/service/auth/ldap/TestSearchResultHandler.java
@@ -0,0 +1,222 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hive.service.auth.ldap;
+
+import java.util.AbstractCollection;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.SearchResult;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+import static org.apache.hive.service.auth.ldap.LdapTestUtils.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class TestSearchResultHandler {
+
+  SearchResultHandler handler;
+
+  @Test
+  public void testHandle() throws NamingException {
+    MockResultCollection resultCollection = MockResultCollection.create()
+        .addSearchResultWithDns("1")
+        .addSearchResultWithDns("2", "3");
+    handler = new SearchResultHandler(resultCollection);
+    List<String> expected = Arrays.asList("1", "2");
+    final List<String> actual = new ArrayList<>();
+    handler.handle(new SearchResultHandler.RecordProcessor() {
+      @Override
+      public boolean process(SearchResult record) throws NamingException {
+        actual.add(record.getNameInNamespace());
+        return actual.size() < 2;
+      }
+    });
+    assertEquals(expected, actual);
+    assertAllNamingEnumerationsClosed(resultCollection);
+  }
+
+  @Test
+  public void testGetAllLdapNamesNoRecords() throws NamingException {
+    MockResultCollection resultCollection = MockResultCollection.create()
+        .addEmptySearchResult();
+    handler = new SearchResultHandler(resultCollection);
+    List<String> actual = handler.getAllLdapNames();
+    assertEquals("Resultset size", 0, actual.size());
+    assertAllNamingEnumerationsClosed(resultCollection);
+  }
+
+  @Test
+  public void testGetAllLdapNamesWithExceptionInNamingEnumerationClose() throws NamingException {
+    MockResultCollection resultCollection = MockResultCollection.create()
+        .addSearchResultWithDns("1")
+        .addSearchResultWithDns("2");
+    doThrow(NamingException.class).when(resultCollection.iterator().next()).close();
+    handler = new SearchResultHandler(resultCollection);
+    List<String> actual = handler.getAllLdapNames();
+    assertEquals("Resultset size", 2, actual.size());
+    assertAllNamingEnumerationsClosed(resultCollection);
+  }
+
+  @Test
+  public void testGetAllLdapNames() throws NamingException {
+    String objectDn1 = "cn=a1,dc=b,dc=c";
+    String objectDn2 = "cn=a2,dc=b,dc=c";
+    String objectDn3 = "cn=a3,dc=b,dc=c";
+    MockResultCollection resultCollection = MockResultCollection.create()
+        .addSearchResultWithDns(objectDn1)
+        .addSearchResultWithDns(objectDn2, objectDn3);
+    handler = new SearchResultHandler(resultCollection);
+    List<String> expected = Arrays.asList(objectDn1, objectDn2, objectDn3);
+    Collections.sort(expected);
+    List<String> actual = handler.getAllLdapNames();
+    Collections.sort(actual);
+    assertEquals(expected, actual);
+    assertAllNamingEnumerationsClosed(resultCollection);
+  }
+
+  @Test
+  public void testGetAllLdapNamesAndAttributes() throws NamingException {
+    SearchResult searchResult1 = mockSearchResult("cn=a1,dc=b,dc=c",
+        mockAttributes("attr1", "attr1value1"));
+    SearchResult searchResult2 = mockSearchResult("cn=a2,dc=b,dc=c",
+        mockAttributes("attr1", "attr1value2", "attr2", "attr2value1"));
+    SearchResult searchResult3 = mockSearchResult("cn=a3,dc=b,dc=c",
+        mockAttributes("attr1", "attr1value3", "attr1", "attr1value4"));
+    SearchResult searchResult4 = mockSearchResult("cn=a4,dc=b,dc=c",
+        mockEmptyAttributes());
+
+    MockResultCollection resultCollection = MockResultCollection.create()
+        .addSearchResults(searchResult1)
+        .addSearchResults(searchResult2, searchResult3)
+        .addSearchResults(searchResult4);
+
+    handler = new SearchResultHandler(resultCollection);
+    List<String> expected = Arrays.asList(
+        "cn=a1,dc=b,dc=c", "attr1value1",
+        "cn=a2,dc=b,dc=c", "attr1value2", "attr2value1",
+        "cn=a3,dc=b,dc=c", "attr1value3", "attr1value4",
+        "cn=a4,dc=b,dc=c");
+    Collections.sort(expected);
+    List<String> actual = handler.getAllLdapNamesAndAttributes();
+    Collections.sort(actual);
+    assertEquals(expected, actual);
+    assertAllNamingEnumerationsClosed(resultCollection);
+  }
+
+  @Test
+  public void testHasSingleResultNoRecords() throws NamingException {
+    MockResultCollection resultCollection = MockResultCollection.create()
+        .addEmptySearchResult();
+    handler = new SearchResultHandler(resultCollection);
+    assertFalse(handler.hasSingleResult());
+    assertAllNamingEnumerationsClosed(resultCollection);
+  }
+
+  @Test
+  public void testHasSingleResult() throws NamingException {
+    MockResultCollection resultCollection = MockResultCollection.create()
+        .addSearchResultWithDns("1");
+    handler = new SearchResultHandler(resultCollection);
+    assertTrue(handler.hasSingleResult());
+    assertAllNamingEnumerationsClosed(resultCollection);
+  }
+
+  @Test
+  public void testHasSingleResultManyRecords() throws NamingException {
+    MockResultCollection resultCollection = MockResultCollection.create()
+        .addSearchResultWithDns("1")
+        .addSearchResultWithDns("2");
+    handler = new SearchResultHandler(resultCollection);
+    assertFalse(handler.hasSingleResult());
+    assertAllNamingEnumerationsClosed(resultCollection);
+  }
+
+  @Test(expected = NamingException.class)
+  public void testGetSingleLdapNameNoRecords() throws NamingException {
+    MockResultCollection resultCollection = MockResultCollection.create()
+        .addEmptySearchResult();
+    handler = new SearchResultHandler(resultCollection);
+    try {
+      handler.getSingleLdapName();
+    } finally {
+      assertAllNamingEnumerationsClosed(resultCollection);
+    }
+  }
+
+  @Test
+  public void testGetSingleLdapName() throws NamingException {
+    String objectDn = "cn=a,dc=b,dc=c";
+    MockResultCollection resultCollection = MockResultCollection.create()
+        .addEmptySearchResult()
+        .addSearchResultWithDns(objectDn);
+
+    handler = new SearchResultHandler(resultCollection);
+    String expected = objectDn;
+    String actual = handler.getSingleLdapName();
+    assertEquals(expected, actual);
+    assertAllNamingEnumerationsClosed(resultCollection);
+  }
+
+  private void assertAllNamingEnumerationsClosed(MockResultCollection resultCollection) throws NamingException {
+    for (NamingEnumeration<SearchResult> namingEnumeration : resultCollection) {
+      verify(namingEnumeration, atLeastOnce()).close();
+    }
+  }
+
+  private static final class MockResultCollection extends AbstractCollection<NamingEnumeration<SearchResult>> {
+
+    List<NamingEnumeration<SearchResult>> results = new ArrayList<>();
+
+    static MockResultCollection create() {
+      return new MockResultCollection();
+    }
+
+    MockResultCollection addSearchResultWithDns(String... dns) throws NamingException {
+      results.add(mockNamingEnumeration(dns));
+      return this;
+    }
+
+    MockResultCollection addSearchResults(SearchResult... dns) throws NamingException {
+      results.add(mockNamingEnumeration(dns));
+      return this;
+    }
+
+    MockResultCollection addEmptySearchResult() throws NamingException {
+      addSearchResults();
+      return this;
+    }
+
+    @Override
+    public Iterator<NamingEnumeration<SearchResult>> iterator() {
+      return results.iterator();
+    }
+
+    @Override
+    public int size() {
+      return results.size();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/hive/blob/990927e3/service/src/test/org/apache/hive/service/auth/ldap/TestUserFilter.java
----------------------------------------------------------------------
diff --git a/service/src/test/org/apache/hive/service/auth/ldap/TestUserFilter.java b/service/src/test/org/apache/hive/service/auth/ldap/TestUserFilter.java
new file mode 100644
index 0000000..f941c9c
--- /dev/null
+++ b/service/src/test/org/apache/hive/service/auth/ldap/TestUserFilter.java
@@ -0,0 +1,75 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hive.service.auth.ldap;
+
+import java.io.IOException;
+import javax.naming.NamingException;
+import javax.security.sasl.AuthenticationException;
+import org.apache.hadoop.hive.conf.HiveConf;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import org.junit.Before;
+import org.mockito.Mock;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class TestUserFilter {
+
+  private FilterFactory factory;
+  private HiveConf conf;
+
+  @Mock
+  private DirSearch search;
+
+  @Before
+  public void setup() {
+    conf = new HiveConf();
+    factory = new UserFilterFactory();
+  }
+
+  @Test
+  public void testFactory() {
+    conf.unset(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERFILTER.varname);
+    assertNull(factory.getInstance(conf));
+
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERFILTER, "User1");
+    assertNotNull(factory.getInstance(conf));
+  }
+
+  @Test
+  public void testApplyPositive() throws AuthenticationException, NamingException, IOException {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERFILTER, "User1,User2,uSeR3");
+
+    Filter filter = factory.getInstance(conf);
+    filter.apply(search, "User1");
+    filter.apply(search, "uid=user2,ou=People,dc=example,dc=com");
+    filter.apply(search, "User3@mydomain.com");
+  }
+
+  @Test(expected = AuthenticationException.class)
+  public void testApplyNegative() throws AuthenticationException, NamingException, IOException {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERFILTER, "User1,User2");
+
+    Filter filter = factory.getInstance(conf);
+    filter.apply(search, "User3");
+  }
+}

http://git-wip-us.apache.org/repos/asf/hive/blob/990927e3/service/src/test/org/apache/hive/service/auth/ldap/TestUserSearchFilter.java
----------------------------------------------------------------------
diff --git a/service/src/test/org/apache/hive/service/auth/ldap/TestUserSearchFilter.java b/service/src/test/org/apache/hive/service/auth/ldap/TestUserSearchFilter.java
new file mode 100644
index 0000000..0f2b509
--- /dev/null
+++ b/service/src/test/org/apache/hive/service/auth/ldap/TestUserSearchFilter.java
@@ -0,0 +1,94 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hive.service.auth.ldap;
+
+import java.io.IOException;
+import javax.naming.NamingException;
+import javax.security.sasl.AuthenticationException;
+import org.apache.hadoop.hive.conf.HiveConf;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class TestUserSearchFilter {
+
+  private FilterFactory factory;
+  private HiveConf conf;
+
+  @Mock
+  private DirSearch search;
+
+  @Before
+  public void setup() {
+    conf = new HiveConf();
+    factory = new UserSearchFilterFactory();
+  }
+
+  @Test
+  public void testFactoryWhenNoGroupOrUserFilters() {
+    assertNull(factory.getInstance(conf));
+  }
+
+  @Test
+  public void testFactoryWhenGroupFilter() {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPFILTER, "Grp1,Grp2");
+    assertNotNull(factory.getInstance(conf));
+  }
+
+  @Test
+  public void testFactoryWhenUserFilter() {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERFILTER, "User1,User2");
+    assertNotNull(factory.getInstance(conf));
+  }
+
+  @Test
+  public void testApplyPositive() throws AuthenticationException, NamingException, IOException {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERFILTER, "User1");
+    Filter filter = factory.getInstance(conf);
+
+    when(search.findUserDn(anyString())).thenReturn("cn=User1,ou=People,dc=example,dc=com");
+
+    filter.apply(search, "User1");
+  }
+
+  @Test(expected = AuthenticationException.class)
+  public void testApplyWhenNamingException() throws AuthenticationException, NamingException, IOException {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERFILTER, "User1");
+    Filter filter = factory.getInstance(conf);
+
+    when(search.findUserDn(anyString())).thenThrow(NamingException.class);
+
+    filter.apply(search, "User3");
+  }
+
+  @Test(expected = AuthenticationException.class)
+  public void testApplyWhenNotFound() throws AuthenticationException, NamingException, IOException {
+    conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERFILTER, "User1");
+    Filter filter = factory.getInstance(conf);
+
+    when(search.findUserDn(anyString())).thenReturn(null);
+
+    filter.apply(search, "User3");
+  }
+}


Mime
View raw message