All LDAPv3 requests and responses are encapsulated in a BER sequence called an LDAP message. This is defined as follows in RFC 4511 section 4.1.1:
LDAPMessage ::= SEQUENCE { messageID MessageID, protocolOp CHOICE { bindRequest BindRequest, bindResponse BindResponse, unbindRequest UnbindRequest, searchRequest SearchRequest, searchResEntry SearchResultEntry, searchResDone SearchResultDone, searchResRef SearchResultReference, modifyRequest ModifyRequest, modifyResponse ModifyResponse, addRequest AddRequest, addResponse AddResponse, delRequest DelRequest, delResponse DelResponse, modDNRequest ModifyDNRequest, modDNResponse ModifyDNResponse, compareRequest CompareRequest, compareResponse CompareResponse, abandonRequest AbandonRequest, extendedReq ExtendedRequest, extendedResp ExtendedResponse, ..., intermediateResponse IntermediateResponse }, controls [0] Controls OPTIONAL }
As you can see, an LDAP message contains three components: a message ID, a protocol operation, and an optional set of controls. We will look at each of these in more detail in the following sections.
The messageID element of an LDAPMessage sequence is used to correlate requests and responses.
Whenever a client sends a request to the directory server, it chooses the message ID for that request. All of the messages that the server returns in response to that request will have the same message ID as the request. This allows LDAP to operate as an asynchronous protocol, where a single client connection can have multiple outstanding requests at a time. This can allow multiple application threads to share the same connection. It can also allow a single thread to submit multiple requests at the same time, as long as the content of one request doesn't depend on the response from another of the requests being submitted.
The messageID type is defined alongside the LDAPMessage sequence in RFC 4511 section 4.1.1. That definition is:
MessageID ::= INTEGER (0 .. maxInt) maxInt INTEGER ::= 2147483647 -- (2^^31 - 1) --
That is, the messageID component of an LDAPMessage sequence is an integer between 0 and 2,147,483,647 (although message ID zero is reserved for a special type of message called an unsolicited notification, which is a message that the server sends to the client without any corresponding request). When sending a request, the client must choose a message ID between 1 and 2,147,483,647 that is not already in use by any outstanding request on that connection (and ideally, that has not also been used by any recently-abandoned request). A client will typically maintain a counter that is incremented for each request so that there will be over two billion requests before a message ID needs to be reused.
The protocolOp element of an LDAPMessage sequence provides the main content of the request or response. It encapsulates all of the details about the request or response, and therefore its format varies based on the content of that request or response. For example, a DeleteRequest protocol operation includes the DN of the entry to delete, while a SearchRequest protocol operation includes elements that specify the base DN, scope, filter, and other components of the search request.
We'll look at each type of protocolOp element in detail in subsequent sections.
An LDAPMessage sequence may optionally include a set of controls that provide additional information about the operation.
If a control is included in a request, then it may provide additional information about how the server should process that request. For example, an LDAP message that contains a search request protocol operation may also include a server-side sort request control to indicate that the client wants the server to return the results to the client in a particular order.
If a control is included in a response, then it may provide additional information to the client about the way that the operation was processed. Response controls are often (but not always) triggered by a corresponding request control. For example, if a search request message includes a server-side sort request control, then the corresponding search result done message may include a server-side sort response control with information about whether it was able to successfully sort the results.
The Controls type is defined in RFC 4511 section 4.1.11, as:
Controls ::= SEQUENCE OF control Control Control ::= SEQUENCE { controlType LDAPOID, criticality BOOLEAN DEFAULT FALSE, controlValue OCTET STRING OPTIONAL }
The LDAPOID type is defined in RFC 4511 section 4.1.2 as:
LDAPOID ::= OCTET STRING -- Constrained to <numericoid> -- [RFC4512]
That is, if the optional controls element is present in an LDAPMessage, then it will be a sequence of sequences, each of which contains up to three elements. Those elements are:
Even though we haven't yet gone into any detail on any of the different types of protocol operations or controls, it may still be helpful to provide an example of an encoded LDAP message. We'll provide many more examples in later sections, but we'll start here with a simple one: an LDAP message with a message ID of five that requests deleting the dc=example,dc=com entry and includes a subtree delete request control to indicate that the server should also remove any entries that exist below the target entry.
The delete request protocol operation is defined as follows in RFC 4511 section 4.8:
DelRequest ::= [APPLICATION 10] LDAPDN
where LDAPDN is defined in RFC 4511 section 4.1.3 as:
LDAPDN ::= LDAPString -- Constrained to <distinguishedName> [RFC4514]
and LDAPString is defined in RFC 4511 section 4.1.2 as:
LDAPString ::= OCTET STRING -- UTF-8 encoded, -- [ISO10646] characters
So basically, a delete request protocol operation is simply encoded as an octet string with a BER type of application-specific ten (0x4a) whose value is the string representation of the DN of the entry to delete.
A subtree delete request control is defined in draft-armijo-ldap-treedelete. In this specification, the control has an OID of “1.2.840.113556.1.4.805” and no value. The draft states that the criticality may be either true or false, so in this case we'll make it true so that the operation will fail if the server can’t process the subtree delete, which will allow us to differentiate between a problem in the server's support for the subtree delete control and some other problem in processing.
With all of this in mind, the encoded representation of the LDAP message containing the delete request described above is:
30 35 02 01 05 4a 11 64 63 3d 65 78 61 6d 70 6c 65 2c 64 63 3d 63 6f 6d a0 1d 30 1b 04 16 31 2e 32 2e 38 34 30 2e 31 31 33 35 35 36 2e 31 2e 34 2e 38 30 35 01 01 ff
And here's a formatted version with comments to make it easier to interpret. For subsequent sections, only the formatted representation will be provided.
30 35 -- Begin the LDAPMessage sequence 02 01 05 -- The message ID (integer value 5) 4a 11 64 63 3d 65 78 61 6d 70 -- The delete request protocol op 6c 65 2c 64 63 3d 63 6f -- (octet string 6d -- dc=example,dc=com) a0 1d -- Begin the sequence for the set of controls 30 1b -- Begin the sequence for the first control 04 16 31 2e 32 2e 38 34 30 2e -- The control OID 31 31 33 35 35 36 2e 31 -- (octet string 2e 34 2e 38 30 35 -- 1.2.840.113556.1.4.805) 01 01 ff -- The control criticality (Boolean true)
Previous: The ASN.1 Basic Encoding Rules | Next: The LDAPResult Sequence |