OpenLDAP search filters

I use LDAP authentication on several Web servers. For the first time, I have a Web application that I want to open to customers as well as staff. Usually, I just put the users into a group. Apache validates the password against LDAP and checks for group membership, and either accepts or rejects the request. The relevant Apache configuration looks like this:

AuthLDAPURL “ldap://ldap1.domain.com/ou=people,dc=domain,dc=com” STARTTLS
AuthLDAPGroupAttribute memberUid
require ldap-group cn=groupname,ou=groups,dc=domain,dc=com

Apache requires that I specify where to look for accounts, as shown in bold above. My customers are in a different OU than my coworkers. (It would have made more sense to name the “people” container “staff,” but I didn’t realize that at the time.) Apache will accept a filter in AuthLDAPURL, letting you check in multiple groups. I’ve never taken the time to understand LDAP filters, so I guess I better start now. I’ll write my first filters for ldapsearch(1), and then carry them over to Apache.

Normally, I run ldapsearch like so:

# ldapsearch -WxZD "cn=manager,dc=domain,dc=com"
Enter LDAP Password:

-W tells ldapsearch to ask for a password, -x sets simple auth, -Z toggles startTLS, and -D indicates a bind DN follows. While I have an inherent dislike of typing a password on the command line, I’m going to run many LDAP searches in quick succession on a test machine. My test machine doesn’t use the same password as my production environment, so I’m willing to make an exception for convenience. Drop the -W, and add the password with -w. Specify the password in quotes to escape symbols and such.

# ldapsearch -xZD "cn=manager,dc=domain,dc=com" -w "password"

You should get a dump of your LDAP directory.

Now to build up a filter iteratively, figuring out how they work as we go. ldapsearch expects the filter to be the last item on the command line. Put it in quotes, to escape special characters.

# ldapsearch -xZD "cn=manager,dc=domain,dc=com" -w "password" "(uid=mwlucas)"

This returns only my user account, as I would expect. Now let’s search for one of two accounts, joined by an OR. I’m going to stop including the entire command line, and only list the filter at the end.

"(|(uid=mwlucas)(uid=mwlucas2))"

The OR operator is a pipe symbol (|). It’s followed by the two possible choices, each in parenthesis. This filter matches any entry where the uid is either mwlucas or mwlucas2. I get information for two accounts back.

Similarly, I can search for a group by CN as well as a username. I want to see everything with a UID of “mwlucas” or matching the CN “cacti”.

"(|(uid=mwlucas)(cn=cacti))"

Entries for my account and this group appear.

About this time I realize that I can probably fix my Apache problem by removing the ou=people entry in AuthLDAPURL, giving me:

AuthLDAPURL “ldap://ldap1.domain.com/dc=domain,dc=com” STARTTLS

I try it and, yes, users from both OUs can now log in. But I'm going to learn about search filters, anyway.

I can use two additional logical operators, AND (&) and NOT(!).

Also, filters support wildcards. For example, here I want to see all accounts that have the initials "mwl" in them. I've created more than one test account, and want to be sure that I remember all of them.

(uid=*mwl*)

That generates a lot of output, though. I'm more interested in a list of UIDs. If you specify an attribute after the filter, ldapsearch will only print that attribute. Here's the whole command string for this search.

# ldapsearch -xZD "cn=manager,dc=domain,dc=com" -w "password" "(uid=*mwl*)" uid
...ldap internal stuff deleted...
# mwlucas, people, domain.com
dn: uid=mwlucas,ou=people,dc=domain,dc=com
uid: mwlucas

# mwltest, people, domain.com
dn: uid=mwltest,ou=people,dc=domain,dc=com
uid: mwltest

# mwlstaff, people, domain.com
dn: uid=mwlstaff,ou=people,dc=domain,dc=com
uid: mwlstaff

# mwlucas2, customers, domain.com
dn: uid=mwlucas2,ou=customers,dc=domain,dc=com
uid: mwltest2

That's enough filtering to make my day-to-day life easier, so I'll get back to the problem I'm really trying to solve today.