Directory Services 7.4.2

LDAP search

Examples in this documentation depend on features activated in the ds-evaluation setup profile. For details, refer to Learn about the evaluation setup profile.

The code samples demonstrate how to contact the server over HTTPS using the deployment CA certificate. Before trying the samples, generate the CA certificate in PEM format from the server deployment ID and password:

$ dskeymgr \
 export-ca-cert \
 --deploymentId $DEPLOYMENT_ID \
 --deploymentIdPassword password \
 --outputFile ca-cert.pem

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, refer to 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 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --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 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --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: oauth2TokenObject
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)).

Substring searches

Sometimes you only have part of the value that the search must match. Use a substring search in this case.

The following example returns entries with phone numbers that contain 5551212:

$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --usePkcs12TrustStore /path/to/opendj/config/keystore \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --baseDN ou=people,dc=example,dc=com \
 "(telephoneNumber=*5551212*)"

The following example returns entries where the full name (common name) starts with Barb:

$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --usePkcs12TrustStore /path/to/opendj/config/keystore \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --baseDN ou=people,dc=example,dc=com \
 "(cn=barb*)"

The filter has barb in lower case because the cn attribute is case-insensitive. Many standard LDAP attributes are case-insensitive.

The following example returns entries where the full name ends with ensen:

$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --usePkcs12TrustStore /path/to/opendj/config/keystore \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --baseDN ou=people,dc=example,dc=com \
 "(sn=*ensen)"

If you had the whole last name, such as Jensen, then you would use (sn=jensen) as the search filter. Substring searches are useful, but they are also more expensive than exact searches.

Operational attributes are returned only when explicitly requested. Use + in the attribute list after the filter to return all operational attributes:

$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --usePkcs12TrustStore /path/to/opendj/config/keystore \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --baseDN dc=example,dc=com \
 "(uid=bjensen)" \
 +

dn: uid=bjensen,ou=People,dc=example,dc=com
entryDN: uid=bjensen,ou=People,dc=example,dc=com
entryUUID: <uuid>
etag: <etag>
hasSubordinates: false
isMemberOf: cn=Carpoolers,ou=Self Service,ou=Groups,dc=example,dc=com
numSubordinates: 0
structuralObjectClass: inetOrgPerson
subschemaSubentry: cn=schema

Alternatively, specify operational attributes by name.

Use @objectClass in the attribute list to return all attributes of a particular object class:

$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --usePkcs12TrustStore /path/to/opendj/config/keystore \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --baseDN dc=example,dc=com \
 "(uid=bjensen)" \
  @person

dn: uid=bjensen,ou=People,dc=example,dc=com
objectClass: person
objectClass: cos
objectClass: oauth2TokenObject
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 \
 --trustStorePassword:file /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 \
 --trustStorePassword:file /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 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --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.

