Authenticating against an Active Directory server, pt. 3
Posted on September 20, 2009 by Tommy McGuire
- Authenticating against an Active Directory Server, pt. 1: Introduction
- Authenticating against an Active Directory Server, pt. 2: ASN.1
- Authenticating against an Active Directory Server, pt. 4: LDAP Ping request
- Authenticating against an Active Directory Server, pt. 5: Conclusion
In order to locate an AD server, the first step is to perform a DNS query to locate a group of potential servers; this is actually pretty trivial. I am using the dnsjava library; there are other alternatives floating around. Personally, I find the JNDI interface abhorrent (particularly the "set property, set property, set property, do it!" interface style and the whole "JNDI is independent of the underlying implementation" pseudo-feature). Anyway, dnsjava is where the org.xbill.DNS package comes from.
To locate potential LDAP hosts for basic LDAP username/password authentication against AD, this code needs to look for SRV records matching _ldap._tcp.fully-qualified-domain-name; something along the lines of "_ldap._tcp.example.com", for Example.com's AD domain of EXAMPLE.COM, with an unqualified name of EXAMPLE. (I.e. a user would log into a workstation as EXAMPLE\jdoe.)
The argument to the following method is the service record lookup name, "_ldap._tcp.example.com".
* Return SRV records for the domain, sorted by priority and weight (ahem).
* This uses the SRVRecordComparator class below; see it for the caveat about the order.
* @param domain String domain name to search for records.
* @return List of matching SRV records, sorted by priority and weight.
* @throws SecuritySystemException If the domain is ill-formed.
getSrvRecords(String domain) throws SecuritySystemException
Record records = new Lookup(domain, Type.SRV).run();
srvRecords = new ArrayList (records.length);
for (Record record : records)
Collections.sort(srvRecords, new SRVRecordComparator());
catch (TextParseException e)
String msg = "domain <" + domain + "> is not a valid DNS name";
throw new SecuritySystemException(msg, e);
(That method needs some extra error condition checking, by the way.)
SRV records contain a priority value, which is used to order the records in the list, and a weighting, which is used to order records within a priority for load balancing purposes. (For example, if each of the n records within a priority have a weighting of wk, for k between 0 and n - 1, then the first record would be chosen randomly, with a probability of wk/w where w is the sum of the wk's and so on.)
However, in my environment, all of the SRV records have the same priority and weight. Further, the choice of with host to use will be made later, by the LDAP ping process. Therefore, I am simply sorting the records by priority and randomly within priorities.
* Comparator to sort SRV Records by priority and to shuffle the SRV records within priority.
* The idea here is to sort the list of records by priority, then shuffle the records within
* each priority by comparing priorities and then flipping a coin when the priorities are equal.
* This is technically incorrect, since the choice within priority should be
* random by weighting, but I'm lazy. (And the SRV records I have at the moment have all the same
* priorities and weights).
* According to apfelmus, http://apfelmus.nfshost.com/random-permutations.html,
* "Yes, there is! The main idea is that shuffling a list is essentially the same as sorting a
* list; the minor difference being that the former chooses a permutation at random while the
* latter chooses a very particular permutation, namely the one that sorts the input. In
* other words, the idea is to take a generic sorting algorithm like merge sort and turn it
* into a shuffle algorithm by simply replacing each comparison with a random choice."
* @author mcguire
private static final class SRVRecordComparator implements Comparator
private static final Random generator = new Random();
public int compare(SRVRecord left, SRVRecord right)
int relativePriority = Integer.signum(right.getPriority() - left.getPriority());
if (relativePriority == 0)
return (generator.nextBoolean() ? -1 : 1);
The result of this code is a list of SRV records, sorted somehow. The next part of the series will attempt to locate a the best server from the list via LDAP pings.
1. Try to contact a global catalog (to resolve alternate UPNs)
2. Try to contact a domain controller in your site
or combining the two:
- Try to contact a global catalog in your site.
You can find your site on Windows via registry (and a bit more problematic, via cldap queries).
That's what I said. :-)
This post is the first step on the road to contacting the site global catalog, identifying candidate domain controllers. The CLDAP query is the next post in the series.