ldap search is very slow

2019-01-27 02:47发布

问题:

I am using JNDI to connect to the LDAP active directory, and I want to search for users where the name contains the search string, so my search method is as follows:

public static List<LDAPUser> searchContactsByName(
        ExtendedDirContext extendedDirContext, String name) {

    try {

        LdapContext ldapContext = extendedDirContext.getLdapContext();
        String searchBaseStr = extendedDirContext.getSearchBase();

        String sortKey = LDAPAttributes.NAME;
        ldapContext.setRequestControls(new Control[] { new SortControl(
                sortKey, Control.CRITICAL) });

        SearchControls searchCtls = new SearchControls();
        searchCtls.setTimeLimit(1000 * 10);

        String returnedAtts[] = { LDAPAttributes.USER_NAME,
                LDAPAttributes.NAME };
        searchCtls.setReturningAttributes(returnedAtts);

        searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);

        String searchFilter = "(&(ObjectCategory=person)(cn=*" + name
                + "*))";

        NamingEnumeration<SearchResult> results = ldapContext.search(
                searchBaseStr, searchFilter, searchCtls);

        List<LDAPUser> users = new ArrayList<LDAPUser>(0);
        while (results.hasMoreElements()) {
            SearchResult sr = (SearchResult) results.next();
            Attributes attrs = sr.getAttributes();
            LDAPUser user = new LDAPUser();
            user.setName(attrs.get(LDAPAttributes.NAME).toString()
                    .replace("cn: ", ""));
            user.setUserName(attrs.get(LDAPAttributes.USER_NAME).toString()
                    .replace("sAMAccountName: ", ""));
            users.add(user);
        }

        return users;

    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

and here is how I am making the connection to LDAP:

public static ExtendedDirContext connectToLdap(MessageSource messageSource) {

    try {
        log.debug("connectToLdap");
        String providerUrl = messageSource.getMessage("provider.url", null,
                null);
        String securityPrincipal = messageSource.getMessage(
                "security.principal", null, null);
        String securityCredentials = messageSource.getMessage(
                "security.credentials", null, null);
        String searchBase = messageSource.getMessage("search.base", null,
                null);
        boolean ssl = Boolean.parseBoolean(messageSource.getMessage("ssl",
                null, null));
        LdapContext ldapContext;

        Hashtable<String, String> ldapEnv = new Hashtable<String, String>(
                11);
        ldapEnv.put(Context.INITIAL_CONTEXT_FACTORY,
                "com.sun.jndi.ldap.LdapCtxFactory");
        ldapEnv.put(Context.PROVIDER_URL, providerUrl);
        ldapEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
        ldapEnv.put(Context.SECURITY_PRINCIPAL, securityPrincipal);
        ldapEnv.put(Context.SECURITY_CREDENTIALS, securityCredentials);
        if (ssl)
            ldapEnv.put(Context.SECURITY_PROTOCOL, "ssl");
        // To get rid of the PartialResultException when using Active
        // Directory
        ldapEnv.put(Context.REFERRAL, "follow");
        ldapContext = new InitialLdapContext(ldapEnv, null);
        ExtendedDirContext extendedDirContext = new ExtendedDirContext();
        extendedDirContext.setLdapContext(ldapContext);
        extendedDirContext.setSearchBase(searchBase);
        log.debug("success connection to ldap");
        return extendedDirContext;
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }

}

The LDAP credentials are as follows:

provider.url=ldap://dc.fabrikam.com:389
security.principal=CN=administrator,CN=Users,DC=fabrikam,DC=com
security.credentials=password
search.base=dc=fabrikam,dc=com

Why does the search take so much time to retrieve the data? Is there any change that I can do to make the search faster, since I have only 285 contacts in the AD?

回答1:

Solution was to change ldapEnv.put(Context.REFERRAL, "follow"); to ldapEnv.put(Context.REFERRAL, "ignore");



回答2:

Your filter:

"(&(ObjectCategory=person)(cn=*" + name + "*))"

May be an issue.

I would recommend that you download a known LDAP utility (Apache Directory Studio Browser as an example) and try different search filters until you find one that works.

To Start, try

"(&(ObjectCategory=person)(cn= + name ))"


回答3:

You're right,

    ldapEnv.put(Context.REFERRAL, "ignore") 

didnt get exception about connection timed out. But when i first try i get a partialexception. After i changed my ldap configuration port from 389 to 3268 i didnt get any exception, build successfully. 3268 port about global catalog of ldap. For example Outlook clients query the global catalog to locate Address Book information. You can try global catalog if you get an exception referral type setting.