The LDAP search operation is used to retrieve all entries that match a given set of criteria (at least all entries that the requester has permission to see). It’s the only core LDAPv3 operation type that can have multiple response messages (although it is possible for an extended request or a request control to cause one or more intermediate response messages to be returned, but that’s pretty rare). The types of search response messages are:
- Search result entries. Each entry that matches the search request criteria will be returned in a separate search result entry.
- Search result references. If the server has information to suggest that other servers may also contain entries that match the search criteria, then it may return a separate search result reference for each additional search that should be issued.
- Search result done. When all appropriate search result entries and search result references have been returned, a search result done will be returned to indicate that the server is done processing the search operation.
The Search Request
RFC 4511 section 4.5.1 defines the search request protocol operation as follows:
SearchRequest ::= [APPLICATION 3] SEQUENCE { baseObject LDAPDN, scope ENUMERATED { baseObject (0), singleLevel (1), wholeSubtree (2), ... }, derefAliases ENUMERATED { neverDerefAliases (0), derefInSearching (1), derefFindingBaseObj (2), derefAlways (3) }, sizeLimit INTEGER (0 .. maxInt), timeLimit INTEGER (0 .. maxInt), typesOnly BOOLEAN, filter Filter, attributes AttributeSelection } AttributeSelection ::= SEQUENCE OF selector LDAPString -- The LDAPString is constrained to -- <attributeSelector> in Section 4.5.1.8 Filter ::= CHOICE { and [0] SET SIZE (1..MAX) OF filter Filter, or [1] SET SIZE (1..MAX) OF filter Filter, not [2] Filter, equalityMatch [3] AttributeValueAssertion, substrings [4] SubstringFilter, greaterOrEqual [5] AttributeValueAssertion, lessOrEqual [6] AttributeValueAssertion, present [7] AttributeDescription, approxMatch [8] AttributeValueAssertion, extensibleMatch [9] MatchingRuleAssertion, ... } SubstringFilter ::= SEQUENCE { type AttributeDescription, substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE { initial [0] AssertionValue, -- can occur at most once any [1] AssertionValue, final [2] AssertionValue } -- can occur at most once } MatchingRuleAssertion ::= SEQUENCE { matchingRule [1] MatchingRuleId OPTIONAL, type [2] AttributeDescription OPTIONAL, matchValue [3] AssertionValue, dnAttributes [4] BOOLEAN DEFAULT FALSE }
And the dependencies are defined elsewhere in RFC 4511 as:
LDAPDN ::= LDAPString -- Constrained to <distinguishedName> [RFC4514] LDAPString ::= OCTET STRING -- UTF-8 encoded, -- [ISO10646] characters AttributeValueAssertion ::= SEQUENCE { attributeDesc AttributeDescription, assertionValue AssertionValue } AttributeDescription ::= LDAPString -- Constrained to <attributedescription> -- [RFC4512] AssertionValue ::= OCTET STRING MatchingRuleId ::= LDAPString
So the search request protocol op is a sequence with BER type 0x63 (application class, constructed, tag number three). The elements of this sequence are rather involved, so we’ll look at each of them in detail below.
The baseObject Request Element
This element is an octet string that specifies the DN of the base entry for the search request. Only this entry and its subordinates may be returned, with the scope request element further restricting the set of entries that may be considered.
A search request may only have a single search base DN. If you wish to search below multiple base DNs, you will need to use separate searches. However, some servers allow you to specify an empty DN as the search base, treating it as superior to all other entries within the server.
The scope Request Element
This element specifies the set of entries, relative to the entry specified as the baseObject, that may be returned. It is an enumerated element, with the following possible values:
- baseObject (0) — Indicates that only the entry whose DN is provided in the baseObject element of the request will be considered. None of its subordinates will be examined.
- singleLevel (1) — Indicates that only the entries that are immediate subordinates to the baseObject entry will be considered. The base entry itself will not be considered, nor will entries more than one level beneath the base entry.
- wholeSubtree (2) — Indicates that the baseObject entry will be considered, as well as all of its subordinates to any depth.
The scope enumerated element is also defined with the “...” specifier to indicate that additional scope values may be defined. And the draft-sermersheim-ldap-subordinate-scope draft does propose such an additional scope value:
- subordinateSubtree (3) — Indicates that all subordinates to the baseObject entry will be considered, but the base entry itself will not be considered. Unfortunately, since this draft was never published as an RFC, there is no standard way to determine whether a directory server supports it. So it’s generally only recommended that you use this scope if you know for sure that the server you’re using does support it. Otherwise, it’s best to just use the wholeSubtree scope and ignore the base entry if it is included in the set of search result entries.
There is also no standard way to exclude portions of the DIT from the search scope. Some servers may provide some way to accomplish this (for example, the Ping Identity Directory Server offers an exclude branch request control that can be used for this purpose), but, again, the best way to achieve this in the general case is to simply use the smallest scope that includes all of the entries you might want, and ignore any search result entries in a portion of the DIT that you don’t care about.
The derefAliases Request Element
This element specifies how the server should treat alias entries that it may encounter during processing. Alias entries are described in RFC 4512 section 2.6, but they’re kind of like the LDAP equivalent of a UNIX symbolic link in that they can make it look like an entry exists in more than one location in the DIT. An alias entry has an object class of alias, and the aliasedObjectName attribute specifies the DN of the entry to which it refers.
The act of following an alias to the entry that it references is called dereferencing that alias. The derefAliases element is an enumerated element with the following possible values:
- neverDerefAliases (0) — Indicates that the server should not dereference any aliases that it may encounter when processing the search operation.
- derefInSearching (1) — Indicates that the server should dereference any aliases that it encounters within the scope of the search, except for the base entry itself. If an entry referenced by an alias within the scope of the search matches the search filter, then that entry will be returned. If the scope is wholeSubtree or subordinateSubtree, then the server will also be evaluated against any subordinates of the referenced entry.
- derefFindingBaseObj (2) — Indicates that the server should only dereference the entry specified by the baseObject element of the request. If that base entry is an alias, then the search will be processed as if the referenced entry had been specified as the search base entry.
- derefAlways (3) — Indicates that the server should not dereference any aliases encountered within the scope of the search. If the base entry is an alias, then it will be treated in the same way as if derefFindingBaseObj had been used. And if there are any other alias entries within the scope of the search, they will be treated in the same way as if derefInSearching had been used.
Alias entries can only be leaf entries, so it is not possible to have any kind of entry below an alias entry. However, an alias entry can reference either a leaf entry or a non-leaf entry, and it is possible to add subordinate entries below an entry referenced by one or more alias entries. It is also possible for an alias entry to reference another alias entry, so the act of dereferencing an alias may require multiple hops to reach the final entry. Further, servers that support aliases must also be able to detect circular references between alias entries.
Aliases will only be dereferenced when processing search requests, and only in accordance with the derefAliases element. Any other operation that targets an alias entry will operate on that entry directly rather than on the entry that it references.
Aliases are an optional element of the LDAPv3 specification, and not all LDAP servers support them.
The sizeLimit Request Element
This element specifies the maximum number of entries that should be returned in response to the search request. It is an integer element, and its value must be greater than or equal to zero. A value of zero indicates that no size limit is requested, and a value greater than zero will be treated as the requested maximum size limit.
Note that directory servers often impose their own size limit for client requests. There may be a global limit in effect for all users, and it may be possible to define a custom size limit for individual users or for subsets of clients (e.g., based on the address of the client, the type of authentication the client performed, whether the client connection is secure, the set of groups in which the client is a member, etc.). In such cases, the server will generally use the smaller of its own size limit and the one included in the search request.
In the event that the search request criteria matches more entries than allowed by the enforced size limit, the server will return a search result done message with a result code of sizeLimitExceeded (4). It may optionally return a portion of the search result entries before sending that search result done message, but should never return more than the maximum allowed number of entries.
The timeLimit Request Element
This element specifies the maximum length of time, in seconds, that the server should spend processing the request. It is an integer element, and its value must be greater than or equal to zero. A value of zero indicates that no time limit is requested, and a value greater than zero will be treated as the requested maximum time limit.
As with the size limit, the requested time limit may be overridden by the server to impose a smaller limit than the one requested by the client. And also like the sizeLimit element, the server may or may not return a subset of the matching entries before the time limit is reached. The timeLimitExceeded (3) result code is used to indicate that a search ended prematurely because the time limit was reached before processing could complete.
Many LDAP clients also impose a client-side time limit, which represents the maximum amount of time they will spend waiting for a response from the server. That client-side time limit isn’t communicated to the server (although for a search operation, it’s often the same as the timeLimit value included in the search request), and if the server hasn’t sent a response by that time, the client will often give up, possibly abandon the request, and fail the operation with the client-side timeout (85) result code.
The typesOnly Request Element
This element indicates whether search result entries should only include attribute descriptions (attribute type names or OIDs, followed by zero or more attribute options), rather than both attribute descriptions and values. This is a Boolean element, and if it has a value of true, then search result entries will include the appropriate set of attributes, but all of them will have zero values. If it has a value of false, then attributes included in search result entries will include all of their values (or at least all of the values that the client has permission to access).
The typesOnly element must be included in the search request, but it is virtually always provided with a value of false. About the only case in which you would use with a value of true is if you want to see which attributes are present in the entry, but you don’t care about what their values are. And even then, the only case in which there’s any significant benefit to omitting the attribute values from the search result entry is if you think that one or more of those attributes might have a lot of values.
The baseObject Request Element
This element provides the criteria that entries within the scope of the search must match in order to be returned to the client. There are ten types of search filters, each of which has a slightly different encoding (if for no other reason than the BER type used to indicate which type of filter it is). The filter element itself is a CHOICE between one of the following filter types.
The present Filter Type
A present filter (also known as a presence filter) will match any entry that contains at least one value for a specified attribute. It is encoded as a simple octet string with type 0x87 (context-specific class, primitive, tag number seven) whose value is the target attribute description. For example, the encoding for the present filter with string representation (uid=*) is:
87 03 75 69 64 -- The octet string "uid" with type context-specific primitive seven
The equalityMatch Filter Type
An equalityMatch filter (also known as an equality filter) will match any entry that contains a given value for an attribute with a specified attribute description. It is encoded as an AttributeValueAssertion, which is a sequence (with type 0xa3, context-specific class, constructed, tag number three) containing two octet strings: the first being the attribute description, and the second the assertion value. For example, the encoding for the equalityMatch filter with string representation (uid=jdoe) is:
a3 0b -- Begin the AttributeValueAssertion sequence with type -- context-specific constructed three 04 03 75 69 64 -- The attribute description (octet string "uid") 04 04 6a 64 6f 65 -- The assertion value (octet string "jdoe")
The greaterOrEqual Filter Type
A greaterOrEqual filter will match any entry that contains at least one value for a specified attribute that is greater than or equal to a given value. Its encoding is very similar to that of the equalityMatch filter, except that it has a BER type of 0xa5 (context-specific class, constructed, tag number five). For example, the encoding for the greaterOrEqual filter with string representation (createTimestamp&tt;=20170102030405.678Z) is:
a5 26 -- Begin the AttributeValueAssertion sequence with type -- context-specific constructed five 04 0f 63 72 65 61 74 65 54 69 -- The attribute description 6d 65 73 74 61 6d 70 -- (octet string "createTimestamp") 04 13 32 30 31 37 30 31 30 32 -- The assertion value 30 33 30 34 30 35 2e 36 -- (octet string "20170102030405.678Z") 37 38 5a
The lessOrEqual Filter Type
A lessOrEqual filter is the same as a greaterOrEqual filter, except that it will match any entry that contains at least one value that is less than or equal to a given value rather than at least one value that is greater than or equal to a given value. Its encoding is also the same as the encoding for the greaterOrEqual filter type, except that it has a BER type of 0xa6 (context-specific class, constructed, tag number six) rather than 0xa5. For example, the encoding for a lessOrEqual filter with string representation (accountBalance<=1234) is:
a6 16 -- Begin the AttributeValueAssertion sequence with type -- context-specific constructed six 04 0e 61 63 63 6f 75 6e 74 42 -- The attribute description 61 6c 61 6e 63 65 -- (octet string "accountBalance") 04 04 31 32 33 34 -- The assertion value (octet string "1234")
The approximateMatch Filter Type
An approximateMatch filter can be used to match any entry that has a specified attribute with at least one value that is approximately equal to a given value. Official LDAP specifications are vague as to what exactly “approximately equal to” means, and leave it up to the individual server implementations. Many servers use a “sounds like” algorithm (e.g., soundex or one of the metaphone variants), at least for attributes with a string syntax, but it’s possible for other logic to be used (for example, if an attribute’s numeric value is close to the provided value).
As with the equalityMatch, greaterOrEqual, and lessOrEqual filter types, the approximateMatch filter type is encoded as an AttributeValueAssertion. It has a BER type of 0xa8 (context-specific class, constructed, tag number eight).
For example, the encoding for the approximateMatch filter with string representation (givenName~=John) is:
a8 11 -- Begin the AttributeValueAssertion sequence with type -- context-specific constructed eight 04 09 67 69 76 65 6e 4e 61 6d -- The attribute description 65 -- (octet string "givenName") 04 04 4a 6f 68 6e -- The assertion value (octet string "John")
The substrings Filter Type
The substrings filter (also called a substring filter) can be used to match an that has a specified attribute with at least one value that matches a provided substring assertion. The substring assertion can contain one or more of the following components:
- An initial component (sometimes called subInitial), which will match a value that starts with a specified string.
- An any component (sometimes called subAny), which will match a value that contains a specified string.
- A final component (sometimes called subFinal), which will match a value that ends with a specified string.
Since a string can only contain one beginning and one end, there can be at most one initial component and at most one final component, but there can be any number of any components.
The substrings filter type has a BER type of 0xa4 (context-specific class, constructed, tag number four) and the following encoding:
SubstringFilter ::= SEQUENCE { type AttributeDescription, substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE { initial [0] AssertionValue, -- can occur at most once any [1] AssertionValue, final [2] AssertionValue } -- can occur at most once }
For example, the substrings filter with string representation (cn=abc*) is encoded as:
a4 0b -- Begin the SubstringFilter sequence with type -- context-specific constructed four 04 02 63 6e -- The attribute description (octet string "cn") 30 05 -- Begin the substrings sequence 80 03 61 62 63 -- The initial element (octet string "abc") with type -- context-specific primitive zero
The substrings filter with string representation (cn=*lmn*) is encoded as:
a4 0b -- Begin the SubstringFilter sequence with type -- context-specific constructed four 04 02 63 6e -- The attribute description (octet string "cn") 30 05 -- Begin the substrings sequence 81 03 6c 6d 6e -- The any element (octet string "lmn") with type -- context-specific primitive one
The substrings filter with string representation (cn=*xyz) is encoded as:
a4 0b -- Begin the SubstringFilter sequence with type -- context-specific constructed four 04 02 63 6e -- The attribute description (octet string "cn") 30 05 -- Begin the substrings sequence 82 03 78 79 7a -- The final element (octet string "xyz") with type -- context-specific primitive two
The substrings filter with string representation (cn=abc*def*lmn*uvw*xyz) is encoded as:
a4 1f -- Begin the SubstringFilter sequence with type -- context-specific constructed four 04 02 63 6e -- The attribute description (octet string "cn") 30 19 -- Begin the substrings sequence 80 03 61 62 63 -- The initial element (octet string "abc") with type -- context-specific primitive zero 81 03 64 65 66 -- The first any element (octet string "def") with type -- context-specific primitive one 81 03 6c 6d 6e -- The second any element (octet string "lmn") with type -- context-specific primitive one 81 03 75 76 77 -- The third any element (octet string "uvw") with type -- context-specific primitive one 82 03 78 79 7a -- The final element (octet string "xyz") with type -- context-specific primitive two
The extensibleMatch Filter Type
An extensibleMatch filter provides a substantial amount of flexibility when performing matching against an entry. The filter can contain the following four elements:
- A matchingRule element, which specifies the name or OID of the matching rule that should be used. This is an optional element, and if it is absent, then an attribute description must be specified, and the search will use the equality matching rule for that attribute.
- A type element, which specifies the attribute description for the attribute to target. This is an optional element, and if it is absent, then a matching rule must be specified, and the search will be evaluated against any attribute in the entry for which that matching rule may be used.
- A dnAttributes element, which indicates whether to perform matching against attribute-value pairs included in the entry’s DN. If this element is present with a value of true, then the filter will match an entry in which any of the attribute values matches the assertion, or in which any of the attribute values that make up any component of the DN matches the assertion. Otherwise, the filter will only be evaluated against the entry attributes but not those attribute values included in its DN (except for the attribute values in the RDN, which will also be in the entry attributes).
- A matchValue element, which is the assertion value for the search. This must always be provided.
The extensibleMatch filter type has a BER type of 0xa9 (context-specific class, constructed, tag number nine) and the following encoding:
MatchingRuleAssertion ::= SEQUENCE { matchingRule [1] MatchingRuleId OPTIONAL, type [2] AttributeDescription OPTIONAL, matchValue [3] AssertionValue, dnAttributes [4] BOOLEAN DEFAULT FALSE }
For example, the extensibleMatch filter with string representation (uid:=jdoe) is:
a9 0b -- Begin the MatchingRuleAssertion sequence with type -- context-specific constructed nine 82 03 75 69 64 -- The attribute description (octet string "uid" with type -- context-specific primitive two) 83 04 6a 64 6f 65 -- The assertion value (octet string "jdoe" with type -- context-specific primitive three
The extensibleMatch filter with string representation (:caseIgnoreMatch:=foo) is:
a9 16 -- Begin the MatchingRuleAssertion sequence with type -- context-specific constructed nine 81 0f 63 61 73 65 49 67 6e 6f -- The matching rule ID (octet string 72 65 4d 61 74 63 68 -- "caseIgnoreMatch" with type -- context-specific primitive one) 83 03 66 6f 6f -- The assertion value (octet string "foo" with type -- context-specific primitive three
The extensibleMatch filter with string representation (uid:dn:caseIgnoreMatch:=jdoe) is:
a9 1f -- Begin the MatchingRuleAssertion sequence with type -- context-specific constructed nine 81 0f 63 61 73 65 49 67 6e 6f -- The matching rule ID (octet string 72 65 4d 61 74 63 68 -- "caseIgnoreMatch" with type 82 03 75 69 64 -- The attribute description (octet string "uid" with type -- context-specific primitive two) 83 04 6a 64 6f 65 -- The assertion value (octet string "jdoe" with type -- context-specific primitive three 84 01 ff -- The dnAttributes flag (boolean true)
The and Filter Type
An and filter encapsulates some number of other filters and will only match an entry if all of the encapsulated filters match that entry. It is encoded as a set with BER type 0xa0 (context-specific class, constructed, tag number zero) in which each of the elements is the encoded representation of an encapsulated filter.
For example, the encoded representation of the and filter with string representation (&(givenName=John)(sn=Doe)) is:
a0 1e -- Begin the and set with type context-specific constructed zero a3 11 -- Begin the AttributeValueAssertion sequence with type -- context-specific constructed three 04 09 67 69 76 65 6e 4e 61 6d -- The attribute description 65 -- (octet string "givenName") 04 04 4a 6f 68 6e -- The assertion value (octet string "John") a3 09 -- Begin the AttributeValueAssertion sequence with type -- context-specific constructed three 04 02 73 6e -- The attribute description (octet string "sn") 04 03 44 6f 65 -- The assertion value (octet string "Doe")
RFC 4511 section 4.5.1 defines the and filter type with a constraint of SIZE (1..MAX), indicating that the and filter must encapsulate at least one filter component. However, RFC 4526 defines an absolute true filter, which is an and filter that encapsulates zero components and will always match any entry. Servers that support absolute true filters will advertise that with a value of 1.3.6.1.4.1.4203.1.5.3 in the supportedFeatures attribute of their root DSE. An absolute true filter has a string representation of (&) is encoded as:
a0 00 -- An empty and set with type context-specific constructed zero
The or Filter Type
An or filter encapsulates some number of other filters and will only match an entry if at least one of the encapsulated filters matches that entry. It is encoded as a set with BER type 0xa1 (context-specific class, constructed, tag number one), in which each of the elements is the encoded representation of an encapsulated filter.
For example, the encoded representation of the or filter with string representation (|(givenName=John)(givenName=Jonathan)) is:
a1 2a -- Begin the or set with type context-specific constructed one a3 11 -- Begin the AttributeValueAssertion sequence with type -- context-specific constructed three 04 09 67 69 76 65 6e 4e 61 6d -- The attribute description 65 -- (octet string "givenName") 04 04 4a 6f 68 6e -- The assertion value (octet string "John") a3 15 -- Begin the AttributeValueAssertion sequence with type -- context-specific constructed three 04 09 67 69 76 65 6e 4e 61 6d -- The attribute description 65 -- (octet string "givenName") 04 08 4a 6f 6e 61 74 68 61 6e -- The assertion value (octet string "Jonathan")
Just as RFC 4526 defines an absolute true filter that is an and filter with zero elements that will always match any entry, it also defines an absolute false filter that is an or filter with zero elements that will never match any entry. An absolute false filter has a string representation of (|) and is encoded as:
a1 00 -- An empty or set with type context-specific constructed one
The not Filter Type
A not filter encapsulates exactly one filter (which may be any kind of filter, including an and or or filter that combines multiple other filters) and inverts the result obtained from evaluating the encapsulated filter against an entry. So a not filter will only match an entry if the encapsulated filter does not match that entry.
A not filter has a BER type of 0xa2 (context-specific class, constructed, tag number two) and its value is the encoded representation of the filter that it encapsulates. For example, the not filter with string representation (!(givenName=John)) would be encoded as:
a2 13 -- Begin the not filter with type context-specific constructed two a3 11 -- Begin the AttributeValueAssertion sequence with type -- context-specific constructed three 04 09 67 69 76 65 6e 4e 61 6d -- The attribute description 65 -- (octet string "givenName") 04 04 4a 6f 68 6e -- The assertion value (octet string "John")
The attributes Request Element
This element specifies the set of attributes that the client wants to have included in search result entries. It is encoded as a sequence of zero or more octet string values. If the sequence is empty, then the server will assume that the client wants to retrieve all user attributes. If there are one or more octet strings in the sequence, then they may include any number of the following:
- An attribute description (the name or OID of an attribute, followed by zero or more attribute options) for an attribute that the client wants to be included. The attribute description may refer to a user attribute or an operational attribute. If the target attribute type has subordinate types, then this implicitly requests those subordinate types as well.
- An asterisk (*), to indicate that the client wants to retrieve all user attributes. If the asterisk is the only element in the requested attribute sequence, then it’s equivalent to leaving the sequence empty, but it’s often combined with one or more other options that will cause operational attributes to be returned.
- A plus sign (+), to indicate that the client wants to retrieve all operational attributes. This feature is described in RFC 3673, and not all servers support this ability. Servers that do support it will include OID 1.3.6.1.4.1.4203.1.5.1 as a value in the supportedFeatures attribute of the root DSE. For servers that do not, clients will need to explicitly name all of the operational attributes they want to retrieve.
- An at sign (@) immediately followed by the name of an object class (for example, @inetOrgPerson) to indicate that the client wants to retrieve all attributes associated with the specified object class. This behavior is described in RFC 4529, and if a server supports it, then its root DSE will include a supportedFeatures value of 1.3.6.1.4.1.4203.1.5.2.
Example Encoded Search Request Message
As an example, consider a search request protocol operation with the following settings:
- A base DN of dc=example,dc=com
- A scope of wholeSubtree
- An alias dereferencing policy of neverDerefAliases
- A size limit of 1000 entries
- A time limit of 30 seconds
- A typesOnly value of false
- A filter of (&(objectClass=person)(uid=jdoe))
- A requested attribute set of * and + (to request all user and all operational attributes)
A search request with message ID two, no controls, and the above search request protocol op would be encoded as follows:
30 56 -- Begin the LDAPMessage sequence 02 01 02 -- The message ID (integer value 2) 63 51 -- Begin the search request protocol op 04 11 64 63 3d 65 78 61 6d 70 -- The search base DN 6c 65 2c 64 63 3d 63 6f -- (octet string "dc=example,dc=com") 6d 0a 01 02 -- The wholeSubtree scope (enumerated value 2) 0a 01 00 -- The neverDerefAliases policy (enumerated value 0) 02 02 03 e8 -- The size limit (integer value 1000) 02 01 1e -- The time limit (integer value 30) 01 01 00 -- The typesOnly flag (boolean false) a0 24 -- Begin an and filter a3 15 -- Begin an equality filter 04 0b 6f 62 6a 65 63 74 43 6c -- The attribute description 61 73 73 -- (octet string "objectClass") 04 06 70 65 72 73 6f 6e -- The assertion value (octet string "person") a3 0b -- Begin an equality filter 04 03 75 69 64 -- The attribute description (octet string "uid") 04 04 6a 64 6f 65 -- The assertion value (octet string "jdoe") 30 06 -- Begin the set of requested attributes 04 01 2a -- Request all user attributes (octet string "*") 04 01 2b -- Request all operational attributes (octet string "+")
The Search Result Entry Response
The server will send a search result entry message for each entry that it wants to return to the client. RFC 4511 section 4.5.2 defines the search result entry protocol operation as:
SearchResultEntry ::= [APPLICATION 4] SEQUENCE { objectName LDAPDN, attributes PartialAttributeList } PartialAttributeList ::= SEQUENCE OF partialAttribute PartialAttribute
And its dependencies from elsewhere in RFC 4511:
LDAPDN ::= LDAPString -- Constrained to[RFC4514] LDAPString ::= OCTET STRING -- UTF-8 encoded, -- [ISO10646] characters PartialAttribute ::= SEQUENCE { type AttributeDescription, vals SET OF value AttributeValue } AttributeDescription ::= LDAPString -- Constrained to -- [RFC4512] AttributeValue ::= OCTET STRING
This means that a search result entry is basically encoded in the same way as an add request, but with two differences: the BER type for a search result entry is 0x64 (application class, constructed, tag number four), and a search result entry can have attributes with zero values (if the search request included a typesOnly value of true).
For example, consider the entry:
dn: dc=example,dc=com objectClass: top objectClass: domain dc: example
A search result entry message for that entry would be encoded as:
30 49 -- Begin the LDAPMessage sequence 02 01 02 -- The message ID (integer value 2) 64 44 -- Begin the search result entry protocol op 04 11 64 63 3d 65 78 61 6d 70 -- The entry DN 6c 65 2c 64 63 3d 63 6f -- (octet string "dc=example,dc=com") 6d 30 2f -- Begin the sequence of attributes 30 1c -- Begin the first attribute sequence 04 0b 6f 62 6a 65 63 74 43 6c -- The attribute description 61 73 73 -- (octet string "objectClass") 31 0d -- Begin the set of objectClass values 04 03 74 6f 70 -- The first value (octet string "top") 04 06 64 6f 6d 61 69 6e -- The second value (octet string "domain") 30 0f -- Begin the second attribute sequence 04 02 64 63 -- The attribute description (octet string "dc") 31 09 -- Begin the set of dc values 04 07 65 78 61 6d 70 6c 65 -- The value (octet string "example")
If the search request had included a typesOnly value of true to indicate that the attributes should be returned without values, then the entry would be encoded as follows:
30 33 -- Begin the LDAPMessage sequence 02 01 02 -- The message ID (integer value 2) 64 2e -- Begin the search result entry protocol op 04 11 64 63 3d 65 78 61 6d 70 -- The entry DN 6c 65 2c 64 63 3d 63 6f -- (octet string "dc=example,dc=com") 6d 30 19 -- Begin the sequence of attributes 30 0f -- Begin the first attribute sequence 04 0b 6f 62 6a 65 63 74 43 6c -- The attribute description 61 73 73 -- (octet string "objectClass") 31 00 -- The empty value set 30 06 -- Begin the second attribute sequence 04 02 64 63 -- The attribute description (octet string "dc") 31 00 -- The empty value set
The SearchResult Reference Response
A search result reference can be used to indicate that the client should issue the search request elsewhere against other servers or another portion of the DIT. A single search request can return any number of search result references.
RFC 4511 section 4.5.2 defines the search result reference protocol operation as:
SearchResultReference ::= [APPLICATION 19] SEQUENCE SIZE (1..MAX) OF uri URI
And its dependencies from elsewhere in RFC 4511:
URI ::= LDAPString -- limited to characters permitted in -- URIs LDAPString ::= OCTET STRING -- UTF-8 encoded, -- [ISO10646] characters
That is, a search result reference is a sequence with BER type 0x73 (application class, constructed, tag number nineteen) with one or more octet string elements that represent the referral URIs (which are usually LDAP URLs, as described in RFC 4516).
For example, consider a search result reference with the following two LDAP URLs:
- ldap://ds1.example.com:389/dc=example,dc=com??sub?
- ldap://ds2.example.com:389/dc=example,dc=com??sub?
The encoded representation of that search result reference is:
30 6d -- Begin the LDAPMessage sequence 02 01 02 -- The message ID (integer value 2) 73 68 -- Begin the search result reference protocol op 04 32 6c 64 61 70 3a 2f 2f 64 -- The first referral URI (octet string "ldap:// 73 31 2e 65 78 61 6d 70 -- ds1.example.com:389/dc=example,dc=com??sub?") 6c 65 2e 63 6f 6d 3a 33 38 39 2f 64 63 3d 65 78 61 6d 70 6c 65 2c 64 63 3d 63 6f 6d 3f 3f 73 75 62 3f 04 32 6c 64 61 70 3a 2f 2f 64 -- The second referral URI (octet string "ldap:// 73 32 2e 65 78 61 6d 70 -- ds2.example.com:389/dc=example,dc=com??sub?") 6c 65 2e 63 6f 6d 3a 33 38 39 2f 64 63 3d 65 78 61 6d 70 6c 65 2c 64 63 3d 63 6f 6d 3f 3f 73 75 62 3f
The Search Result Done Response
When the server has finished all processing for a search operation and has returned all appropriate entries and references, it will send a search result done message to indicates that the search is complete. RFC 4511 section 4.5.2 defines the search result done protocol operation as:
SearchResultDone ::= [APPLICATION 5] LDAPResult
That is, it’s an LDAPResult (which we’ve discussed in an earlier section) with a BER type of 0x65 (application class, constructed, tag number five). A successful search result done response is encoded as follows:
30 0c -- Begin the LDAPMessage sequence 02 01 02 -- The message ID (integer value 2) 65 07 -- Begin the search result done protocol op 0a 01 00 -- success result code (enumerated value 0) 04 00 -- No matched DN (0-byte octet string) 04 00 -- No diagnostic message (0-byte octet string)
Previous: The LDAP Modify DN Operation | Next: The LDAP Unbind Operation |