【问题标题】:Find LDAP user in nested group through Java通过 Java 在嵌套组中查找 LDAP 用户
【发布时间】:2019-07-11 23:03:20
【问题描述】:

我发现没有什么对我有用。而且我很难找到具有有效代码的答案,而不是简单地粘贴来自另一个站点的搜索过滤器字符串。

尝试进行搜索的相关代码是:

SearchResult sr = executeSearchSingleResult(ctx, SearchControls.SUBTREE_SCOPE, "dc=mydomain,dc=local", "(&(objectClass=person)(sAMAccountName=admin2))", new String[]{"memberOf"});
if (sr != null) {
    Attribute memberOf = sr.getAttributes().get("memberOf");
    if (memberOf != null) {
        for (int i = 0; i < memberOf.size(); i++) {
            Attributes attributes = ctx.getAttributes(memberOf.get(i).toString(), new String[]{"CN"});
            Attribute attribute = attributes.get("CN");
            if (attribute != null) {
                log.info("member of : " + attribute.get(0));
            }
        }
        for (Enumeration e1 = memberOf.getAll(); e1.hasMoreElements();) {
            String unprocessedGroupDN = e1.nextElement().toString();
            String unprocessedGroupCN = getCN(unprocessedGroupDN);
            //checking something here
        }
    }
}

private static SearchResult executeSearchSingleResult(DirContext ctx, int searchScope, String searchBase, String searchFilter, String[] attributes) throws NamingException {
    NamingEnumeration result = executeSearch(ctx, searchScope, searchBase, searchFilter, attributes);
    SearchResult sr = null;
    try {
        while (result.hasMoreElements()) {
            sr = (SearchResult) result.next();
            break;
        }
    } catch (Exception e) {
        log.error(e, e);
    }
    return sr;
}

private static NamingEnumeration executeSearch(DirContext ctx, int searchScope, String searchBase, String searchFilter, String[] attributes) throws NamingException {
    SearchControls searchCtls = new SearchControls();
    if (attributes != null) {
        searchCtls.setReturningAttributes(attributes);
    }
    searchCtls.setSearchScope(searchScope);
    NamingEnumeration result = ctx.search(searchBase, searchFilter, searchCtls);
    return result;
}

当没有嵌套组时,这可以正常工作。但是假设我有以下组和用户结构:

My Admins (dn = CN=My Admins,CN=Users,DC=mydomain,DC=local)
    AdminUser1 (dn = CN=AdminUser 1,CN=Users,DC=mydomain,DC=local)
        AdminGroup1 (dn = CN=AdminGroup 1,CN=Users,DC=,mydomain,DC=local)
            AdminUser2 (dn = CN=AdminUser 2,CN=Users,DC=mydomain,DC=local)

这发现 AdminUser1 就好了。它找不到 AdminUser2。我需要做的是发现 AdminUser2 一直返回到名为 My Admins 的最高级别组。

我发现了很多对 1.2.840.113556.1.4.1941 的引用,但将其放入搜索过滤器的不同方法没有帮助。

我需要在代码和/或搜索过滤器中进行哪些更改以收集处于任何特定组嵌套深度的特定用户一直回到最顶层组?

