通过Java在嵌套组中查找LDAP用户

时间:2019-07-11 23:03:20

标签: java active-directory ldap

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

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

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的引用,但是将其放入搜索过滤器的其他方法没有帮助。

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

2 个答案:

答案 0 :(得分: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类型搜索往往会失败。该成员所属的嵌套级别过多或组过多。

答案 1 :(得分:0)

在 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

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

我们不能在生产中使用 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;
    }
}