Ryan
Ryan

Reputation: 177

Ldap query only returning 1000 users... yes I am using paging

I have a simple GetStaff function that should retrieve all users from active directory. We have over a 1000 users so the directory searcher is using paging because the default for the AD MaxPageSize is 1000.

Currently the search works 'sometimes' when I build and sends back all 1054 users, and other times it only sends back 1000. If it works once, it works all the time. If it fails once, it fails all the time. I have set everything in using statements to make sure the objects are destroyed, but it still doesn't always seem to respect the PageSize attribute. By default if the PageSize attribute is set, the searcher should use a SizeLimit of 0. I have tried leaving the size limit out, setting it to 0, and setting it to 100000 and the unstable result is the same. I have also tried lowering the PageSize to 250 and get the same unstable results. Currently I am trying changing the ldap policy on the server to have a MaxPageSize of 10000 and I am still receiving 1000 users with the search PageSize to 10000 also. Not sure what I am missing here, but any help or direction would be appreciated.

    public IEnumerable<StaffInfo> GetStaff(string userId)
    {
        try
        {
            var userList = new List<StaffInfo>();

            using (var directoryEntry = new DirectoryEntry("LDAP://" + _adPath + _adContainer, _quarcAdminUserName, _quarcAdminPassword))
            {
                using (var de = new DirectorySearcher(directoryEntry)
                {
                    Filter = GetDirectorySearcherFilter(LdapFilterOptions.AllUsers),
                    PageSize = 1000,
                    SizeLimit = 0
                })
                {

                    foreach (SearchResult sr in de.FindAll())
                    {
                        try
                        {
                            var userObj = sr.GetDirectoryEntry();
                            var staffInfo = new StaffInfo(userObj);

                            userList.Add(staffInfo);
                        }
                        catch (Exception ex)
                        {
                            Log.Error("AD Search result loop Error", ex);
                        }
                    }
                }
            }

            return userList;
        }
        catch (Exception ex)
        {
            Log.Error("AD get staff try Error", ex);
            return Enumerable.Empty<StaffInfo>();
        }

    }

Upvotes: 2

Views: 12673

Answers (2)

Bluebaron
Bluebaron

Reputation: 2526

LDAP is configured, by default, to only return a maximum of 1000. You can change this setting on the domain your requesting from.

Upvotes: 1

Ryan
Ryan

Reputation: 177

A friend got back to me with the below response that helped me out, so I thought I would share it and hope it helps anyone else with the same issue.

The first thing I think of is "Are you using the domain name, e.g. foo.com as the _adpath?"

If so, then I have a pretty good idea. A dns query for Foo.com will return a random list of all of up to 25 DCs in the domain. If the first DC in that random list is not responsive or firewalled off and you get that DC from DNS then you will experience the behavior you describe. Since the DNS is cached on the local machine, you will see it happen consistently one day, then not do it the next. That's infuriating behavior. :/

You can verify this with a network trace to see if this is happening.

So how do you workaround it? A couple of options.

  1. Query DNS -> create a lists of hosts returned -> Try the first one. If it fails, Try the next one. If you hit the bottom of the list, Fail. If you do this, log each independent failure noisily so the admins don't blame you.

Even better would be to ask the AD administrators for a list of ldap servers and use that with the approach described above.

80% of administrators will tell you just to use the domain name. This is good because that deploying a new domain will "just work" with no reconfiguration required.

15% of administrators will want to specify a couple of DCs that are network closest to the application. This is good for performance, but bad if they forget about this application when the time comes for them to upgrade their domain.

The other 5% doesn't really matter. :)

The next point that I see is that you are using LDAP, not LDAPs. That is fine, but there is a risk that you will use "Basic" binds. With "Basic" binds, joe hacker can steal your account credentials using a network sniffer. There are a couple of possible workarounds. 1. There is another DirectoryEntry constructor that will let you specify "Secure" as the auth method. 2. Ask your admins if you can use LdapS. (more portable, in case you need to talk to an LDAP server other than Active Directory)

The last piece is regarding Page Size. 1,000 should be fine universally. Don't use any value > 5,000 or you can expect some fidgety behaviors. i.e. This is higher than the default limit under Windows 2003, and in Windows 2008 the pagesize is hardcoded limited to 5,000 unless it's been overridden using a rather obscure bit in AD called dsHeuristics. http://support.microsoft.com/kb/2009267

Upvotes: 2

Related Questions