【问题讨论】:

    标签: java active-directory ldap


    【解决方案1】:

    使用LDAP_MATCHING_RULE_IN_CHAIN 过滤器类似于:

    (member:1.2.840.113556.1.4.1941:=(CN=UserName,CN=Users,DC=YOURDOMAIN,DC=NET))

    通常会找到用户 CN=UserName,CN=Users,DC=YOURDOMAIN,DC=NET 所属的所有组。

    但这很复杂。

    • Microsoft Active Directory 有几个group types
    • Microsoft Active Directory 具有不同的 LDAP 服务 (普通目录和全局目录)
    • 限制

    任何可能导致组不显示在结果中的内容。

    所以组必须是Security Groups,你应该使用Global Catalog

    还有一些限制。当组嵌套“太深”或“太宽”时,LDAP_MATCHING_RULE_IN_CHAIN 类型的搜索往往会失败。嵌套级别太多或成员所属的组太多。

    【讨论】:

    • ....那么代码中需要改变什么,如果有的话?搜索过滤器应该是什么?或者如果不是代码,AD结构如何变化?
    • Jim 提到的全局目录 (GC) 使用不同的端口(3268 用于 LDAP,3269 用于 LDAPS)。使用他在回答中为您提供的搜索过滤器以及 GC 端口。这应该可以解决问题。
    • 我更改了上面的过滤器(假设UserName 表示sAMAccountName,他们键入要登录的内容)并将端口更改为3268,但它仍然无法返回任何内容。我正在尝试的两个用户(上面概述)都是只有 1 个组的成员。我已经在 AD 服务器上验证了这些组是安全组。
    • "假设 UserName 表示 sAMAccountName" -> CN=UserName,CN=Users,DC=YOURDOMAIN,DC=NET 的 NO 是用户的完全限定域名。见:ldapwiki.com/wiki/Determining%20the%20FDN
    • 我们一定漏掉了什么。尝试使用 KNOWN DAP 浏览器或带有过滤器的命令行 ldapsearch 实用程序。 (我喜欢directory.apache.org/studio
    【解决方案2】:

    在 LDAP 中,一旦您建立了连接,我们就可以查询用户是否属于给定组,您可以使用 member 或 memberOf 属性进行查询。

    查询 memberOf 属性: 使用的过滤器:(&(Group Member Attribute=Group DN)(objectClass=Group Object class)) 例如:(&(memberOf=CN=group,ou=qa_ou,dc=ppma,dc=org)(objectClass=group))

    使用成员属性: 使用的过滤器:(&(Group Member Attribute=User DN)(objectClass=Group Object class)) 例如 : (&(member=CN=user,ou=qa_ou,dc=ppma,dc=org)(objectClass=group)) 但是您必须使用用户的 member 或 memberOf 属性列表递归搜索。例如如果用户具有以下组层次结构:

    cn: user1 memberOf: CN=group1,DC=foo,DC=example,DC=com memberOf: CN=group2,DC=foo,DC=example,DC=com

    然后您需要递归查找 group1 和 group2 以及额外的 LDAP 搜索,依此类推,以查找这些组所属的组。

    我们不能在生产环境中使用 LDAP_MATCHING_RULE_IN_CHAIN,因为当我们嵌套的层次结构太深时它不起作用并且它只适用于 Active Directory。下面的解决方案与 AD 或 OpenLDAP 独立工作,我们只需要替换组属性。

    以下是查询用户所属的所有嵌套组的示例代码:

    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Hashtable;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    import java.util.concurrent.CopyOnWriteArrayList;
    
    import javax.naming.Context;
    import javax.naming.NamingEnumeration;
    import javax.naming.NamingException;
    import javax.naming.directory.InitialDirContext;
    import javax.naming.directory.SearchControls;
    import javax.naming.directory.SearchResult;
    
    public class MemberDemo {
        private static final String contextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
        private static final String connectionURL = "ldap://10.224.243.133:389";
        private static final String connectionName = "CN=administrator,CN=users,DC=ppma,DC=org";
        private static final String connectionPassword = "Conleyqa12345";
    
        public static int nestLevel = 3;
        public static int level = 1;
    
        // Optional
        private static final String authentication = null;
        private static final String protocol = null;
        private static String userBase = "OU=qa_OU,DC=ppma,DC=org";
    
        public static void main(String[] args) throws NamingException {
            long start = System.currentTimeMillis();
    
            Hashtable<String, String> env = new Hashtable<String, String>();
    
            // Configure our directory context environment.
    
            env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory);
            env.put(Context.PROVIDER_URL, connectionURL);
            env.put(Context.SECURITY_PRINCIPAL, connectionName);
            env.put(Context.SECURITY_CREDENTIALS, connectionPassword);
            if (authentication != null)
                env.put(Context.SECURITY_AUTHENTICATION, authentication);
            if (protocol != null)
                env.put(Context.SECURITY_PROTOCOL, protocol);
    
            InitialDirContext context = new InitialDirContext(env);
    
            SearchControls constraints = new SearchControls();
            constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
    
            Set<String> traversedGroups = new HashSet<String>();
            Set<String> relatedGroups = new HashSet<String>();
            List<String> tempParentColl = new CopyOnWriteArrayList<String>();
            List<String> tempGroups = new ArrayList<String>();
    
            String loginUser = "CN=qa20Nest,OU=qa_OU,DC=ppma,DC=org";
    
            String filter = "(&(member=" + loginUser + ")(objectClass=group))";
            tempGroups = findNestedGroups(tempGroups, context, filter, loginUser, constraints,
                    tempParentColl, traversedGroups, getUserName(loginUser));
            relatedGroups.addAll(tempGroups);
    
            System.out.println("Parent Groups :");
    
            for (String group : relatedGroups) {
                System.out.println(group);
            }
            long end = System.currentTimeMillis();
            long elapsedTime = end - start;
            System.out.println("Total time taken in sec : " + elapsedTime / 1000);
    
        }
    
        @SuppressWarnings("rawtypes")
        public static List<String> findNestedGroups(List<String> tempGrpRelations, InitialDirContext context, String filter,
                String groupName, SearchControls constraints, List<String> tempParentColl, Set<String> traversedGrp,
                String groupIdentifier) {
            NamingEnumeration results;
            try {
                traversedGrp.add(groupName);
                results = context.search(userBase, filter, constraints);
    
                // Fail if no entries found
                if (results == null || !results.hasMore()) {
                    System.out.println("No result found for :" + groupName);
                    if (tempParentColl.isEmpty()) {
                        return tempGrpRelations;
                    } else {
                        tempParentColl.remove(groupName);
                    }
                }
    
                while (results.hasMore()) {
                    SearchResult result = (SearchResult) results.next();
                    System.out.println("DN - " + result.getNameInNamespace());
                    tempParentColl.add(result.getNameInNamespace());
                    tempGrpRelations.add(result.getNameInNamespace());
                }
    
                Iterator<String> itr = tempParentColl.iterator();
                while (itr.hasNext()) {
                    String groupDn = itr.next();
                    String nfilter = "(&(member=" + groupDn + ")(objectClass=group))";
                    tempParentColl.remove(groupDn);
                    if (!traversedGrp.contains(groupDn)) {
                        findNestedGroups(tempGrpRelations, context, nfilter, groupDn, constraints, tempParentColl,
                                traversedGrp, getUserName(groupDn));
                    }
                }
    
            } catch (NamingException e) {
                e.printStackTrace();
            }
            return tempGrpRelations;
        }
    
        public static String getUserName(String cnName) {
    
            String name = cnName.substring(cnName.indexOf("CN=")).split(",")[0].split("=")[1];
            return name;
        }
    }
    
    

    【讨论】:

      猜你喜欢
      • 2012-11-17
      • 1970-01-01
      • 2021-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-30
      • 2015-06-23
      • 1970-01-01
      相关资源
      最近更新 更多