You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hive.apache.org by ai...@apache.org on 2017/01/09 20:39:32 UTC
hive git commit: HIVE-15076: Improve scalability of LDAP
authentication provider group filter (Illya Yalovyy, reviewed by Aihua Xu,
Naveen Gangam)
Repository: hive
Updated Branches:
refs/heads/master 6fdf49ac2 -> 01e691c5c
HIVE-15076: Improve scalability of LDAP authentication provider group filter (Illya Yalovyy, reviewed by Aihua Xu, Naveen Gangam)
Project: http://git-wip-us.apache.org/repos/asf/hive/repo
Commit: http://git-wip-us.apache.org/repos/asf/hive/commit/01e691c5
Tree: http://git-wip-us.apache.org/repos/asf/hive/tree/01e691c5
Diff: http://git-wip-us.apache.org/repos/asf/hive/diff/01e691c5
Branch: refs/heads/master
Commit: 01e691c5c545523f1ba88cafe68b2460ad0a4ab0
Parents: 6fdf49a
Author: Aihua Xu <ai...@apache.org>
Authored: Mon Jan 9 15:38:23 2017 -0500
Committer: Aihua Xu <ai...@apache.org>
Committed: Mon Jan 9 15:38:23 2017 -0500
----------------------------------------------------------------------
.../org/apache/hadoop/hive/conf/HiveConf.java | 11 +-
.../hive/service/auth/ldap/DirSearch.java | 17 +++
.../service/auth/ldap/GroupFilterFactory.java | 76 +++++++++-
.../hive/service/auth/ldap/LdapSearch.java | 17 +++
.../apache/hive/service/auth/ldap/Query.java | 11 ++
.../hive/service/auth/ldap/QueryFactory.java | 42 +++++-
.../auth/TestLdapAtnProviderWithMiniDS.java | 147 ++++++++++++++++++-
.../TestLdapAuthenticationProviderImpl.java | 74 +++++++++-
.../auth/ldap/LdapAuthenticationTestCase.java | 10 +-
.../hive/service/auth/ldap/TestGroupFilter.java | 68 ++++++++-
.../hive/service/auth/ldap/TestLdapSearch.java | 84 +++++++++++
.../service/auth/ldap/TestQueryFactory.java | 24 +++
.../src/test/resources/ldap/ad.example.com.ldif | 133 +++++++++++++++++
.../test/resources/ldap/microsoft.schema.ldif | 45 ++++++
14 files changed, 736 insertions(+), 23 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/hive/blob/01e691c5/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java
----------------------------------------------------------------------
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 47db0c0..16f6c1c 100644
--- a/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java
+++ b/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java
@@ -320,7 +320,8 @@ public class HiveConf extends Configuration {
}
public static final String HIVE_LLAP_DAEMON_SERVICE_PRINCIPAL_NAME = "hive.llap.daemon.service.principal";
-
+ public static final String HIVE_SERVER2_AUTHENTICATION_LDAP_USERMEMBERSHIPKEY_NAME =
+ "hive.server2.authentication.ldap.userMembershipKey";
/**
* dbVars are the parameters can be set per database. If these
@@ -2519,8 +2520,14 @@ public class HiveConf extends Configuration {
"LDAP attribute name whose values are unique in this LDAP server.\n" +
"For example: uid or CN."),
HIVE_SERVER2_PLAIN_LDAP_GROUPMEMBERSHIP_KEY("hive.server2.authentication.ldap.groupMembershipKey", "member",
- "LDAP attribute name on the user entry that references a group, the user belongs to.\n" +
+ "LDAP attribute name on the group object that contains the list of distinguished names\n" +
+ "for the user, group, and contact objects that are members of the group.\n" +
"For example: member, uniqueMember or memberUid"),
+ HIVE_SERVER2_PLAIN_LDAP_USERMEMBERSHIP_KEY(HIVE_SERVER2_AUTHENTICATION_LDAP_USERMEMBERSHIPKEY_NAME, null,
+ "LDAP attribute name on the user object that contains groups of which the user is\n" +
+ "a direct member, except for the primary group, which is represented by the\n" +
+ "primaryGroupId.\n" +
+ "For example: memberOf"),
HIVE_SERVER2_PLAIN_LDAP_GROUPCLASS_KEY("hive.server2.authentication.ldap.groupClassKey", "groupOfNames",
"LDAP attribute name on the group entry that is to be used in LDAP group searches.\n" +
"For example: group, groupOfNames or groupOfUniqueNames."),
http://git-wip-us.apache.org/repos/asf/hive/blob/01e691c5/service/src/java/org/apache/hive/service/auth/ldap/DirSearch.java
----------------------------------------------------------------------
diff --git a/service/src/java/org/apache/hive/service/auth/ldap/DirSearch.java b/service/src/java/org/apache/hive/service/auth/ldap/DirSearch.java
index 33b6088..f7020bc 100644
--- a/service/src/java/org/apache/hive/service/auth/ldap/DirSearch.java
+++ b/service/src/java/org/apache/hive/service/auth/ldap/DirSearch.java
@@ -35,6 +35,23 @@ public interface DirSearch extends Closeable {
String findUserDn(String user) throws NamingException;
/**
+ * Finds group's distinguished name.
+ * @param group group name or unique identifier
+ * @return DN for the specified group name
+ * @throws NamingException
+ */
+ String findGroupDn(String group) throws NamingException;
+
+ /**
+ * Verifies that specified user is a member of specified group.
+ * @param user user id or distinguished name
+ * @param groupDn group's DN
+ * @return {@code true} if the user is a member of the group, {@code false} - otherwise.
+ * @throws NamingException
+ */
+ boolean isUserMemberOfGroup(String user, String groupDn) throws NamingException;
+
+ /**
* Finds groups that contain the specified user.
* @param userDn user's distinguished name
* @return list of groups
http://git-wip-us.apache.org/repos/asf/hive/blob/01e691c5/service/src/java/org/apache/hive/service/auth/ldap/GroupFilterFactory.java
----------------------------------------------------------------------
diff --git a/service/src/java/org/apache/hive/service/auth/ldap/GroupFilterFactory.java b/service/src/java/org/apache/hive/service/auth/ldap/GroupFilterFactory.java
index 152c4b2..e0f4518 100644
--- a/service/src/java/org/apache/hive/service/auth/ldap/GroupFilterFactory.java
+++ b/service/src/java/org/apache/hive/service/auth/ldap/GroupFilterFactory.java
@@ -17,6 +17,9 @@
*/
package org.apache.hive.service.auth.ldap;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Joiner;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
@@ -48,22 +51,28 @@ public final class GroupFilterFactory implements FilterFactory {
return null;
}
- return new GroupFilter(groupFilter);
+ if (conf.getVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERMEMBERSHIP_KEY) == null) {
+ return new GroupMembershipKeyFilter(groupFilter);
+ } else {
+ return new UserMembershipKeyFilter(groupFilter);
+ }
}
- private static final class GroupFilter implements Filter {
+ @VisibleForTesting
+ static final class GroupMembershipKeyFilter implements Filter {
- private static final Logger LOG = LoggerFactory.getLogger(GroupFilter.class);
+ private static final Logger LOG = LoggerFactory.getLogger(GroupMembershipKeyFilter.class);
private final Set<String> groupFilter = new HashSet<>();
- GroupFilter(Collection<String> groupFilter) {
+ GroupMembershipKeyFilter(Collection<String> groupFilter) {
this.groupFilter.addAll(groupFilter);
}
@Override
public void apply(DirSearch ldap, String user) throws AuthenticationException {
- LOG.info("Authenticating user '{}' using group membership", user);
+ LOG.info("Authenticating user '{}' using {}", user,
+ GroupMembershipKeyFilter.class.getSimpleName());
List<String> memberOf = null;
@@ -78,6 +87,8 @@ public final class GroupFilterFactory implements FilterFactory {
for (String groupDn : memberOf) {
String shortName = LdapUtils.getShortName(groupDn);
if (groupFilter.contains(shortName)) {
+ LOG.debug("GroupMembershipKeyFilter passes: user '{}' is a member of '{}' group",
+ user, groupDn);
LOG.info("Authentication succeeded based on group membership");
return;
}
@@ -87,4 +98,59 @@ public final class GroupFilterFactory implements FilterFactory {
+ "User not a member of specified list");
}
}
+
+ @VisibleForTesting
+ static final class UserMembershipKeyFilter implements Filter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(UserMembershipKeyFilter.class);
+
+ private final Collection<String> groupFilter;
+
+ UserMembershipKeyFilter(Collection<String> groupFilter) {
+ this.groupFilter = groupFilter;
+ }
+
+ @Override
+ public void apply(DirSearch ldap, String user) throws AuthenticationException {
+ LOG.info("Authenticating user '{}' using {}", user,
+ UserMembershipKeyFilter.class.getSimpleName());
+
+ List<String> groupDns = new ArrayList<>();
+ for (String groupId : groupFilter) {
+ try {
+ String groupDn = ldap.findGroupDn(groupId);
+ groupDns.add(groupDn);
+ } catch (NamingException e) {
+ LOG.warn("Cannot find DN for group", e);
+ LOG.debug("Cannot find DN for group " + groupId, e);
+ }
+ }
+
+ if (groupDns.isEmpty()) {
+ String msg = String.format("No DN(s) has been found for any of group(s): %s",
+ Joiner.on(',').join(groupFilter));
+ LOG.debug(msg);
+ throw new AuthenticationException("No DN(s) has been found for any of specified group(s)");
+ }
+
+ for (String groupDn : groupDns) {
+ try {
+ if (ldap.isUserMemberOfGroup(user, groupDn)) {
+ LOG.debug("UserMembershipKeyFilter passes: user '{}' is a member of '{}' group",
+ user, groupDn);
+ LOG.info("Authentication succeeded based on user membership");
+ return;
+ }
+ } catch (NamingException e) {
+ LOG.warn("Cannot match user and group", e);
+ if (LOG.isDebugEnabled()) {
+ String msg = String.format("Cannot match user '%s' and group '%s'", user, groupDn);
+ LOG.debug(msg, e);
+ }
+ }
+ }
+ throw new AuthenticationException(String.format(
+ "Authentication failed: User '%s' is not a member of listed groups", user));
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/hive/blob/01e691c5/service/src/java/org/apache/hive/service/auth/ldap/LdapSearch.java
----------------------------------------------------------------------
diff --git a/service/src/java/org/apache/hive/service/auth/ldap/LdapSearch.java b/service/src/java/org/apache/hive/service/auth/ldap/LdapSearch.java
index 65076ea..be512c0 100644
--- a/service/src/java/org/apache/hive/service/auth/ldap/LdapSearch.java
+++ b/service/src/java/org/apache/hive/service/auth/ldap/LdapSearch.java
@@ -121,6 +121,23 @@ public final class LdapSearch implements DirSearch {
* {@inheritDoc}
*/
@Override
+ public String findGroupDn(String group) throws NamingException {
+ return execute(groupBases, queries.findGroupDnById(group)).getSingleLdapName();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isUserMemberOfGroup(String user, String groupDn) throws NamingException {
+ String userId = LdapUtils.extractUserName(user);
+ return execute(userBases, queries.isUserMemberOfGroup(userId, groupDn)).hasSingleResult();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
public List<String> findGroupsForUser(String userDn) throws NamingException {
String userName = LdapUtils.extractUserName(userDn);
return execute(groupBases, queries.findGroupsForUser(userName, userDn)).getAllLdapNames();
http://git-wip-us.apache.org/repos/asf/hive/blob/01e691c5/service/src/java/org/apache/hive/service/auth/ldap/Query.java
----------------------------------------------------------------------
diff --git a/service/src/java/org/apache/hive/service/auth/ldap/Query.java b/service/src/java/org/apache/hive/service/auth/ldap/Query.java
index b8bf938..194f8aa 100644
--- a/service/src/java/org/apache/hive/service/auth/ldap/Query.java
+++ b/service/src/java/org/apache/hive/service/auth/ldap/Query.java
@@ -103,6 +103,17 @@ public final class Query {
}
/**
+ * Sets mapping between names in the search filter template and actual values.
+ * @param key marker in the search filter template.
+ * @param values array of values
+ * @return the current instance of the builder
+ */
+ public QueryBuilder map(String key, String[] values) {
+ filterTemplate.add(key, values);
+ return this;
+ }
+
+ /**
* Sets attribute that should be returned in results for the query.
* @param attributeName attribute name
* @return the current instance of the builder
http://git-wip-us.apache.org/repos/asf/hive/blob/01e691c5/service/src/java/org/apache/hive/service/auth/ldap/QueryFactory.java
----------------------------------------------------------------------
diff --git a/service/src/java/org/apache/hive/service/auth/ldap/QueryFactory.java b/service/src/java/org/apache/hive/service/auth/ldap/QueryFactory.java
index e9172d3..6ce01c0 100644
--- a/service/src/java/org/apache/hive/service/auth/ldap/QueryFactory.java
+++ b/service/src/java/org/apache/hive/service/auth/ldap/QueryFactory.java
@@ -17,17 +17,21 @@
*/
package org.apache.hive.service.auth.ldap;
+import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import org.apache.hadoop.hive.conf.HiveConf;
/**
* A factory for common types of directory service search queries.
*/
-public final class QueryFactory {
+final class QueryFactory {
+
+ private static final String[] USER_OBJECT_CLASSES = {"person", "user", "inetOrgPerson"};
private final String guidAttr;
private final String groupClassAttr;
private final String groupMembershipAttr;
+ private final String userMembershipAttr;
/**
* Constructs the factory based on provided Hive configuration.
@@ -38,6 +42,8 @@ public final class QueryFactory {
groupClassAttr = conf.getVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPCLASS_KEY);
groupMembershipAttr = conf.getVar(
HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPMEMBERSHIP_KEY);
+ userMembershipAttr = conf.getVar(
+ HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERMEMBERSHIP_KEY);
}
/**
@@ -62,9 +68,10 @@ public final class QueryFactory {
*/
public Query findUserDnByRdn(String userRdn) {
return Query.builder()
- .filter("(&(|(objectClass=person)(objectClass=user)(objectClass=inetOrgPerson))"
+ .filter("(&(|<classes:{ class |(objectClass=<class>)}>)"
+ "(<userRdn>))")
.limit(2)
+ .map("classes", USER_OBJECT_CLASSES)
.map("userRdn", userRdn)
.build();
}
@@ -93,8 +100,9 @@ public final class QueryFactory {
*/
public Query findUserDnByName(String userName) {
return Query.builder()
- .filter("(&(|(objectClass=person)(objectClass=user)(objectClass=inetOrgPerson))"
+ .filter("(&(|<classes:{ class |(objectClass=<class>)}>)"
+ "(|(uid=<userName>)(sAMAccountName=<userName>)))")
+ .map("classes", USER_OBJECT_CLASSES)
.map("userName", userName)
.limit(2)
.build();
@@ -118,6 +126,34 @@ public final class QueryFactory {
}
/**
+ * Returns a query for checking whether specified user is a member of specified group.
+ *
+ * The query requires {@value HiveConf#HIVE_SERVER2_AUTHENTICATION_LDAP_USERMEMBERSHIPKEY_NAME}
+ * Hive configuration property to be set.
+ *
+ * @param userId user unique identifier
+ * @param groupDn group DN
+ * @return an instance of {@link Query}
+ * @see HiveConf.ConfVars#HIVE_SERVER2_PLAIN_LDAP_USERMEMBERSHIP_KEY
+ * @throws NullPointerException when
+ * {@value HiveConf#HIVE_SERVER2_AUTHENTICATION_LDAP_USERMEMBERSHIPKEY_NAME} is not set.
+ */
+ public Query isUserMemberOfGroup(String userId, String groupDn) {
+ Preconditions.checkState(!Strings.isNullOrEmpty(userMembershipAttr),
+ "hive.server2.authentication.ldap.userMembershipKey is not configured.");
+ return Query.builder()
+ .filter("(&(|<classes:{ class |(objectClass=<class>)}>)" +
+ "(<userMembershipAttr>=<groupDn>)(<guidAttr>=<userId>))")
+ .map("classes", USER_OBJECT_CLASSES)
+ .map("guidAttr", guidAttr)
+ .map("userMembershipAttr", userMembershipAttr)
+ .map("userId", userId)
+ .map("groupDn", groupDn)
+ .limit(2)
+ .build();
+ }
+
+ /**
* Returns a query object created for the custom filter.
* <br>
* This query is configured to return a group membership attribute as part of the search result.
http://git-wip-us.apache.org/repos/asf/hive/blob/01e691c5/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 cd62935..d6d67a5 100644
--- a/service/src/test/org/apache/hive/service/auth/TestLdapAtnProviderWithMiniDS.java
+++ b/service/src/test/org/apache/hive/service/auth/TestLdapAtnProviderWithMiniDS.java
@@ -67,7 +67,11 @@ import static org.junit.Assert.assertTrue;
)
})
-@ApplyLdifFiles("ldap/example.com.ldif")
+@ApplyLdifFiles({
+ "ldap/example.com.ldif",
+ "ldap/microsoft.schema.ldif",
+ "ldap/ad.example.com.ldif"
+})
public class TestLdapAtnProviderWithMiniDS extends AbstractLdapTestUnit {
private static final String GROUP1_NAME = "group1";
@@ -75,6 +79,12 @@ public class TestLdapAtnProviderWithMiniDS extends AbstractLdapTestUnit {
private static final String GROUP3_NAME = "group3";
private static final String GROUP4_NAME = "group4";
+ private static final String GROUP_ADMINS_NAME = "admins";
+ private static final String GROUP_TEAM1_NAME = "team1";
+ private static final String GROUP_TEAM2_NAME = "team2";
+ private static final String GROUP_RESOURCE1_NAME = "resource1";
+ private static final String GROUP_RESOURCE2_NAME = "resource2";
+
private static final User USER1 = User.builder()
.id("user1")
.useIdForPassword()
@@ -99,6 +109,36 @@ public class TestLdapAtnProviderWithMiniDS extends AbstractLdapTestUnit {
.dn("cn=user4,ou=People,dc=example,dc=com")
.build();
+ private static final User ENGINEER_1 = User.builder()
+ .id("engineer1")
+ .dn("sAMAccountName=engineer1,ou=Engineering,dc=ad,dc=example,dc=com")
+ .password("engineer1-password")
+ .build();
+
+ private static final User ENGINEER_2 = User.builder()
+ .id("engineer2")
+ .dn("sAMAccountName=engineer2,ou=Engineering,dc=ad,dc=example,dc=com")
+ .password("engineer2-password")
+ .build();
+
+ private static final User MANAGER_1 = User.builder()
+ .id("manager1")
+ .dn("sAMAccountName=manager1,ou=Management,dc=ad,dc=example,dc=com")
+ .password("manager1-password")
+ .build();
+
+ private static final User MANAGER_2 = User.builder()
+ .id("manager2")
+ .dn("sAMAccountName=manager2,ou=Management,dc=ad,dc=example,dc=com")
+ .password("manager2-password")
+ .build();
+
+ private static final User ADMIN_1 = User.builder()
+ .id("admin1")
+ .dn("sAMAccountName=admin1,ou=Administration,dc=ad,dc=example,dc=com")
+ .password("admin1-password")
+ .build();
+
private LdapAuthenticationTestCase testCase;
private LdapAuthenticationTestCase.Builder defaultBuilder() {
@@ -481,7 +521,7 @@ public class TestLdapAtnProviderWithMiniDS extends AbstractLdapTestUnit {
.userDNPatterns(
"cn=%s,ou=People,dc=example,dc=com",
"uid=%s,ou=People,dc=example,dc=com")
- .groupMembership("uniqueMember")
+ .groupMembershipKey("uniqueMember")
.customQuery(
String.format("(&(objectClass=groupOfUniqueNames)(cn=%s))",
GROUP4_NAME))
@@ -528,11 +568,112 @@ public class TestLdapAtnProviderWithMiniDS extends AbstractLdapTestUnit {
.groupDNPatterns("cn=%s,ou=Groups,dc=example,dc=com")
.groupFilters(GROUP4_NAME)
.guidKey("cn")
- .groupMembership("uniqueMember")
+ .groupMembershipKey("uniqueMember")
.groupClassKey("groupOfUniqueNames")
.build();
testCase.assertAuthenticatePasses(USER4.credentialsWithId());
testCase.assertAuthenticatePasses(USER4.credentialsWithDn());
}
+
+ @Test
+ public void testDirectUserMembershipGroupFilterPositive() {
+ testCase = defaultBuilder()
+ .userDNPatterns(
+ "sAMAccountName=%s,ou=Engineering,dc=ad,dc=example,dc=com",
+ "sAMAccountName=%s,ou=Management,dc=ad,dc=example,dc=com")
+ .groupDNPatterns(
+ "sAMAccountName=%s,ou=Teams,dc=ad,dc=example,dc=com",
+ "sAMAccountName=%s,ou=Resources,dc=ad,dc=example,dc=com")
+ .groupFilters(
+ GROUP_TEAM1_NAME,
+ GROUP_TEAM2_NAME,
+ GROUP_RESOURCE1_NAME,
+ GROUP_RESOURCE2_NAME)
+ .guidKey("sAMAccountName")
+ .userMembershipKey("memberOf")
+ .build();
+
+ testCase.assertAuthenticatePasses(ENGINEER_1.credentialsWithId());
+ testCase.assertAuthenticatePasses(ENGINEER_2.credentialsWithId());
+ testCase.assertAuthenticatePasses(MANAGER_1.credentialsWithId());
+ testCase.assertAuthenticatePasses(MANAGER_2.credentialsWithId());
+ }
+
+ @Test
+ public void testDirectUserMembershipGroupFilterNegative() {
+ testCase = defaultBuilder()
+ .userDNPatterns(
+ "sAMAccountName=%s,ou=Engineering,dc=ad,dc=example,dc=com",
+ "sAMAccountName=%s,ou=Management,dc=ad,dc=example,dc=com")
+ .groupDNPatterns("cn=%s,ou=Teams,dc=ad,dc=example,dc=com")
+ .groupFilters(GROUP_TEAM1_NAME)
+ .guidKey("sAMAccountName")
+ .userMembershipKey("memberOf")
+ .build();
+
+ testCase.assertAuthenticateFails(ENGINEER_2.credentialsWithId());
+ testCase.assertAuthenticateFails(MANAGER_2.credentialsWithId());
+ }
+
+ @Test
+ public void testDirectUserMembershipGroupFilterNegativeWithoutUserBases() throws Exception {
+ testCase = defaultBuilder()
+ .groupDNPatterns("cn=%s,ou=Teams,dc=ad,dc=example,dc=com")
+ .groupFilters(GROUP_TEAM1_NAME)
+ .guidKey("sAMAccountName")
+ .userMembershipKey("memberOf")
+ .build();
+
+ testCase.assertAuthenticateFails(ENGINEER_1.credentialsWithId());
+ testCase.assertAuthenticateFails(ENGINEER_2.credentialsWithId());
+ testCase.assertAuthenticateFails(MANAGER_1.credentialsWithId());
+ testCase.assertAuthenticateFails(MANAGER_2.credentialsWithId());
+ }
+
+ @Test
+ public void testDirectUserMembershipGroupFilterWithDNCredentials() throws Exception {
+ testCase = defaultBuilder()
+ .userDNPatterns("sAMAccountName=%s,ou=Engineering,dc=ad,dc=example,dc=com")
+ .groupDNPatterns("cn=%s,ou=Teams,dc=ad,dc=example,dc=com")
+ .groupFilters(GROUP_TEAM1_NAME)
+ .guidKey("sAMAccountName")
+ .userMembershipKey("memberOf")
+ .build();
+
+ testCase.assertAuthenticatePasses(ENGINEER_1.credentialsWithDn());
+ testCase.assertAuthenticateFails(MANAGER_1.credentialsWithDn());
+ }
+
+ @Test
+ public void testDirectUserMembershipGroupFilterWithDifferentGroupClassKey() throws Exception {
+ testCase = defaultBuilder()
+ .userDNPatterns("sAMAccountName=%s,ou=Administration,dc=ad,dc=example,dc=com")
+ .groupDNPatterns("cn=%s,ou=Administration,dc=ad,dc=example,dc=com")
+ .groupFilters(GROUP_ADMINS_NAME)
+ .guidKey("sAMAccountName")
+ .userMembershipKey("memberOf")
+ .groupClassKey("groupOfUniqueNames")
+ .build();
+
+ testCase.assertAuthenticatePasses(ADMIN_1.credentialsWithId());
+ testCase.assertAuthenticateFails(ENGINEER_1.credentialsWithId());
+ testCase.assertAuthenticateFails(MANAGER_1.credentialsWithDn());
+ }
+
+ @Test
+ public void testDirectUserMembershipGroupFilterNegativeWithWrongGroupClassKey() throws Exception {
+ testCase = defaultBuilder()
+ .userDNPatterns("sAMAccountName=%s,ou=Administration,dc=ad,dc=example,dc=com")
+ .groupDNPatterns("cn=%s,ou=Administration,dc=ad,dc=example,dc=com")
+ .groupFilters(GROUP_ADMINS_NAME)
+ .guidKey("sAMAccountName")
+ .userMembershipKey("memberOf")
+ .groupClassKey("wrongClass")
+ .build();
+
+ testCase.assertAuthenticateFails(ADMIN_1.credentialsWithId());
+ testCase.assertAuthenticateFails(ENGINEER_1.credentialsWithId());
+ testCase.assertAuthenticateFails(MANAGER_1.credentialsWithDn());
+ }
}
http://git-wip-us.apache.org/repos/asf/hive/blob/01e691c5/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 4fad755..6fd218c 100644
--- a/service/src/test/org/apache/hive/service/auth/TestLdapAuthenticationProviderImpl.java
+++ b/service/src/test/org/apache/hive/service/auth/TestLdapAuthenticationProviderImpl.java
@@ -154,7 +154,7 @@ public class TestLdapAuthenticationProviderImpl {
}
@Test
- public void testAuthenticateWhenGroupFilterPasses() throws NamingException, AuthenticationException, IOException {
+ public void testAuthenticateWhenGroupMembershipKeyFilterPasses() 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");
@@ -174,7 +174,7 @@ public class TestLdapAuthenticationProviderImpl {
}
@Test
- public void testAuthenticateWhenUserAndGroupFiltersPass() throws NamingException, AuthenticationException, IOException {
+ public void testAuthenticateWhenUserAndGroupMembershipKeyFiltersPass() 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");
@@ -195,7 +195,7 @@ public class TestLdapAuthenticationProviderImpl {
}
@Test
- public void testAuthenticateWhenUserFilterPassesAndGroupFilterFails()
+ public void testAuthenticateWhenUserFilterPassesAndGroupMembershipKeyFilterFails()
throws NamingException, AuthenticationException, IOException {
thrown.expect(AuthenticationException.class);
conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPFILTER, "group1,group2");
@@ -212,7 +212,7 @@ public class TestLdapAuthenticationProviderImpl {
}
@Test
- public void testAuthenticateWhenUserFilterFailsAndGroupFilterPasses()
+ public void testAuthenticateWhenUserFilterFailsAndGroupMembershipKeyFilterPasses()
throws NamingException, AuthenticationException, IOException {
thrown.expect(AuthenticationException.class);
conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPFILTER, "group3");
@@ -258,6 +258,72 @@ public class TestLdapAuthenticationProviderImpl {
authenticateUserAndCheckSearchIsClosed("user3");
}
+ @Test
+ public void testAuthenticateWhenUserMembershipKeyFilterPasses() throws NamingException, AuthenticationException, IOException {
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPFILTER, "HIVE-USERS");
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_BASEDN, "dc=mycorp,dc=com");
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERMEMBERSHIP_KEY, "memberOf");
+
+ when(search.findUserDn("user1")).thenReturn("cn=user1,ou=PowerUsers,dc=mycorp,dc=com");
+
+ String groupDn = "cn=HIVE-USERS,ou=Groups,dc=mycorp,dc=com";
+ when(search.findGroupDn("HIVE-USERS")).thenReturn(groupDn);
+ when(search.isUserMemberOfGroup("user1", groupDn)).thenReturn(true);
+
+ auth = new LdapAuthenticationProviderImpl(conf, factory);
+ auth.Authenticate("user1", "Blah");
+
+ verify(factory, times(1)).getInstance(isA(HiveConf.class), anyString(), eq("Blah"));
+ verify(search, times(1)).findGroupDn(anyString());
+ verify(search, times(1)).isUserMemberOfGroup(anyString(), anyString());
+ verify(search, atLeastOnce()).close();
+ }
+
+ @Test
+ public void testAuthenticateWhenUserMembershipKeyFilterFails() throws NamingException, AuthenticationException, IOException {
+ thrown.expect(AuthenticationException.class);
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPFILTER, "HIVE-USERS");
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_BASEDN, "dc=mycorp,dc=com");
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERMEMBERSHIP_KEY, "memberOf");
+
+ when(search.findUserDn("user1")).thenReturn("cn=user1,ou=PowerUsers,dc=mycorp,dc=com");
+
+ String groupDn = "cn=HIVE-USERS,ou=Groups,dc=mycorp,dc=com";
+ when(search.findGroupDn("HIVE-USERS")).thenReturn(groupDn);
+ when(search.isUserMemberOfGroup("user1", groupDn)).thenReturn(false);
+
+ auth = new LdapAuthenticationProviderImpl(conf, factory);
+ auth.Authenticate("user1", "Blah");
+ }
+
+ @Test
+ public void testAuthenticateWhenUserMembershipKeyFilter2x2PatternsPasses() throws NamingException, AuthenticationException, IOException {
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPFILTER, "HIVE-USERS1,HIVE-USERS2");
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPDNPATTERN,
+ "cn=%s,ou=Groups,ou=branch1,dc=mycorp,dc=com");
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERDNPATTERN,
+ "cn=%s,ou=Userss,ou=branch1,dc=mycorp,dc=com");
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERMEMBERSHIP_KEY, "memberOf");
+
+ when(search.findUserDn("user1")).thenReturn("cn=user1,ou=PowerUsers,dc=mycorp,dc=com");
+
+ when(search.findGroupDn("HIVE-USERS1"))
+ .thenReturn("cn=HIVE-USERS1,ou=Groups,ou=branch1,dc=mycorp,dc=com");
+ when(search.findGroupDn("HIVE-USERS2"))
+ .thenReturn("cn=HIVE-USERS2,ou=Groups,ou=branch1,dc=mycorp,dc=com");
+
+ when(search.isUserMemberOfGroup("user1", "cn=HIVE-USERS1,ou=Groups,ou=branch1,dc=mycorp,dc=com")).thenThrow(NamingException.class);
+ when(search.isUserMemberOfGroup("user1", "cn=HIVE-USERS2,ou=Groups,ou=branch1,dc=mycorp,dc=com")).thenReturn(true);
+
+ auth = new LdapAuthenticationProviderImpl(conf, factory);
+ auth.Authenticate("user1", "Blah");
+
+ verify(factory, times(1)).getInstance(isA(HiveConf.class), anyString(), eq("Blah"));
+ verify(search, times(2)).findGroupDn(anyString());
+ verify(search, times(2)).isUserMemberOfGroup(anyString(), anyString());
+ verify(search, atLeastOnce()).close();
+ }
+
private void expectAuthenticationExceptionForInvalidPassword() {
thrown.expect(AuthenticationException.class);
thrown.expectMessage("a null or blank password has been provided");
http://git-wip-us.apache.org/repos/asf/hive/blob/01e691c5/service/src/test/org/apache/hive/service/auth/ldap/LdapAuthenticationTestCase.java
----------------------------------------------------------------------
diff --git a/service/src/test/org/apache/hive/service/auth/ldap/LdapAuthenticationTestCase.java b/service/src/test/org/apache/hive/service/auth/ldap/LdapAuthenticationTestCase.java
index acde8c1..f4ad6ed 100644
--- a/service/src/test/org/apache/hive/service/auth/ldap/LdapAuthenticationTestCase.java
+++ b/service/src/test/org/apache/hive/service/auth/ldap/LdapAuthenticationTestCase.java
@@ -113,8 +113,14 @@ public final class LdapAuthenticationTestCase {
return setVarOnce(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_CUSTOMLDAPQUERY, customQuery);
}
- public Builder groupMembership(String groupMembership) {
- return setVarOnce(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPMEMBERSHIP_KEY, groupMembership);
+ public Builder groupMembershipKey(String groupMembershipKey) {
+ return setVarOnce(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPMEMBERSHIP_KEY,
+ groupMembershipKey);
+ }
+
+ public Builder userMembershipKey(String userMembershipKey) {
+ return setVarOnce(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERMEMBERSHIP_KEY,
+ userMembershipKey);
}
private Builder setVarOnce(HiveConf.ConfVars confVar, String value) {
http://git-wip-us.apache.org/repos/asf/hive/blob/01e691c5/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
index 0cc2ead..d5da76c 100644
--- a/service/src/test/org/apache/hive/service/auth/ldap/TestGroupFilter.java
+++ b/service/src/test/org/apache/hive/service/auth/ldap/TestGroupFilter.java
@@ -29,6 +29,7 @@ import org.mockito.runners.MockitoJUnitRunner;
import org.junit.Before;
import org.mockito.Mock;
+import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
@@ -49,16 +50,31 @@ public class TestGroupFilter {
}
@Test
- public void testFactory() {
+ public void testGetInstanceWhenGroupFilterIsEmpty() {
conf.unset(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPFILTER.varname);
assertNull(factory.getInstance(conf));
+ }
+ @Test
+ public void testGetInstanceOfGroupMembershipKeyFilter() {
conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPFILTER, "G1");
- assertNotNull(factory.getInstance(conf));
+ Filter instance = factory.getInstance(conf);
+ assertNotNull(instance);
+ assertThat(instance, instanceOf(GroupFilterFactory.GroupMembershipKeyFilter.class));
}
@Test
- public void testApplyPositive() throws AuthenticationException, NamingException, IOException {
+ public void testGetInstanceOfUserMembershipKeyFilter() {
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPFILTER, "G1");
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERMEMBERSHIP_KEY, "memberof");
+ Filter instance = factory.getInstance(conf);
+ assertNotNull(instance);
+ assertThat(instance, instanceOf(GroupFilterFactory.UserMembershipKeyFilter.class));
+ }
+
+ @Test
+ public void testGroupMembershipKeyFilterApplyPositive()
+ throws AuthenticationException, NamingException, IOException {
conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPFILTER, "HiveUsers");
when(search.findUserDn(eq("user1")))
@@ -90,7 +106,8 @@ public class TestGroupFilter {
}
@Test(expected = AuthenticationException.class)
- public void testApplyNegative() throws AuthenticationException, NamingException, IOException {
+ public void testGroupMembershipKeyFilterApplyNegative()
+ 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"));
@@ -98,4 +115,47 @@ public class TestGroupFilter {
Filter filter = factory.getInstance(conf);
filter.apply(search, "user1");
}
+
+ @Test
+ public void testUserMembershipKeyFilterApplyPositiveWithUserId()
+ throws AuthenticationException, NamingException, IOException {
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERMEMBERSHIP_KEY, "memberOf");
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPFILTER, "Group1,Group2");
+
+ when(search.findGroupDn("Group1")).thenReturn("cn=Group1,dc=a,dc=b");
+ when(search.findGroupDn("Group2")).thenReturn("cn=Group2,dc=a,dc=b");
+
+ when(search.isUserMemberOfGroup("User1", "cn=Group2,dc=a,dc=b")).thenReturn(true);
+
+ Filter filter = factory.getInstance(conf);
+ filter.apply(search, "User1");
+ }
+
+ @Test
+ public void testUserMembershipKeyFilterApplyPositiveWithUserDn()
+ throws AuthenticationException, NamingException, IOException {
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERMEMBERSHIP_KEY, "memberOf");
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPFILTER, "Group1,Group2");
+
+ when(search.findGroupDn("Group1")).thenReturn("cn=Group1,dc=a,dc=b");
+ when(search.findGroupDn("Group2")).thenReturn("cn=Group2,dc=a,dc=b");
+
+ when(search.isUserMemberOfGroup("cn=User1,dc=a,dc=b", "cn=Group2,dc=a,dc=b")).thenReturn(true);
+
+ Filter filter = factory.getInstance(conf);
+ filter.apply(search, "cn=User1,dc=a,dc=b");
+ }
+
+ @Test(expected = AuthenticationException.class)
+ public void testUserMembershipKeyFilterApplyNegative()
+ throws AuthenticationException, NamingException, IOException {
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERMEMBERSHIP_KEY, "memberOf");
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPFILTER, "Group1,Group2");
+
+ when(search.findGroupDn("Group1")).thenReturn("cn=Group1,dc=a,dc=b");
+ when(search.findGroupDn("Group2")).thenReturn("cn=Group2,dc=a,dc=b");
+
+ Filter filter = factory.getInstance(conf);
+ filter.apply(search, "User1");
+ }
}
http://git-wip-us.apache.org/repos/asf/hive/blob/01e691c5/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
index 499b624..7c7b393 100644
--- a/service/src/test/org/apache/hive/service/auth/ldap/TestLdapSearch.java
+++ b/service/src/test/org/apache/hive/service/auth/ldap/TestLdapSearch.java
@@ -17,6 +17,7 @@
*/
package org.apache.hive.service.auth.ldap;
+import com.google.common.base.Joiner;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -49,6 +50,7 @@ public class TestLdapSearch {
@Before
public void setup() {
conf = new HiveConf();
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERMEMBERSHIP_KEY, "memberOf");
}
@Test
@@ -206,4 +208,86 @@ public class TestLdapSearch {
Collections.sort(actual);
assertEquals(expected, actual);
}
+
+ @Test
+ public void testFindGroupDnPositive() throws NamingException {
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPDNPATTERN,
+ "CN=%s,OU=org1,DC=foo,DC=bar");
+ String groupDn = "CN=Group1";
+ NamingEnumeration<SearchResult> result = mockNamingEnumeration(groupDn);
+ when(ctx.search(anyString(), anyString(), any(SearchControls.class))).thenReturn(result);
+ search = new LdapSearch(conf, ctx);
+ String expected = groupDn;
+ String actual = search.findGroupDn("grp1");
+ assertEquals(expected, actual);
+ }
+
+ @Test(expected = NamingException.class)
+ public void testFindGroupDNNoResults() throws NamingException {
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPDNPATTERN,
+ "CN=%s,OU=org1,DC=foo,DC=bar");
+ NamingEnumeration<SearchResult> result = mockEmptyNamingEnumeration();
+ when(ctx.search(anyString(), anyString(), any(SearchControls.class))).thenReturn(result);
+ search = new LdapSearch(conf, ctx);
+ search.findGroupDn("anyGroup");
+ }
+
+ @Test(expected = NamingException.class)
+ public void testFindGroupDNTooManyResults() throws NamingException {
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPDNPATTERN,
+ "CN=%s,OU=org1,DC=foo,DC=bar");
+ NamingEnumeration<SearchResult> result =
+ LdapTestUtils.mockNamingEnumeration("Result1", "Result2", "Result3");
+ when(ctx.search(anyString(), anyString(), any(SearchControls.class))).thenReturn(result);
+ search = new LdapSearch(conf, ctx);
+ search.findGroupDn("anyGroup");
+ }
+
+ @Test
+ public void testFindGroupDNWhenExceptionInSearch() throws NamingException {
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPDNPATTERN,
+ Joiner.on(":").join(
+ "CN=%s,OU=org1,DC=foo,DC=bar",
+ "CN=%s,OU=org2,DC=foo,DC=bar"
+ )
+ );
+ NamingEnumeration<SearchResult> result = LdapTestUtils.mockNamingEnumeration("CN=Group1");
+ when(ctx.search(anyString(), anyString(), any(SearchControls.class)))
+ .thenReturn(result)
+ .thenThrow(NamingException.class);
+ search = new LdapSearch(conf, ctx);
+ String expected = "CN=Group1";
+ String actual = search.findGroupDn("grp1");
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testIsUserMemberOfGroupWhenUserId() throws NamingException {
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERDNPATTERN,
+ "CN=%s,OU=org1,DC=foo,DC=bar");
+ NamingEnumeration<SearchResult> validResult = LdapTestUtils.mockNamingEnumeration("CN=User1");
+ NamingEnumeration<SearchResult> emptyResult = LdapTestUtils.mockEmptyNamingEnumeration();
+ when(ctx.search(anyString(), contains("(uid=usr1)"), any(SearchControls.class)))
+ .thenReturn(validResult);
+ when(ctx.search(anyString(), contains("(uid=usr2)"), any(SearchControls.class)))
+ .thenReturn(emptyResult);
+ search = new LdapSearch(conf, ctx);
+ assertTrue(search.isUserMemberOfGroup("usr1", "grp1"));
+ assertFalse(search.isUserMemberOfGroup("usr2", "grp2"));
+ }
+
+ @Test
+ public void testIsUserMemberOfGroupWhenUserDn() throws NamingException {
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERDNPATTERN,
+ "CN=%s,OU=org1,DC=foo,DC=bar");
+ NamingEnumeration<SearchResult> validResult = LdapTestUtils.mockNamingEnumeration("CN=User1");
+ NamingEnumeration<SearchResult> emptyResult = LdapTestUtils.mockEmptyNamingEnumeration();
+ when(ctx.search(anyString(), contains("(uid=User1)"), any(SearchControls.class)))
+ .thenReturn(validResult);
+ when(ctx.search(anyString(), contains("(uid=User2)"), any(SearchControls.class)))
+ .thenReturn(emptyResult);
+ search = new LdapSearch(conf, ctx);
+ assertTrue(search.isUserMemberOfGroup("CN=User1,OU=org1,DC=foo,DC=bar", "grp1"));
+ assertFalse(search.isUserMemberOfGroup("CN=User2,OU=org1,DC=foo,DC=bar", "grp2"));
+ }
}
http://git-wip-us.apache.org/repos/asf/hive/blob/01e691c5/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
index 3054e33..582ca35 100644
--- a/service/src/test/org/apache/hive/service/auth/ldap/TestQueryFactory.java
+++ b/service/src/test/org/apache/hive/service/auth/ldap/TestQueryFactory.java
@@ -34,6 +34,7 @@ public class TestQueryFactory {
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");
+ conf.setVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERMEMBERSHIP_KEY, "partOf");
queries = new QueryFactory(conf);
}
@@ -76,4 +77,27 @@ public class TestQueryFactory {
String actual = q.getFilter();
assertEquals(expected, actual);
}
+
+ @Test
+ public void testIsUserMemberOfGroup() {
+ Query q = queries.isUserMemberOfGroup("unique_user", "cn=MyGroup,ou=Groups,dc=mycompany,dc=com");
+ String expected = "(&(|(objectClass=person)(objectClass=user)(objectClass=inetOrgPerson))" +
+ "(partOf=cn=MyGroup,ou=Groups,dc=mycompany,dc=com)(guid=unique_user))";
+ String actual = q.getFilter();
+ assertEquals(expected, actual);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testIsUserMemberOfGroupWhenMisconfigured() {
+ QueryFactory misconfiguredQueryFactory = new QueryFactory(new HiveConf());
+ misconfiguredQueryFactory.isUserMemberOfGroup("user", "cn=MyGroup");
+ }
+
+ @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);
+ }
}
http://git-wip-us.apache.org/repos/asf/hive/blob/01e691c5/service/src/test/resources/ldap/ad.example.com.ldif
----------------------------------------------------------------------
diff --git a/service/src/test/resources/ldap/ad.example.com.ldif b/service/src/test/resources/ldap/ad.example.com.ldif
new file mode 100644
index 0000000..6e0f20f
--- /dev/null
+++ b/service/src/test/resources/ldap/ad.example.com.ldif
@@ -0,0 +1,133 @@
+dn: dc=ad,dc=example,dc=com
+dc: ad
+objectClass: top
+objectClass: domain
+
+dn: ou=Engineering,dc=ad,dc=example,dc=com
+objectClass: top
+objectClass: organizationalUnit
+ou: Engineering
+
+dn: ou=Management,dc=ad,dc=example,dc=com
+objectClass: top
+objectClass: organizationalUnit
+ou: Management
+
+dn: ou=Administration,dc=ad,dc=example,dc=com
+objectClass: top
+objectClass: organizationalUnit
+ou: Administration
+
+dn: ou=Teams,dc=ad,dc=example,dc=com
+objectClass: top
+objectClass: organizationalUnit
+ou: Teams
+
+dn: ou=Resources,dc=ad,dc=example,dc=com
+objectClass: top
+objectClass: organizationalUnit
+ou: Resources
+
+dn: cn=Team 1,ou=Teams,dc=ad,dc=example,dc=com
+objectClass: top
+objectClass: groupOfNames
+objectClass: microsoftSecurityPrincipal
+sAMAccountName: team1
+cn: Team 1
+member: sAMAccountName=engineer1,ou=Engineering,dc=ad,dc=example,dc=com
+member: sAMAccountName=manager1,ou=Management,dc=ad,dc=example,dc=com
+
+dn: cn=Team 2,ou=Teams,dc=ad,dc=example,dc=com
+objectClass: top
+objectClass: groupOfNames
+objectClass: microsoftSecurityPrincipal
+sAMAccountName: team2
+cn: Team 2
+member: sAMAccountName=engineer2,ou=Engineering,dc=ad,dc=example,dc=com
+member: sAMAccountName=manager2,ou=Management,dc=ad,dc=example,dc=com
+
+dn: cn=Resource 1,ou=Resources,dc=ad,dc=example,dc=com
+objectClass: top
+objectClass: groupOfNames
+objectClass: microsoftSecurityPrincipal
+sAMAccountName: resource1
+cn: Resource 1
+member: sAMAccountName=engineer1,ou=Engineering,dc=ad,dc=example,dc=com
+
+dn: cn=Resource 2,ou=Resources,dc=ad,dc=example,dc=com
+objectClass: top
+objectClass: groupOfNames
+objectClass: microsoftSecurityPrincipal
+sAMAccountName: resource2
+cn: Resource 2
+member: sAMAccountName=engineer2,ou=Engineering,dc=ad,dc=example,dc=com
+
+dn: cn=Admins,ou=Administration,dc=ad,dc=example,dc=com
+objectClass: top
+objectClass: groupOfUniqueNames
+objectClass: microsoftSecurityPrincipal
+sAMAccountName: admins
+cn: Admins
+uniqueMember: sAMAccountName=admin1,ou=Administration,dc=ad,dc=example,dc=com
+
+dn: sAMAccountName=engineer1,ou=Engineering,dc=ad,dc=example,dc=com
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+objectClass: microsoftSecurityPrincipal
+sAMAccountName: engineer1
+cn: Engineer 1
+sn: Surname 1
+userPassword: engineer1-password
+memberOf: cn=Team 1,ou=Teams,dc=ad,dc=example,dc=com
+memberOf: cn=Resource 1,ou=Resources,dc=ad,dc=example,dc=com
+
+dn: sAMAccountName=engineer2,ou=Engineering,dc=ad,dc=example,dc=com
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+objectClass: microsoftSecurityPrincipal
+sAMAccountName: engineer2
+cn: Engineer 2
+sn: Surname 2
+userPassword: engineer2-password
+memberOf: cn=Team 2,ou=Teams,dc=ad,dc=example,dc=com
+memberOf: cn=Resource 2,ou=Resources,dc=ad,dc=example,dc=com
+
+dn: sAMAccountName=manager1,ou=Management,dc=ad,dc=example,dc=com
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+objectClass: microsoftSecurityPrincipal
+sAMAccountName: manager1
+cn: Manager 1
+sn: Surname 1
+userPassword: manager1-password
+memberOf: cn=Team 1,ou=Teams,dc=ad,dc=example,dc=com
+
+dn: sAMAccountName=manager2,ou=Management,dc=ad,dc=example,dc=com
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+objectClass: microsoftSecurityPrincipal
+sAMAccountName: manager2
+cn: Manager 2
+sn: Surname 2
+userPassword: manager2-password
+memberOf: cn=Team 2,ou=Teams,dc=ad,dc=example,dc=com
+
+dn: sAMAccountName=admin1,ou=Administration,dc=ad,dc=example,dc=com
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+objectClass: microsoftSecurityPrincipal
+sAMAccountName: admin1
+cn: Admin 1
+sn: Surname 1
+userPassword: admin1-password
+memberOf: cn=Admins,ou=Administration,dc=ad,dc=example,dc=com
http://git-wip-us.apache.org/repos/asf/hive/blob/01e691c5/service/src/test/resources/ldap/microsoft.schema.ldif
----------------------------------------------------------------------
diff --git a/service/src/test/resources/ldap/microsoft.schema.ldif b/service/src/test/resources/ldap/microsoft.schema.ldif
new file mode 100644
index 0000000..d9a6d94
--- /dev/null
+++ b/service/src/test/resources/ldap/microsoft.schema.ldif
@@ -0,0 +1,45 @@
+dn: cn=microsoft, ou=schema
+objectclass: metaSchema
+objectclass: top
+cn: microsoft
+
+dn: ou=attributetypes, cn=microsoft, ou=schema
+objectclass: organizationalUnit
+objectclass: top
+ou: attributetypes
+
+dn: m-oid=1.2.840.113556.1.4.221, ou=attributetypes, cn=microsoft, ou=schema
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-oid: 1.2.840.113556.1.4.221
+m-name: sAMAccountName
+m-equality: caseIgnoreMatch
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-singleValue: TRUE
+
+dn: m-oid=1.2.840.113556.1.4.222, ou=attributetypes, cn=microsoft, ou=schema
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-oid: 1.2.840.113556.1.4.222
+m-name: memberOf
+m-equality: caseIgnoreMatch
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-singleValue: FALSE
+
+dn: ou=objectClasses, cn=microsoft, ou=schema
+objectclass: organizationalUnit
+objectclass: top
+ou: objectClasses
+
+dn: m-oid=1.2.840.113556.1.5.6, ou=objectClasses, cn=microsoft, ou=schema
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-oid: 1.2.840.113556.1.5.6
+m-name: microsoftSecurityPrincipal
+m-supObjectClass: top
+m-typeObjectClass: AUXILIARY
+m-must: sAMAccountName
+m-may: memberOf