HIVE-11512: Hive LDAP Authenticator should also support full DN in Authenticate() Naveen Gangam via Chaoyu Tang
Project: http://git-wip-us.apache.org/repos/asf/hive/repo Commit: http://git-wip-us.apache.org/repos/asf/hive/commit/cc78dd5d Tree: http://git-wip-us.apache.org/repos/asf/hive/tree/cc78dd5d Diff: http://git-wip-us.apache.org/repos/asf/hive/diff/cc78dd5d Branch: refs/heads/beeline-cli Commit: cc78dd5d8ce1e5a77ecf9f65b9bd19cccf158ac3 Parents: ae588db Author: ctang <[email protected]> Authored: Fri Sep 18 22:02:22 2015 -0400 Committer: ctang <[email protected]> Committed: Fri Sep 18 22:03:42 2015 -0400 ---------------------------------------------------------------------- .../auth/LdapAuthenticationProviderImpl.java | 82 ++++++++++++++++++-- 1 file changed, 76 insertions(+), 6 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/hive/blob/cc78dd5d/service/src/java/org/apache/hive/service/auth/LdapAuthenticationProviderImpl.java ---------------------------------------------------------------------- diff --git a/service/src/java/org/apache/hive/service/auth/LdapAuthenticationProviderImpl.java b/service/src/java/org/apache/hive/service/auth/LdapAuthenticationProviderImpl.java index 0c7cede..b2c4daf 100644 --- a/service/src/java/org/apache/hive/service/auth/LdapAuthenticationProviderImpl.java +++ b/service/src/java/org/apache/hive/service/auth/LdapAuthenticationProviderImpl.java @@ -146,15 +146,28 @@ public class LdapAuthenticationProviderImpl implements PasswdAuthenticationProvi DirContext ctx = null; String userDN = null; + String userName = null; try { // Create initial context ctx = new InitialDirContext(env); + if (isDN(user)) { + userName = extractName(user); + } else { + userName = user; + } + if (userFilter == null && groupFilter == null && customQuery == null) { - userDN = findUserDNByPattern(ctx, user); + if (isDN(user)) { + userDN = findUserDNByDN(ctx, user); + } else { + if (userDN == null) { + userDN = findUserDNByPattern(ctx, user); + } - if (userDN == null) { - userDN = findUserDNByName(ctx, baseDN, user); + if (userDN == null) { + userDN = findUserDNByName(ctx, baseDN, user); + } } // This should not be null because we were allowed to bind with this username @@ -185,7 +198,7 @@ public class LdapAuthenticationProviderImpl implements PasswdAuthenticationProvi boolean success = false; for (String filteredUser : userFilter) { - if (filteredUser.equalsIgnoreCase(user)) { + if (filteredUser.equalsIgnoreCase(userName)) { LOG.debug("User filter partially satisfied"); success = true; break; @@ -198,7 +211,7 @@ public class LdapAuthenticationProviderImpl implements PasswdAuthenticationProvi "of specified list"); } - userDN = findUserDNByPattern(ctx, user); + userDN = findUserDNByPattern(ctx, userName); if (userDN != null) { LOG.info("User filter entirely satisfied"); } else { @@ -214,7 +227,7 @@ public class LdapAuthenticationProviderImpl implements PasswdAuthenticationProvi // if only groupFilter is configured. if (userDN == null) { - userDN = findUserDNByName(ctx, baseDN, user); + userDN = findUserDNByName(ctx, baseDN, userName); } List<String> userGroups = getGroupsForUser(ctx, userDN); @@ -395,6 +408,44 @@ public class LdapAuthenticationProviderImpl implements PasswdAuthenticationProvi return null; } + /** + * This helper method attempts to find a username given a DN. + * Various LDAP implementations have different keys/properties that store this unique userID. + * Active Directory has a "sAMAccountName" that appears reliable,openLDAP uses "uid" + * So the first attempt is to find an entity with objectClass=person||user where + * (uid||sAMAccountName) matches the given username. + * The second attempt is to use CN attribute for wild card matching and then match the + * username in the DN. + * @param ctx DirContext for the LDAP Connection. + * @param baseDN BaseDN for this LDAP directory where the search is to be performed. + * @param userName A unique userid that is to be located in the LDAP. + * @return LDAP DN if the user is found in LDAP, null otherwise. + */ + public static String findUserDNByDN(DirContext ctx, String userDN) + throws NamingException { + if (!isDN(userDN)) { + return null; + } + + String baseDN = extractBaseDN(userDN); + List<String> results = null; + String searchFilter = "(&(|(objectClass=person)(objectClass=user))(" + DN_ATTR + "=" + + userDN + "))"; + + results = findDNByName(ctx, baseDN, searchFilter, 2); + + if (results == null) { + return null; + } + + if(results.size() > 1) { + //make sure there is not another item available, there should be only 1 match + LOG.info("Matched multiple users for the user: " + userDN + ",returning null"); + return null; + } + return userDN; + } + public static List<String> findDNByName(DirContext ctx, String baseDN, String searchString, int limit) throws NamingException { SearchResult searchResult = null; @@ -507,4 +558,23 @@ public class LdapAuthenticationProviderImpl implements PasswdAuthenticationProvi } return list; } + + public static boolean isDN(String name) { + return (name.indexOf("=") > -1); + } + + public static String extractName(String dn) { + if (dn.indexOf("=") > -1) { + return dn.substring(dn.indexOf("=") + 1, dn.indexOf(",")); + } + return dn; + } + + public static String extractBaseDN(String dn) { + if (dn.indexOf(",") > -1) { + return dn.substring(dn.indexOf(",") + 1); + } + return null; + } + }