Escape characters in filters

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 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --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

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

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 (ds-last-login-time: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

Partial date and time matching rule for matching parts of dates in time-based searches.

The filter (ds-last-login-time:1.3.6.1.4.1.26027.1.4.7:=2020) matches entries where the last login time was in 2020.

The following example uses the ds-last-login-time attribute, which is an operational attribute (USAGE directoryOperation) with Generalized Time syntax (SYNTAX 1.3.6.1.4.1.1466.115.121.1.24).

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.

As the ds-last-login-time attribute is operational, it has limited visibility. This helps prevent client applications from modifying its value unless specifically allowed to.

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 ds-last-login-time operational attribute:

$ ldapmodify \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --usePkcs12TrustStore /path/to/opendj/config/keystore \
 --trustStorePassword:file /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: ds-last-login-time
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 is GeneralizedTime.

  • Be a valid format string for the java.text.SimpleDateFormat class.

With the setting shown in the example, ds-pwp-last-login-time-format: yyyyMMddHH’Z', DS records last login time to the nearest hour. For each bind where the timestamp changes, DS updates the timestamp on the entry. So this recommended setting avoids updating entries often for users who bind repeatedly over a short period. If the deployment requires a fine-grained last login timestamp, use a format that includes minutes or seconds. For example, to get last login times that are accurate to the second, use ds-pwp-last-login-time-format:"yyyyMMddHHmmss’Z'".

Configure and build an index for time-based searches on the ds-last-login-time 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 ds-last-login-time \
 --usePkcs12TrustStore /path/to/opendj/config/keystore \
 --trustStorePassword:file /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 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --baseDN dc=example,dc=com \
 --index ds-last-login-time

Make sure you have some users who have authenticated recently:

$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --usePkcs12TrustStore /path/to/opendj/config/keystore \
 --trustStorePassword:file /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 \
 --trustStorePassword:file /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 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=admin \
 --bindPassword password \
 --baseDN dc=example,dc=com \
 "(ds-last-login-time: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 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=admin \
 --bindPassword password \
 --baseDN dc=example,dc=com \
 "(ds-last-login-time: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 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --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 than

  • Add .2 for less than or equal to

  • Add .3 for equal to (default)

  • Add .4 for greater than or equal to

  • Add .5 for greater than

  • Add .6 for substring

LDAP filter operators

Operator Definition Example

=

Equality comparison, as in (sn=Jensen).

This can also be used with substring matches. For example, to match last names starting with Jen, use the filter (sn=Jen*). Substrings are more expensive for the directory server to index. Substring searches might not be permitted, depending on the attribute.

"(cn=My App)" matches entries with common name My App.

"(sn=Jen*)" matches entries with surname starting with Jen.

<=

Less than or equal to comparison, which works alphanumerically.

"(cn<=App)" matches entries with commonName up to those starting with App (case-insensitive) in alphabetical order.

>=

Greater than or equal to comparison, which works alphanumerically.

"(uidNumber>=1151)" matches entries with uidNumber greater than 1151.

=*

Presence comparison. For example, to match all entries with a userPassword attribute, use the filter (userPassword=*).

"(member=*)" matches entries with a member attribute.

~=

Approximate comparison, matching attribute values similar to the value you specify.

"(sn~=jansen)" matches entries with a surname that sounds similar to Jansen (Johnson, Jensen, and other surnames).

[:dn][:oid]:=

Extensible match comparison.

At the end of the OID or language subtype, you further specify the matching rule as follows:

  • Add .1 for less than

  • Add .2 for less than or equal to

  • Add .3 for equal to (default)

  • Add .4 for greater than or equal to

  • Add .5 for greater than

  • Add .6 for substring

(uid:dn:=bjensen) matches entries with DN component uid=bjensen.

(ds-last-login-time: 1.3.6.1.4.1.26027.1.4.5:=-13w) matches entries with a last login time more recent than 13 weeks.

Extensible match filters work with localized values. DS servers support internationalized locales, each of which has an OID for collation order, such as 1.3.6.1.4.1.42.2.27.9.4.76.1 for French. DS software lets you use the language subtype, such as fr, instead of the OID.

"(cn:dn:=My App)" matches entries with cn: My App and DN component cn=My App.

!

NOT operator, to find entries that do not match the specified filter component.

Take care to limit your search when using ! to avoid matching so many entries that the server treats your search as unindexed.

'!(objectclass=person)' matches non-person entries.

&

AND operator, to find entries that match all specified filter components.

'(&(l=San Francisco)(!(uid=bjensen)))' matches entries for users in San Francisco other than the user with ID bjensen.

|

OR operator, to find entries that match one of the specified filter components.

"|(sn=Jensen)(sn=Johnson)" matches entries with surname Jensen or surname Johnson.

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 HDAP API reference.

The following examples depend on settings applied with the ds-evaluation setup profile.

The first example uses a custom JSON query index for an oauth2Token JSON attribute. The index lets you search with Common REST query filters. The search finds the entry with "access_token": "123":

$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --usePkcs12TrustStore /path/to/opendj/config/keystore \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --baseDN dc=example,dc=com \
 "(oauth2Token=access_token eq '123')" \
 oauth2Token

dn: uid=bjensen,ou=People,dc=example,dc=com
oauth2Token: {"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, (&(oauth2Token=access_token eq '123')(mail=bjensen@example.com)).

The next example relies on a default JSON query index for equality, part of the ds-evaluation setup profile. The index applies to a json attribute that holds arbitrary JSON objects. The search finds an entry with a json attribute that has an "array" field containing an array of objects:

$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --usePkcs12TrustStore /path/to/opendj/config/keystore \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --baseDN dc=example,dc=com \
 "(json=array[x eq 1 and y eq 2])" \
 json

dn: uid=abarnes,ou=People,dc=example,dc=com
json: {"array":[{"x":1,"y":2},{"x":3,"y":4}]}

Notice the value of the json attribute: {"array":[{"x":1,"y":2},{"x":3,"y":4}]}:

  • The filter "(json=array[x eq 1 and y eq 2])" matches because it matches the first object of the array.

  • The filter "(array[x eq 1] and array[y eq 4])" matches because it matches both objects in the array.

  • The filter "(json=array[x eq 1 and y eq 4])" fails to match, because the array has no object {"x":1,"y":4}.

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 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --baseDN dc=example,dc=com \
 '(jsonToken={"id":"HgAaB6xDhLom4JbM"})' \
 jsonToken

jsonToken: {"id":"HgAaB6xDhLom4JbM","scopes":["read","write"],"expires":"2018-01-10T10:08:34Z"}

Server-side sort

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.

The following example grants access to use the server-side sort control:

Show example
$ ldapmodify \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --usePkcs12TrustStore /path/to/opendj/config/keystore \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDn uid=admin \
 --bindPassword password << EOF
dn: dc=example,dc=com
changetype: modify
add: aci
aci: (targetcontrol = "ServerSideSort")
 (version 3.0;acl "Allow Server-Side Sort for Kirsten Vaughan";
 allow (read)(userdn = "ldap:///uid=kvaughan,ou=People,dc=example,dc=com");)
EOF

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.

DS supports the following sort key forms. The ldapsearch command --sortOrder option takes these forms as arguments:

[+|-]attr

Use this form with standard LDAP attributes.

The optional plus or minus sign defines the order, and attr is the name of the LDAP attribute to sort on.

For example, cn and +cn sort by common name in ascending order. -sn sorts by surname in descending order.

The following example sorts the results in ascending order by surname using --sortOrder +sn:

Show example
$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --usePkcs12TrustStore /path/to/opendj/config/keystore \
 --trustStorePassword:file /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
[+|-]jsonAttr:customJsonOrderingMatchingRule

Use this form to sort on predefined fields in LDAP attributes whose values are JSON objects.

Here, jsonAttr is the attribute name of the JSON attribute, and customJsonOrderingMatchingRule is one defined in the LDAP schema and backed by a custom schema provider. For details, refer to Schema and JSON.

The following example sorts the results in ascending order by the "id" field of the jsonToken attribute. The custom matching rule, caseIgnoreJsonTokenIDMatch, is defined by the ds-evaluation setup profile:

Show example
$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --usePkcs12TrustStore /path/to/opendj/config/keystore \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDn uid=kvaughan,ou=people,dc=example,dc=com \
 --bindPassword bribery \
 --baseDn dc=example,dc=com \
 --sortOrder +jsonToken:caseIgnoreJsonTokenIDMatch \
 "(objectClass=jsonTokenObject)" \
 jsonToken

dn: uid=mjablons,ou=People,dc=example,dc=com
jsonToken: {"id":"HgAaB6xDhLom4JbM","scopes":["read","write"],"expires":"2018-01-10T10:08:34Z"}

dn: uid=awhite,ou=People,dc=example,dc=com
jsonToken: {"id":"HkV5KzDrOgqN4prp","scopes":["read"],"expires":"2018-01-10T11:09:12Z"}
[+|-]jsonAttr:extensibleJsonOrderingMatch:caseSensitive?:ignoreSpace?:/jsonPath[:/jsonPath…​]

Use this form to sort on arbitrary fields in LDAP attributes whose values are JSON objects.

DS creates a matching rule on demand, if necessary. In that case, the search is unindexed.

The following example uses this sort key form to mimic the previous example that used a custom JSON ordering rule:

Show example
$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --usePkcs12TrustStore /path/to/opendj/config/keystore \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDn uid=kvaughan,ou=people,dc=example,dc=com \
 --bindPassword bribery \
 --baseDn dc=example,dc=com \
 --sortOrder +jsonToken:extensibleJsonOrderingMatch:true:true:/id \
 "(objectClass=jsonTokenObject)" \
 jsonToken

dn: uid=mjablons,ou=People,dc=example,dc=com
jsonToken: {"id":"HgAaB6xDhLom4JbM","scopes":["read","write"],"expires":"2018-01-10T10:08:34Z"}

dn: uid=awhite,ou=People,dc=example,dc=com
jsonToken: {"id":"HkV5KzDrOgqN4prp","scopes":["read"],"expires":"2018-01-10T11:09:12Z"}

This form has these required parameters:

  • Start with extensibleJsonOrderingMatch, or the OID 1.3.6.1.4.1.36733.2.1.4.6.

  • Set caseSensitive? to true to respect case when comparing values, false otherwise.

  • Set ignoreSpace? to true to ignore whitespace when comparing values, false otherwise.

  • Each /jsonPath specifies a field inside the JSON object. Specify at least one /jsonPath.

DN patterns

LDAP attributes such as manager have DN values. After adding an extensible match index for these attributes, you can use wildcards to find matches for specific RDNs in the DN, for example.

The following example demonstrates adding an index, so you can search for Torrey Rigden’s (uid=trigden) employees, regardless of which company Torrey works for now.

The example that follows creates an extensible match index using the DN pattern matching rule, distinguishedNamePatternMatch, which has numeric OID 1.3.6.1.4.1.36733.2.1.4.13. This supports searches that include wildcards.

The example also indexes manager for equality for search filters. The equality index is not required, but can be useful for searches the match entire DNs:

# Create and rebuild the new index:
$ dsconfig \
 create-backend-index \
 --backend-name dsEvaluation \
 --index-name manager \
 --set index-extensible-matching-rule:1.3.6.1.4.1.36733.2.1.4.13 \
 --set index-type:equality \
 --set index-type:extensible \
 --type generic \
 --hostname localhost \
 --port 4444 \
 --bindDN uid=admin \
 --bindPassword password \
 --usePkcs12TrustStore /path/to/opendj/config/keystore \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --no-prompt
$ rebuild-index \
 --index manager \
 --baseDn dc=example,dc=com \
 --hostname localhost \
 --port 4444 \
 --bindDN uid=admin \
 --bindPassword password \
 --usePkcs12TrustStore /path/to/opendj/config/keystore \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --no-prompt

# Search for Torrey Ridgden's employees:
$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --usePkcs12TrustStore /path/to/opendj/config/keystore \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --baseDn dc=example,dc=com \
 "(manager:distinguishedNamePatternMatch:=uid=trigden,**)" \
 manager
...
dn: uid=bjensen,ou=People,dc=example,dc=com
manager: uid=trigden, ou=People, dc=example,dc=com
...

Notice the search filter, (manager:distinguishedNamePatternMatch:=uid=trigden,**). In DN pattern matching filters:

  • * matches a single RDN component, or a single RDN component value.

  • ** matches multiple RDN components, or a single RDN component value.

  • + is the separator for multiple attribute value assertions (AVAs) in the same RDN component, as in sn=smith+givenName=jane,ou=people,dc=example,dc=com, which matches sn=*+givenName=*,ou=people,dc=example,dc=com, for example.

For details, refer to distinguishedNamePatternMatch.