LDAP Search
Note
Examples in this documentation depend on features activated in the ds-evaluation
setup profile.
For details, see "Learn About the Evaluation Setup Profile".
Searching the directory is like searching for a phone number in a paper phone book. You can look up a phone number because you know the last name of a subscriber's entry. In other words, you use the value of one attribute of the entry to find entries that have another attribute you want.
Whereas a phone book has only one index (alphabetical order by name), the directory has many indexes. When performing a search, you specify which attributes to use, and the server derives the corresponding indexes.
The phone book might be divided into white pages for residential subscribers and yellow pages for businesses. If you look up an individual's phone number, you limit your search to the white pages. Directory services divide entries in various ways. For example, they can store organizations and groups in different locations from user entries or printer accounts. When searching the directory, you therefore also specify where to search.
The ldapsearch command requires arguments for at least the search base DN option and an LDAP filter. The search base DN identifies where in the directory to search for entries that match the filter. For example, if you are looking for printers, you might use ou=Printers,dc=example,dc=com
. In the GNB00
office, you could look up a printer as shown in the following example:
$ ldapsearch --baseDN ou=Printers,dc=example,dc=com "(printerLocation=GNB00)"
In the example above, the LDAP filter matches printer entries where the printerLocation
attribute is equal to GNB00
.
You also specify the host and port to access directory services, and the protocol to use, such as LDAP or LDAPS. If the directory service does not allow anonymous access to the data you want to search, you supply credentials, such as a username and password, or a public key certificate. You can optionally specify a list of attributes to return. If you do not specify attributes, then the search returns all user attributes for the entry.
For details about the operators that can be used in search filters, see "LDAP Filter Operators".
The following example searches for entries with user IDs (sn
) equal to hall
, returning only DNs and user ID values:
$ldapsearch \ --hostname localhost \ --port 1636 \ --useSsl \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --baseDN dc=example,dc=com \ "(sn=hall)" \ uid
dn: uid=ahall,ou=People,dc=example,dc=com uid: ahall dn: uid=bhal2,ou=People,dc=example,dc=com uid: bhal2 dn: uid=bhall,ou=People,dc=example,dc=com uid: bhall
The following example returns entries with sn
equal to jensen
for users located in San Francisco:
$ldapsearch \ --hostname localhost \ --port 1636 \ --useSsl \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --baseDN ou=people,dc=example,dc=com \ "(&(sn=jensen)(l=San Francisco))" \ @person
dn: uid=bjensen,ou=People,dc=example,dc=com objectClass: person objectClass: cos objectClass: jsonObject objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: posixAccount objectClass: top cn: Barbara Jensen cn: Babs Jensen description: Original description sn: Jensen telephoneNumber: +1 408 555 1862 dn: uid=rjensen,ou=People,dc=example,dc=com objectClass: person objectClass: cos objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: posixAccount objectClass: top cn: Richard Jensen description: Description on ou=People sn: Jensen telephoneNumber: +1 408 555 5957
The command returns the attributes associated with the person
object class.
Complex filters can use both "and" syntax, (&(filtercomp)(filtercomp))
, and "or" syntax, (|(filtercomp)(filtercomp))
.
Operational attributes are returned only when explicitly requested. Use +
in the attribute list after the filter to return all operational attributes, as in the following example:
$ldapsearch \ --hostname localhost \ --port 1636 \ --useSsl \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --baseDN dc=example,dc=com \ "(uid=bjensen)" \ +
dn: uid=bjensen,ou=People,dc=example,dc=com entryUUID: <uuid> isMemberOf: cn=Carpoolers,ou=Self Service,ou=Groups,dc=example,dc=com subschemaSubentry: cn=schema hasSubordinates: false numSubordinates: 0 etag: <etag> structuralObjectClass: inetOrgPerson entryDN: uid=bjensen,ou=People,dc=example,dc=com
Alternatively, specify operational attributes by name.
Use @objectClass
in the attribute list to return all attributes associated with a particular object class, as in the following example:
$ldapsearch \ --hostname localhost \ --port 1636 \ --useSsl \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --baseDN dc=example,dc=com \ "(uid=bjensen)" \ @person
dn: uid=bjensen,ou=People,dc=example,dc=com objectClass: person objectClass: cos objectClass: jsonObject objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: posixAccount objectClass: top cn: Barbara Jensen cn: Babs Jensen description: Original description sn: Jensen telephoneNumber: +1 408 555 1862
DS servers support searches for an approximate match of the filter. Approximate match searches use the ~=
comparison operator, described in "LDAP Filter Operators". They rely on approximate
type indexes, which are configured as shown in "Approximate Index".
The following example configures an approximate match index for the surname (sn
) attribute, and then rebuilds the index:
$dsconfig \ set-backend-index-prop \ --hostname localhost \ --port 4444 \ --bindDN uid=admin \ --bindPassword password \ --backend-name dsEvaluation \ --index-name sn \ --set index-type:approximate \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --no-prompt
$rebuild-index \ --hostname localhost \ --port 4444 \ --bindDN uid=admin \ --bindPassword password \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --baseDN dc=example,dc=com \ --index sn
Once the index is built, it is ready for use in searches. The following example shows a search using the approximate comparison operator:
$ldapsearch \ --hostname localhost \ --port 1636 \ --useSsl \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --baseDN dc=example,dc=com \ "(sn~=jansen)" \ sn
dn: uid=ajensen,ou=People,dc=example,dc=com sn: Jensen dn: uid=bjense2,ou=People,dc=example,dc=com sn: Jensen dn: uid=bjensen,ou=People,dc=example,dc=com sn: Jensen dn: uid=ejohnson,ou=People,dc=example,dc=com sn: Johnson dn: uid=gjensen,ou=People,dc=example,dc=com sn: Jensen dn: uid=jjensen,ou=People,dc=example,dc=com sn: Jensen dn: uid=kjensen,ou=People,dc=example,dc=com sn: Jensen dn: uid=rjense2,ou=People,dc=example,dc=com sn: Jensen dn: uid=rjensen,ou=People,dc=example,dc=com sn: Jensen dn: uid=tjensen,ou=People,dc=example,dc=com sn: Jensen
Notice that jansen
matches Jensen
and Johnson
.
RFC 4515, Lightweight Directory Access Protocol (LDAP): String Representation of Search Filters, mentions a number of characters that require special handing in search filters.
For a filter like (attr=value)
, the following list indicates characters that you must replace with a backslash (\
) followed by two hexadecimal digits when using them as part of the value string:
Replace
*
with\2a
.Replace
(
with\28
.Replace
)
with\29
.Replace
\
with\5c
.Replace NUL (0x00) with
\00
.
The following example shows a filter with escaped characters matching an actual value:
$ldapsearch \ --hostname localhost \ --port 1636 \ --useSsl \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --baseDN dc=example,dc=com \ "(cn=\28A \5cgreat\5c name\2a\29)" \ cn
dn: uid=bjensen,ou=People,dc=example,dc=com cn: Barbara Jensen cn: Babs Jensen cn: (A \great\ name*)
DS servers support extensible matching rules. Use a filter that specifies a matching rule OID that extends the matching operator.
DS servers support time-based matching rules for use with attributes that hold timestamp values:
- Name:
relativeTimeOrderingMatch.gt
, OID:1.3.6.1.4.1.26027.1.4.5
Greater-than relative time matching rule for time-based searches.
Use this in a filter to match attributes with values greater than the current time +/- an offset.
The filter
(pwdExpirationTime:1.3.6.1.4.1.26027.1.4.5:=5d)
matches entries where the password expiration time is greater than the current time plus five days. In other words, entries whose passwords expire in more than five days.- Name:
relativeTimeOrderingMatch.lt
, OID:1.3.6.1.4.1.26027.1.4.6
Less-than relative time matching rule for time-based searches.
Use this in a filter to match attributes with values less than the current time +/- an offset.
The filter
(lastLoginTime:1.3.6.1.4.1.26027.1.4.6:=-4w)
matches entries where the last login time is less than the current time minus four weeks. In other words, accounts that have not been active in the last four weeks.- Name:
partialDateAndTimeMatchingRule
, OID:1.3.6.1.4.1.26027.1.4.7
Partial date and time matching rule for matching parts of dates in time-based searches.
The filter
(lastLoginTime:1.3.6.1.4.1.26027.1.4.7:=2020)
matches entries where the last login time was in 2020.
The following example defines a lastLoginTime
attribute:
The new attribute is an operational attribute (
USAGE directoryOperation
).When checking schema compliance, the server skips operational attributes. The server can therefore add operational attributes to an entry without changing the entry's object classes.
Operational attributes hold information for the directory, rather than information targeting client applications. The server returns operational attributes only when explicitly requested, and client applications generally should not be able to modify them.
By defining the
lastLoginTime
attribute as operational, you limit its visibility. You also help prevent client applications from modifying its value unless specifically allowed to.The new attribute has Generalized Time syntax (
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
).
$ ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePasswordFile /path/to/opendj/config/keystore.pin \
--bindDN uid=admin \
--bindPassword password << EOF
dn: cn=schema
changetype: modify
add: attributeTypes
attributeTypes: ( lastLoginTime-oid
NAME 'lastLoginTime'
DESC 'Last time the user logged in'
EQUALITY generalizedTimeMatch
ORDERING generalizedTimeOrderingMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
SINGLE-VALUE
NO-USER-MODIFICATION
USAGE directoryOperation
X-ORIGIN 'DS example documentation' )
EOF
Configure the applicable password policy to write the last login timestamp when a user authenticates.
The following command configures a subentry password policy. On successful authentication, the policy causes the server to write a timestamp in generalized time format to the user's lastLoginTime
operational attribute:
$ ldapmodify \
--hostname localhost \
--port 1636 \
--useSsl \
--usePkcs12TrustStore /path/to/opendj/config/keystore \
--trustStorePasswordFile /path/to/opendj/config/keystore.pin \
--bindDN uid=admin \
--bindPassword password << EOF
dn: cn=Record last login,dc=example,dc=com
objectClass: top
objectClass: subentry
objectClass: ds-pwp-password-policy
cn: Record last login
ds-pwp-password-attribute: userPassword
ds-pwp-default-password-storage-scheme: PBKDF2-HMAC-SHA256
ds-pwp-last-login-time-attribute: lastLoginTime
ds-pwp-last-login-time-format: yyyyMMddHH'Z'
subtreeSpecification: { base "ou=people" }
EOF
The ds-pwp-last-login-time-format
setting must:
Match the syntax of the
ds-pwp-last-login-time-attribute
attribute, which in this example isGeneralizedTime
.Be a valid format string for the
java.text.SimpleDateFormat
class.
Configure and build an index for time-based searches on the lastLoginTime
attribute:
$dsconfig \ create-backend-index \ --hostname localhost \ --port 4444 \ --bindDN uid=admin \ --bindPassword password \ --backend-name dsEvaluation \ --set index-type:extensible \ --set index-extensible-matching-rule:1.3.6.1.4.1.26027.1.4.5 \ --set index-extensible-matching-rule:1.3.6.1.4.1.26027.1.4.6 \ --set index-extensible-matching-rule:1.3.6.1.4.1.26027.1.4.7 \ --index-name lastLoginTime \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --no-prompt
$rebuild-index \ --hostname localhost \ --port 4444 \ --bindDN uid=admin \ --bindPassword password \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --baseDN dc=example,dc=com \ --index lastLoginTime
Make sure you have some users who have authenticated recently:
$ldapsearch \ --hostname localhost \ --port 1636 \ --useSsl \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --bindDN uid=bjensen,ou=people,dc=example,dc=com \ --bindPassword hifalutin \ --baseDN dc=example,dc=com \ "(uid=bjensen)" \ 1.1
$ldapsearch \ --hostname localhost \ --port 1636 \ --useSsl \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --bindDN uid=kvaughan,ou=people,dc=example,dc=com \ --bindPassword bribery \ --baseDN dc=example,dc=com \ "(uid=bjensen)" \ 1.1
The following search returns users who have authenticated in the last 13 weeks:
$ldapsearch \ --hostname localhost \ --port 1636 \ --useSsl \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --bindDN uid=admin \ --bindPassword password \ --baseDN dc=example,dc=com \ "(lastLoginTime:1.3.6.1.4.1.26027.1.4.5:=-13w)" \ 1.1
dn: uid=bjensen,ou=People,dc=example,dc=com dn: uid=kvaughan,ou=People,dc=example,dc=com
The following search returns users who have authenticated this year:
$ldapsearch \ --hostname localhost \ --port 1636 \ --useSsl \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --bindDN uid=admin \ --bindPassword password \ --baseDN dc=example,dc=com \ "(lastLoginTime:1.3.6.1.4.1.26027.1.4.7:=$(date +%Y))" \ 1.1
dn: uid=bjensen,ou=People,dc=example,dc=com dn: uid=kvaughan,ou=People,dc=example,dc=com
DS servers support the language subtypes listed in Support for Languages and Locales.
When you perform a search you can request the language subtype by OID or by language subtype string. For example, the following search gets the French version of a common name. The example uses the DS base64 command to decode the attribute value:
$ldapsearch \ --hostname localhost \ --port 1636 \ --useSsl \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --baseDN dc=example,dc=com \ "(cn=Frederique Dupont)" cn\;lang-fr
dn: uid=fdupont,ou=People,dc=example,dc=com cn;lang-fr:: RnJlZMOpcmlxdWUgRHVwb250
$base64 decode --encodedData RnJlZMOpcmlxdWUgRHVwb250
Fredérique Dupont
At the end of the OID or language subtype, further specify the matching rule as follows:
Add
.1
for less thanAdd
.2
for less than or equal toAdd
.3
for equal to (default)Add
.4
for greater than or equal toAdd
.5
for greater thanAdd
.6
for substring
Operator | Definition | Example |
---|---|---|
= | Equality comparison, as in This can also be used with substring matches. For example, to match last names starting with | |
<= | Less than or equal to comparison, which works alphanumerically. | |
>= | Greater than or equal to comparison, which works alphanumerically. | |
=* | Presence comparison. For example, to match all entries with a | |
~= | Approximate comparison, matching attribute values similar to the value you specify. | |
[:dn][:oid]:= | Extensible match comparison. At the end of the OID or language subtype, you further specify the matching rule as follows:
| Extensible match filters work with localized values. DS servers support internationalized locales, each of which has an OID for collation order, such as |
! | NOT operator, to find entries that do not match the specified filter component. Take care to limit your search when using | |
& | AND operator, to find entries that match all specified filter components. | |
| | OR operator, to find entries that match one of the specified filter components. | |
DS servers support attribute values that have JSON syntax. This makes it possible to index JSON values, and to search for them using Common REST query filters, as described in "Query". This example depends on settings applied with the ds-evaluation
setup profile.
The index lets you search with Common REST query filters. The following example finds the entry with a JSON attribute with "access_token": "123"
:
$ldapsearch \ --hostname localhost \ --port 1636 \ --useSsl \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --baseDN dc=example,dc=com \ "(json=access_token eq '123')" \ json
dn: uid=bjensen,ou=People,dc=example,dc=com json: {"access_token":"123","expires_in":59,"token_type":"Bearer","refresh_token":"456"}
You can combine Common REST query filter syntax filters with other LDAP search filter to form complex filters, as demonstrated in "Complex LDAP Filter". For example, (&(json=access_token eq '123')(mail=bjensen@example.com))
.
In addition to searches with query filters, JSON attributes can be matched with filters using JSON in the assertion. This example demonstrates a case where JSON objects are considered equal if their "id" fields match. This example depends on settings applied with the ds-evaluation
setup profile.
Search for entries with a jsonToken
attribute:
$ldapsearch \ --hostname localhost \ --port 1636 \ --useSsl \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --baseDN dc=example,dc=com \ '(jsonToken={"id":"HgAaB6xDhLom4JbM"})' \ jsonToken
jsonToken: {"id":"HgAaB6xDhLom4JbM","scopes":["read","write"],"expires":"2018-01-10T10:08:34Z"}
If permitted by the directory administrator, you can request that the server sort the search results. When your application requests a server-side sort, the server retrieves the entries matching your search, and then returns the whole set of entries in sorted order. This process consumes memory resources on the server, so the best practice is to sort results on the client side, or to browse results with a search that matches a virtual list view index, as demonstrated in "Virtual List View Index".
This example demonstrates a server-side sort request, where the results are sorted by surname:
$ldapmodify \ --hostname localhost \ --port 1636 \ --useSsl \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --bindDn uid=admin \ --bindPassword password << EOF dn: dc=example,dc=com changetype: modify add: aci aci: (targetcontrol = "PSearch") (version 3.0;acl "Allow Server-Side Sort for Kirsten Vaughan"; allow (read)(userdn = "ldap:///uid=kvaughan,ou=People,dc=example,dc=com");) EOF
$ldapsearch \ --hostname localhost \ --port 1636 \ --useSsl \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --bindDn uid=kvaughan,ou=people,dc=example,dc=com \ --bindPassword bribery \ --baseDn dc=example,dc=com \ --sortOrder +sn \ "(&(sn=*)(cn=babs*))" \ cn
dn: uid=user.94643,ou=People,dc=example,dc=com cn: Babs Bautista dn: uid=user.81225,ou=People,dc=example,dc=com cn: Babs Bawek dn: uid=user.67807,ou=People,dc=example,dc=com cn: Babs Baxter dn: uid=user.54389,ou=People,dc=example,dc=com cn: Babs Bayer dn: uid=user.40971,ou=People,dc=example,dc=com cn: Babs Bayerkohler dn: uid=user.27553,ou=People,dc=example,dc=com cn: Babs Bayless dn: uid=user.14135,ou=People,dc=example,dc=com cn: Babs Bayley dn: uid=user.717,ou=People,dc=example,dc=com cn: Babs Bayly dn: uid=bjensen,ou=People,dc=example,dc=com cn: Barbara Jensen cn: Babs Jensen dn: uid=user.89830,ou=People,dc=example,dc=com cn: Babs Pdesupport dn: uid=user.76412,ou=People,dc=example,dc=com cn: Babs Peacemaker dn: uid=user.62994,ou=People,dc=example,dc=com cn: Babs Peacocke dn: uid=user.49576,ou=People,dc=example,dc=com cn: Babs Peake dn: uid=user.36158,ou=People,dc=example,dc=com cn: Babs Pearce dn: uid=user.22740,ou=People,dc=example,dc=com cn: Babs Pearcy dn: uid=user.9322,ou=People,dc=example,dc=com cn: Babs Pearse
For use with JSON attributes, DS servers extend the standard [+|-]attr
sort order syntax to sort on fields inside JSON objects.
The extended syntax is [+|-]ldapAttr[:extensibleJsonOrderingMatchingRule:caseSensitive:ignoreWhiteSpace:/jsonPath[:/jsonPath ...]]
, where:
All arguments are mandatory when using the extended form:
extensibleJsonOrderingMatchingRule is a JSON ordering matching rule name or OID.
If you plan to create your own ordering indexes based on the matching rule, then first define it in the LDAP schema and create a custom schema provider for the matching rule. For details, see "Schema and JSON".
Otherwise, if the JSON ordering matching rule is not yet implemented, the DS server creates it on-demand to process the request. This makes it possible to sort on any field of a JSON attribute value, although the search is unindexed.
caseSensitive is a boolean.
Set to
true
to respect case when comparing values,false
otherwise.ignoreWhiteSpace is a boolean.
Set to
true
to ignore whitespace when comparing values,false
otherwise.Each jsonPath is a path to a field inside the JSON object.
Specify at least one jsonPath.