【问题标题】:LDAP query get all groups (nested) of a groupLDAP查询获取组的所有组(嵌套)
【发布时间】:2013-10-23 09:05:30
【问题描述】:

我想列出 Active Directory 中的所有组,包括嵌套组。

有了这个,我得到了顶级组:

try {
    Hashtable<String,String> props = new Hashtable<String,String>();
    props.put(Context.SECURITY_AUTHENTICATION, "simple");
    props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    props.put(Context.PROVIDER_URL, "ldap://adserver");
    props.put(Context.SECURITY_PRINCIPAL, "user@domain");
    props.put(Context.SECURITY_CREDENTIALS, "password");

    DirContext ctx = new InitialDirContext(props);

    SearchControls cons = new SearchControls();
    cons.setReturningAttributes(new String[] {"cn"});
    cons.setSearchScope(SearchControls.ONELEVEL_SCOPE);

    NamingEnumeration<SearchResult> answer = ctx.search("cn=users,dc=domain,dc=com", "(objectcategory=group)", cons);
    System.out.println("AD GROUPS:");
    while(answer.hasMore()) {
        SearchResult result = (SearchResult) answer.next();
        Attributes atts = result.getAttributes();
        Attribute att = atts.get("cn");
        String groupName = (String)att.get();

        //how to search for groups nested in this group
    }
} catch (NamingException e) {
    e.printStackTrace();
}

如何获取嵌套组?我google了一下,发现有两种方法:

NamingEnumeration<SearchResult> nested = ctx.search("cn=users,dc=domain,dc=com", "(&(objectClass=group)(objectCategory=group)(memberOf:1.2.840.113556.1.4.194:=cn="+groupName+"))", controls);

NamingEnumeration<SearchResult> nested = ctx.search("cn=users,dc=domain,dc=com", "(&(objectClass=group)(objectCategory=group)(memberOf=CN="+groupName+"))", controls);

但这不会返回嵌套组。我做错了什么?

【问题讨论】:

    标签: java active-directory ldap active-directory-group


    【解决方案1】:

    如果您想查找嵌套组,Active Directory 拥有 memberOf:1.2.840.113556.1.4.1941 很重要(不要替换这个神奇的数字字符串)。

    (&(objectCategory=Person)(sAMAccountName=*)(memberOf:1.2.840.113556.1.4.1941:=CN=Test group,CN=Users,DC=domain,DC=net))
    

    【讨论】:

    • 什么是魔线?无论过去或未来的 AD 版本如何,它都会始终有效吗?
    • 你知道,它是微软。未来总是不可预知的。到现在为止它有效。根据social.technet.microsoft.com/wiki/contents/articles/…“它仅在具有 Windows Server 2003 SP2 或 Windows Server 2008(或更高版本)的域控制器上可用。”
    【解决方案2】:

    你可以尝试下一个

    Attribute memberOf = srLdapUser.getAttributes().get("memberOf");
    if (memberOf != null) {
      for (int i = 0; i < memberOf.size(); i++) {
          Attributes atts = ctx.getAttributes(memberOf.get(i).toString(), new String[] { "CN" });
          Attribute att = atts.get("CN");
          groups.add((att.get().toString())); 
      }
      System.out.println(groups.toString());`
    

    【讨论】:

      【解决方案3】:

      您可以对类别使用过滤器,如下所示

      (&(objectCategory=user)(memberOf=cn=MyCustomGroup,ou=ouOfGroup,dc=subdomain,dc=domain,dc=com))

      【讨论】:

      • 嵌套组呢?
      【解决方案4】:

      这对我有用。

      (&(objectClass=group)(memberof:1.2.840.113556.1.4.1941:=" + groupDn + "))
      

      【讨论】:

      • 什么是魔线?无论过去或未来的 AD 版本如何,它都能正常工作吗?
      【解决方案5】:

      在 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;
          }
      }
      

      【讨论】:

        【解决方案6】:

        尝试改变

        cons.setSearchScope(SearchControls.ONELEVEL_SCOPE); 
        

        cons.setSearchScope(SearchControls.SUBTREE_SCOPE);
        

        这应该允许您搜索下面的整个子树,包括您指定的级别

        【讨论】:

          猜你喜欢
          • 2020-05-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-11-17
          相关资源
          最近更新 更多