|< Day Day Up >|| |
The information model and the naming model describe the elements and the structure of the directory, respectively. The functional model describes the operations that can be performed on the directory.
At this point, it is useful to remember that LDAP is a protocol that mediates the messages sent between client and server. The client sends a message to the server requesting a certain action against the directory. The server then executes this action on behalf the client, sending a message back to the client containing the result code and the eventual results sets. Like every object class, attribute type, syntax, or matching rule, each of the operations requested in the messages also has a unique object identifier (OID). Thus the LDAP standard as defined in the RFC2251 describes the nature of the requests that the client can send to the server. Upon receipt of each request, the server then executes a response operation. How these operations are implemented in the server is not the subject of the LDAP standard. This decision is left to the vendor or to the organization implementing the directory server. Nevertheless, we will call these requests "functions" or "operations." This is the (lazy) terminology you will find in literature. Bear in mind that we are not really speaking of functions or methods in the sense of a programming language. It is the work of the programmers writing APIs to offer functions or methods etc. to the application programmer. With this in mind, you will understand the difference between the messages (alias "functions" and "operations") presented herein and the APIs treated in Chapter 6.
There are three groups of functions, plus one special group of the "extended operations." This group is new in version 3 of LDAP and has been defined in RFC 2251, "Lightweight Directory Access Protocol (v3)." The "extended operations" allow adding further functionality published in the form of RFCs or in private implementations. For example, the "StartTLS" (Transport Layer Security protocol) operation, not foreseen in RFC 2251, is an operation defined with an extended operation. The StartTLS operation is defined in RFC 2830, "Lightweight Directory Access Protocol (v3): Extension for Transport Layer Security." The StartTLS operation requests the server to begin the procedure for negotiating the security protocol to be used for securing the following LDAP session. We will learn more about this when we discuss the security model in the next section. You will also hear more about this in Chapter 7, "LDAP Directory Server Administration." The extended operations provide a high degree of flexibility for the LDAP protocol, which can be further extended in the future without changing the protocol definition as provided so far by the RFCs.
There is also another group of operations called "unsolicited notification." The unsolicited notification is a message sent from the server to the client in an extraordinary condition. At the time of this writing, there is only one of these unsolicited notifications, the "notice of disconnection." It occurs when, for some particular error condition, the LDAP server closes the connection.
But now let us get back to the three groups of operations. In this chapter we will learn what these operations are used for and then discuss each operation's functionality in greater detail. We will not examine the syntax of the various operations because this is implementation dependent, i.e., it depends of the directory client and the API you are using.
There are three types of operations:
Interrogation operations: search, compare
Update operations: add, delete, modify DN, modify
Authentication and control operations : bind, unbind, abandon
All of these operations are requests made by an LDAP client to an LDAP server. The server executes the requested operation and sends back to the client the result plus an error code.
There are two interrogation operations: "search" and "compare."
"Search" looks up a part of the directory for entries matching a condition specified by a filter. It is possible to specify how deep the search should traverse the directory information tree (DIT), the point in the DIT where the server should start searching, and a time limit for the server's search through the entries. Furthermore you specify what attributes a query will return.
"Compare" does the same thing as "search" in that it searches the directory to find a match to an entry. However, in contrast to "search," it does not return any element, reporting only "true" if it found any entry and "false" if it did not. The "compare" operation remains from X.500 and could be managed by search also, except in one special case: when "search" is asked to return all entries matching a certain attribute and it comes back without a result. There can be two distinct reasons for this: The attribute in the entry does not match the one you searched, or the attribute has no value at all. In both cases, "search" returns the same result value, i.e., nothing. "Compare" instead returns a special value if the attribute does not exist at all.
Note that there is no read or iteration operation. These operations can be achieved by configuring the search filter appropriately.
The LDAP protocol has four update operations: "add," "delete," "modify DN," and "modify." The "add" operation simply adds a new entry to the directory. The "delete" operation deletes an entry. The "modify DN" operation modifies an entry. (In version 3, this includes modification of the distinguished name, which removes the entry from its old parent entry and inserts it into a new one. In version 2, it modifies only the relative distinguished name.) The "modify" operation modifies or deletes one or more attributes of an entry.
LDAP has two authentication operations ("bind" and "unbind") and one control operation ("abandon"). The "bind" operation allows a user to connect to a directory server. This is an authentication operation because the user delivers userID and userPassword. The server controls the user credentials and gives access or returns an error code. "Unbind" finishes the connection. The "abandon" operation interrupts the connection between client and server.
Now that we know what operations the LDAP recognizes, we can review the previously mentioned operations in detail. It is important to understand them, since all software development kits rely on these operations. Once you have a clear understanding of what the directory server requests on behalf of these operations, you will have no problem in understanding the different APIs available.
One further note to these operations: All are atomic. This is important for some operations. "Atomic" means that an operation is executed as a whole or is aborted if an error occurs.
Consider an example: You want to update an entry changing more than one attribute. An atomic operation is either updated completely or it is aborted, with an error message sent to the user. If the update operation is completed, then all attributes of the entry you requested to be updated have been updated. You will not have some attributes updated and others not. This holds not only for the "update" operation, but also for the "add" and "delete" operations.
The most complicated operation is the search operation. It can have up to eight parameters: base, scope, derefAliases, sizeLimit, timeLimit, attrOnly, searchFilter, and attributeList:
Base: DN where the query should start
Scope: Extension of the query inside the directory information tree. The scope can have three different values:
baseObject: Limits the search to the base object only. (See Exhibit 26.)
Exhibit 26: Search, scope = baseObject
singleLevel: Limits the search to the base objects and the immediate children. (See Exhibit 27.)
Exhibit 27: Search, scope = singleLevel
wholeSubtree: Extends the search to the entire subtree from the base object. (See Exhibit 28.)
Exhibit 28: Search, scope = wholeSubtree
derefAliases: Indicates how alias dereferencing should be handled. Aliases are used as symbolic links in a file system. Instead of containing an entry, the corresponding leaf contains an object of a particular object class, the object class "alias," which points to the entry containing the data. Chapter 4 discusses aliases in greater detail. This parameter describes how the client should behave if it retrieves an alias, and it can have one of four values:
neverDerefAliases: No dereferencing of aliases at all
derefInSearching: Dereferences aliases in subordinates of the base object in searching, but not in locating the base object of the search
derefFindingBaseObj: Dereferences aliases in locating the base object of the search, but not when searching subordinates of the base object
derefAlways: Dereferences aliases both in searching and in locating the base object of the search
sizeLimit: Maximum number of entries a query will return. A number of "zero" means that there is no size limit. The server can impose a maximum number for this entry.
timeLimit: Maximum number of seconds a query can take. A number of "zero" means that the client does not impose any time limit.
attrOnly: A Boolean value. Set to "true," it indicates that only attribute types are returned; set to "false," it returns attribute types and attribute values.
searchFilter: Defines the conditions under which a search return is successful. The conditions can be combined with the Boolean "and," "or," and "not" operators. The filter evaluates to either "true," "false," or "undefined." If it evaluates to "true," the requested attributes of the entry are returned; if it evaluates to "false" or "undefined," the entry is ignored for the search. The search filter is treated in detail in the next chapter in the section entitled "Search Revisited."
attributeList: Attributes that should be returned if the searchFilter matches. Two values have a special meaning: an empty list with no attributes and an asterisk, "*". Both values instruct the server to return all attributes of the matching entries. The asterisk allows you to specify further operational attributes to be returned.
The "compare" operation tests for the presence of a particular attribute in an entry with a given distinguished name. It returns "true" if the entry contains the attribute and "false" if the entry does not contain the attribute. You may wonder why you need a "compare" operation when there is already a "search" operation. One reason is a historical one, in that "compare" derives from X.500. The other reason is that the results of a "search" operation and a "compare" operation are not really identical. If you execute a "compare" on an attribute not contained in an entry, the "compare" operation returns a special value. Using the "search" operation, you cannot distinguish whether the attribute does not have this particular value or the attribute does not exist at all. Now look at the parameters for the "compare" operations:
entry: Distinguished name of the entry you are searching for
ava: Attribute name-value pair you want to verify is contained in the entry ("ava" means "attribute value assertion")
The "add" operation is a relative easy one, as it contains only two parameters: entry and attributeList
entry: Distinguished name of the new entry
attributeList: A list of name-value pairs of the attributes contained in the entry
The "delete" operation is still easier than the "add" operation inasmuch as it takes one parameter only, the distinguished name of the entry to be deleted.
entry: Distinguished name of the entry to be deleted
The "modify" operation is more complicated than the previous two. It takes three parameters: distinguished name, type of operation, and name-value pairs:
entry: Distinguished name of the entry to be modified
operation: Type of operation to be executed on this entry, with three possible values:
add: Adds a new attribute (name,value pair)
delete: Deletes an attribute
modify: Modifies an attribute
attributeList: Produces a list of name-value pairs to be added/modified
The modifyDN operation can be used for two purposes: to rename an entry or to move an entry within the directory. Exhibit 29 shows the first purpose. You modify only the leftmost, or least significant part, of the distinguished name. The parent remains the same, and only the RDN changes.
Exhibit 29: ModifyDN Name, the Hierarchy Remains the Same
The other version of the modifyDN operation changes the hierarchy also, as shown in Exhibit 30.
Exhibit 30: ModifyDN Name, the Hierarchy Is Modified
You can also specify whether or not you wish to delete the old relative distinguished name. Keeping it would mean that the system copies the entry from its old location to a new one, as shown in Exhibit 31.
Exhibit 31: ModifyDN Name, as in Exhibit 30, but Keeping the Old RDN
Exhibit 32 shows an example where there is a change in the hierarchy, i.e., the system moves the entry to a new location and changes its RDN.
Exhibit 32: ModifyDN Name, Modify Hierarchy, and Change RDN
The parameters that the modifyDN operation can take are as follows:
entry: Distinguished name of the entry to be modified
newRDN: New relative distinguished name
deleteOldRDN: Boolean value indicating whether the old RDN should be kept in the directory
newSuperior: Indicates a change in the hierarchy
Let us also look at what we must specify to initiate these actions. We begin by modifying only the RDN (see Exhibit 29):
Entry: uid=RVoglmaier, ou=Marketing, o=LdapAbc.org newRDN: uid=ReinhardVoglmaier deleteOldRDN: true
The next example changes the hierarchy while the RDN remains the same (see Exhibit 30):
Entry: uid=RVoglmaier, ou=Marketing, o=LdapAbc.org newRDN: uid=RVoglmaier deleteOldRDN: true newSuperior: ou=Sales,o=LdapAbc.org
The following example is the same as the previous one, but this time we do not erase the old entry. The reason for doing this here is not yet clear, but this example is presented simply to show the syntax. A bit later, we will present an example where it makes sense (see Exhibit 31).
Entry: uid=RVoglmaier, ou=Marketing, o=LdapAbc.org newRDN: uid=RVoglmaier deleteOldRDN: false newSuperior: ou=Sales,o=LdapAbc.org
Finally, we change nearly everything (see Exhibit 32):
Entry: uid=RVoglmaier, ou=Marketing, o=LdapAbc.org newRDN: uid=ReinhardVoglmaier deleteOldRDN: true newSuperior: ou=Sales,o=LdapAbc.org
Note that modifying the distinguished name of an entry having children is somewhat more complicated. Look at the coding above to see what could happen. Let us assume we would like to change the name of the organizational unit from "HR" to the more user-friendly "Human Resources." After the modification, the entries under HR would be without a parent. This means that the namespace would be illegal. Most directory servers would refuse the modify operation. What you need to do is first create the new organizational unit, keeping the old entry. Then you rename all the children and delete the old organizational unit. If the children have further children, the situation can get even more complicated. Another possibility would be to export the whole directory, change all occurrences of the old name to the new name, and re-export the directory. We will learn more about this subject in Chapter 4, when we look at the details from a practical point of view.
The main purpose of the "bind" operation is to let the client authenticate itself against the directory server. The "bind" operation takes three parameters, version, name, and authentication:
version: Version of LDAP the client wishes to use
name: Name of the directory object the client wishes to bind to
authentication: Authentication choice, which has two possible values:
simple: Indicates that the password travels in clear text over the wire.
sasl: Uses the SASL mechanism as described in RFC 2222, "Simple Authentication and Security Layer." (We will see more about SASL in the next section about the security model.)
The operation "unbind" is very simple and does not take any parameters. The "unbind" operation does not return any value from the server. The client assumes that the connection to the server is now closed. The server releases any resources allocated for the client, discards any authentication information, and closes the TCP/IP connection with the client.
Another simple operation, "abandon" takes only one parameter. The "abandon" operation is used to inform the server to stop a previously requested operation. The abandon operation typically is used by GUIs in the case of long-running operations on the server to inform the server that the client is no longer interested in the result of the operation. The operation takes only one parameter: the operationID.
operationID: ID of the operation to be abandoned
The server does not send any response to the "abandon" operation. The client does not expect any response, but it has to be prepared to continue to receive responses from the abandoned operation. This can happen when the "abandon" request from the server and the response from the operation to be abandoned cross each other on the wire.
In this section we have reviewed the operations embedded in the LDAP standards. These operations are then implemented in the various APIs provided by the different software development kits. Most of the LDAP implementations ship with a set of command-line tools. However, the command-line tools normally are nothing but a collection of compiled C programs. If you want, you could write your own code. However, I recommend that you get the OpenLDAP distribution, which already contains the source code written in C of the command-line tools, and change it to meet your personal taste and requirements. These C programs are also a very good example of how to use the C language to access a directory, since these programs are built from the ground up without relying on any API.
The most prominent API is the one for the C programming language. The LDAP C API for version 2 is documented in RFC 1823; the version 3 API is still proposed as draft and is available from IETF at http://www.ietf.org. Furthermore, there are APIs available for nearly every language, such as Java, Perl, Python, PHP, or Ruby. Chapter 5 shows some working examples in these languages.
In this section, you learned about the model defining the functions that can be performed on the directory. The two previous sections explained the data structures held by a directory. We are now ready to learn about the security structure proposed in the LDAP standard. As you will see, the standard does not cover all of the security requirements required by a stable LDAP implementation. However, this does not mean that LDAP implementations are, by definition, insecure. Every implementation covers security in a proprietary manner. Thus the problem remains the interoperability between LDAP implementations from different vendors.
|< Day Day Up >|| |