Skip to content
September 21, 2011 / Terry Gardner

LDAP: Mastering Search Filters

About Filters

According to RFC 4511, the search filter in an LDAP search request defines the conditions that must be fulfilled in order for the Search to match a given entry.

The search filter is used to match candidate entries that are in the scope of the search at or below the base object (for one-level search and subtree search). Entries that do not match the search filter are not returned to the LDAP client in the search result. The filter supplied as a parameter to a search request evaluates to true, false, or undefined for each entry in scope (an example of a filter that evaluates to undefined is a filter that contains an attribute that is not known to the directory server). Directory administrators should be made aware of the types of filters before they are used – they might need to index directory attributes to achieve desirable performance results.

Whether a filter matches an entry is determined by the “matching rule” for the attribute description. Therefore, it is crucial when constructing filters to understand the attribute types and the matching rule associated with the attribute description. There is a common misconception that LDAP data is not case-sensitive, but this does not state the reality correctly. The directory server must perform matching and ordering functions using matching rules and ordering rules, respectively. Some widely used attribute syntaxes like DirectoryString are defined to use the caseIgnoreMatch equality matching rule, which can make it seem to the application that data and searches are not case-sensitive. When an LDAP client requires that a search be case-sensitive, an extensible match filter that specifies the matching rule can be used:

(uid:caseExactMatch:=User.0)

The above filter will match "User.0" but not "user.0".

Types of Filters

Search filters can be broadly classified in to three main types:

AND

(&(uid=ianderson)(sn:caseExactMatch:=Anderson)(givenName:caseExactMatch:=Ian))

This filter will match all entries with a uid that has value “ianderson” where case is not significant due to the matching rule for uid, a surname that matches “Anderson” where case is significant, and a first name of “Ian”. If case is not significant, use an equality filter instead of an extensible matching filter:

(&(uid=ianderson)(sn=Anderson)(givenName=Ian))

OR

(|(uid=user.0)(objectClass=inetOrgPerson))

This filter evaluates to true for each entry which has a uid attribute with a value of “user.0″ (case is not significant) or an attribute objectClass with a value of “inetOrgPerson”.

NEGATION (not)

(!(title:dn:caseExactMatch:=Thick as a Brick))

This filter evaluates to true for all entries that have a title attribute whose value is not "Thick as a Brick".

A not filter must have one and only one component, for example, (!(objectClass=inetOrgPerson))

NB: There exist several commercial software products which use illegal negation filters – if strange results occur in testing involving one of these faulty products, this software defect might be contributory. An example of a invalid not filter is (!(name=*)(name=*)). The syntax for a compound not filter is:

(&(!(objectClass=inetOrgPerson))(!(uid=abc)))

There are two assertions: (!(objectClass=inetOrgPerson)) and (!(uid=abc)) which, because of the "&", both must be true in order for the search filter to evaluate to true.

Adjacent Assertions

Two filter components may not be adjacent when there is no & or |, For example, the filter (cn=abc)(description=abc) is not a legal search filter if presented to a standards-compliant LDAP server. There is an error in the older OpenLDAP ldapsearch tool which causes the tool to flag the filter "(cn=abc)(description=abc)" as a bad filter:

/usr/bin/ldapsearch -x -LLL  -D 'cn=directory manager' -w password \
 -h localhost -p 1389 -b cn="" \
 -s base "(cn=abc)(description=abc)" 1.1
ldapsearch: ldap_search_ext: Bad search filter (-7)

The correct behavior is to encode the ")(" sequence resulting in (cn=abc\29\28description=abc). Here, only an entry with an attribute cn having the value abc\29\28description=abc will cause the filter to evaluate to true, where case is not significant. To match case, use an extensible match filter: (cn:caseExactMatch:=abc\29\28description=abc)

Assertions:

For general information about the ldapsearch tool, see “LDAP: Using ldapsearch”.

  • equality: (objectClass=inetOrgPerson)
  • presence: (objectClass=*)
  • substring: (mail=ma*@example.com)
  • greater than: (employeeNumber>=5) but see syntax and matching rules below
  • less than: (employeeNumber<=5) but see syntax and matching rules below
  • approx: (uid~=ianderson)
  • extensible match: (uid:caseExactMatch:=UsEr.0)

Example entry

The example filters below use the following entry for demonstration purposes:

dn: uid=user.0, ou=People, dc=example, dc=com
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
postalAddress: Aaren Atp$91327 Broadway Street$Las Vegas, UT  08103
postalCode: 08103
uid: user.0
userPassword: {SSHA}Zo3Mj5UoiSnd/t58Cd8Uv4vjoZzhOL0a74k2sw==
employeeNumber: 0
initials: AWA
givenName: Aaren
pager: +1 214 214 4195
mobile: +1 947 007 3231
cn: Aaren Atp
sn: Atp
telephoneNumber: +1 089 907 9947
street: 91327 Broadway Street
homePhone: +1 457 787 9183
l: Las Vegas
mail: user.0@example.com
st: UT
description: test description 1
uidNumber: 10000
gidNumber: 10000
homeDirectory: /export/home/user.0
loginShell: /bin/bash

Equality match

A filter that returns true when the equality matching rule returns true when applied to the attribute type or subtype and the the asserted value. The following equality filters would match the above entry:

(uid=user.0)
(sn=atp)
# This equality filter forces the use of the exact matching rule
# and is an example of an extensible match filter:
(sn:caseExactMatch:=Atp)

Presence

A filter that returns true when an attribute or subtype of the specified attribute description is present in an entry. The following presence filters would match the above entry:

(uid=*)
(sn=*)
(mail=*)

The above filters might match a large number of entries in the directory server database. As with any search, the programmer should provide a size limit and time limit when issuing a search. The following example shows how to use a size limit with ldapsearch:

ldapsearch -D 'cn=Directory Manager' -j ~/.pwdFile \
 -h localhost -p 1389 -b dc=example,dc=com \
 -s sub --sizeLimit 2 '(uid=*)' 1.1
dn: uid=user.0, ou=People, dc=example, dc=com

dn: uid=user.1, ou=People, dc=example, dc=com

This search operation has sent the
maximum of 2 entries to the client
Result Code:  4 (Size Limit Exceeded)
Diagnostic Message:  This search operation has sent
the maximum of 2 entries to the client

If you are using the old OpenLDAP ldapsearch tool:

/usr/bin/ldapsearch -D 'cn=Directory Manager' \
  -W -h localhost -p 1389 -b dc=example,dc=com \
 -s sub -z 2 -LLL '(uid=*)' 1.1
Enter LDAP Password:
dn: uid=user.0, ou=People, dc=example, dc=com

dn: uid=user.1, ou=People, dc=example, dc=com

Size limit exceeded (4)
Additional information: This search operation has
sent the maximum of 2 entries to the client

Substring

A filter that returns true when the substring matching rule returns true. The following substring filters would match the above entry:

(mail=u*.0*example.com)
(uid=user*)

Syntax and Matching Rules

Knowledge of syntax and matching rules is important when constructing a filter. The following filter is intended to match all entries that have an employeeNumber attribute whose value is between integer 1 and integer 5, inclusive:

(&(employeeNumber>=1)(employeeNumber<=5))

but fails to produce the desired result because the syntax of employeeNumber is 1.3.6.1.4.1.1466.115.121.1.15 with matching rule caseIgnoreMatch and substring matching rule caseIgnoreSubstringsMatch. Had the syntax of employeeNumber been 1.3.6.1.4.1.1466.115.121.1.27 with a matching rule of integerMatch, the search would have returned all entries which had employeeNumber between 1 and 5, inclusive.

URLs referenced in the article.

Updates

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s