How to get all members of AD group via LDAP in Java

10,754

Solution 1

This will obviously give you the next ones:

String[] returnedAtts = { "member;range=1500-2999" };

You need to fetch the users chunk by chunk (1500 chunks) Just make a counter and update you search and retrieve the next ones until you have all of them.

Solution 2

Two functions missing from the working code example by @Nicolas, I guess they would be something like:

public static String[] generateRangeArray(int i) {
    String range = "member;range=" + i * 1500 + "-" + ((i + 1) * 1500 - 1);
    String[] returnedAtts = { range };

    return returnedAtts;
}

public static String generateRangeString(int i) {
    String range = "member;range=" + i * 1500 + "-" + ((i + 1) * 1500 - 1);

    return range;
}

The code does not handle the case if the AD group is not so large that the member attribute actually needs to be "chunked", that is if the "member" attribute exists instead.

Solution 3

With your help I have a full working code

    // Initialize
    LdapContext ldapContext = null;
    NamingEnumeration<SearchResult> results = null;
    NamingEnumeration<?> members = null;

    try {
        // Initialize properties
        Properties properties = new Properties();
        properties.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        properties.put(Context.PROVIDER_URL, "ldap://" + ldapUrl);
        properties.put(Context.SECURITY_PRINCIPAL, adminLoginADOnPremise);
        properties.put(Context.SECURITY_CREDENTIALS, adminPasswordADOnPremise);

        // Initialize ldap context
        ldapContext = new InitialLdapContext(properties, null);

        int range = 0;
        boolean finish = false;
        while (finish != true) {
            // Set search controls
            SearchControls searchCtls = new SearchControls();
            searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
            searchCtls.setReturningAttributes(generateRangeArray(range));

            // Get results
            results = ldapContext.search(ldapBaseDn, String.format("(samAccountName=%s)", groupName), searchCtls);
            if (results.hasMoreElements() == true) {
                SearchResult result = results.next();
                try {
                    members = result.getAttributes().get(generateRangeString(range)).getAll();
                    while (members.hasMore()) {
                        String distinguishedName = (String) members.next();
                        logger.debug(distinguishedName);
                    }
                    range++;
                } catch (Exception e) {
                    // Fails means there is no more result
                    finish = true;
                }
            }
        }
    } catch (NamingException e) {
        logger.error(e.getMessage());
        throw new Exception(e.getMessage());
    } finally {
        if (ldapContext != null) {
            ldapContext.close();
        }
        if (results != null) {
            results.close();
        }
    }
Share:
10,754
Gary Greenberg
Author by

Gary Greenberg

Updated on June 05, 2022

Comments

  • Gary Greenberg
    Gary Greenberg almost 2 years

    I have written an application that retrieves Active Directory groups and flattens them, i.e. includes recursively members of subgroup to the top parent group. It works fine for small groups, but with larger groups I am facing a problem.

    If number of members does not exceed 1500, they are listed in the member attribute. If there are more - then this attribute is empty and attribute with name member;range:0-1499 appears, containing first 1500 members.

    My problem that I don't know how to get the rest of member set over 1500. We have groups with 8-12 thousand members. Do I need to run another query? On the Microsoft site I have seen C# code snippet on the similar matter, but couldn't make much sense of it, as they were showing how to specify a range, but not how to plug it into query. If someone knows how to do it in Java, I'd appreciate a tip.

  • Gary Greenberg
    Gary Greenberg almost 7 years
    Thanks, I have come up to the same thing couple weeks ago.
  • Thierry Salmon
    Thierry Salmon over 6 years
    And a small function to generate the range would look like this: public String[] genRange(int i) { String range = "member;range=" + i * 1500 + "-" + ((i + 1) * 1500 - 1); String[] returnedAtts = { range }; return returnedAtts; }
  • Steve Zavocki
    Steve Zavocki over 5 years
    You didn't include code for generateRangeString(range)
  • Karthik P
    Karthik P over 2 years
    Hi Nicolas, can you let me know what is "ldapBaseDn"