Mozilla LDAP SDK Programmer's Guide/Best Practices for Writing Client Applications
The section covers what to keep in mind when creating and debugging LDAP client applications.
- 1 Specify LDAP v3
- 2 Authenticate Correctly
- 3 Limit Connection Overhead
- 4 Handle Potential Inactivity Timeouts
- 5 Retrieve Entries Intelligently
- 6 Write Simple, Conforming LDAP Filters
- 7 Performing Specific Modifications
- 8 Trust Result Codes
- 9 Limit Dealings With Groups and Roles
- 10 Read the DSE
- 11 Use Resource-Intensive Features Sparingly
- 12 Avoid Hard Coding Certain Information
- 13 Define Schemas Only When Necessary
- 14 Handle Referrals
- 15 Treat a Directory as a Directory
- 16 Check Result Codes
- 17 Check Server Log Files
- 18 Inspect Network Packets
Specify LDAP v3
With JNDI, you could use LDAP v3 as shown here.
import java.util.Hashtable; import javax.naming.ldap.InitialLdapContext; Hashtable env = new Hashtable(); env.put("java.naming.ldap.version", "3"); InitialLdapContext ctx = new InitialLdapContext(env, null);
With LDAP C SDK, you could use LDAP v3 as shown here.
#include "ldap.h" int version = LDAP_VERSION3; ldap_set_option( NULL, LDAP_OPT_PROTOCOL_VERSION, version );
LDAP C SDK uses LDAP v3 by default.
With LDAP Java SDK, you could use LDAP v3 as shown here.
import netscape.ldap.LDAPConnection; LDAPConnection ld = new LDAPConnection(); ld.setOption(LDAPv3.PROTOCOL_VERSION, new Integer(3));
Your SDK uses terminology that is slightly different from LDAP v3. In LDAP v3, you connect, then you bind and perform LDAP operations, then you unbind and disconnect. The bind is the authentication operation in LDAP. Your application can hold onto a connection but change the authentication credentials by using the bind operation again.
Some directories do not allow anonymous access, even for reads. When you build your application, keep the option that allows users to authenticate to the directory. Furthermore, the information sent across the network can be sensitive. You can protect sensitive data by allowing the application to secure the connection by using Secure Sockets Layer (SSL) or Start Transport Layer Security (TLS).
If your application needs to authenticate, obtain a regular account to authenticate with the directory, rather than using the directory superuser account such as cn=Directory Manager. When you authenticate as directory superuser, you often bypass normal access control mechanisms. Bypassing normal access control renders auditing directory access more difficult.
When authenticating, have your application use SSL or SASL DIGEST MD5 to avoid sending passwords over the network in clear text. Furthermore, when using password-based authentication, have your application check password policy controls, especially to determine when a password must be renewed.
Limit Connection Overhead
A new connection requires system resources. The LDAP model allows you to reuse connections by binding again with a different identity on the same connection. Thus, you can avoid the costs of new connections, particularly negotiated connections such as connections that use SSL, by reusing connections. Your application can use a pool of connections, rebinding when necessary. Your application can alternatively use the proxy authorization control to remain authenticated as the application but perform operations on behalf of a particular user.
When establishing a connection, your application can provide alternate server host names and port numbers to facilitate failover that is transparent to the application. You can also set time limits for LDAP operations to avoid getting blocked.
When finished with a connection, your application should perform an unbind.
Handle Potential Inactivity Timeouts
Most network equipment can use timeouts to drop stale connections, ensuring the equipment keeps a maximum number of connections that are available.
If your application pools connections or opens connections for persistent search, than guard against timeouts that drop those connections. Use the connections occasionally to reset inactivity timers present in the network.
Alternatively, if you have control over the connection, consider disabling inactivity time outs for your applications that need to keep persistent connections open. Load balancers and proxy software often use inactivity timeouts.
Retrieve Entries Intelligently
Directory Server typically responds quickly to requests for entries. Yet, Directory Server can respond most quickly when your application asks it to do only necessary work. If you need to read only a few attributes in an entry, request each attribute explicitly. Avoid reading the entire entry, then parsing the entire entry to obtain the required data.
Furthermore, when you do request attributes in an entry, retrieve all the required attributes at once. Each new request involves a new operation on the server.
If any of the attributes that you require are operational attributes, you must request those attributes specifically. Such attributes are identifiable in directory schema by their USAGE, which is directoryOperation or dsaOperation.
When retrieving entries and attributes, recognize that you might not have access to all the attributes that exist.
Write Simple, Conforming LDAP Filters
The best filters use attributes that are indexed according to the way the attributes are indexed. For example, if employeeNumber is indexed for equality, your filter should be an equality filter such as (employeeNumber=123456). Do not use a substring filter instead.
Avoid deeply nested complex filters when you can. When you must use complex filters, place the most specific filters first to narrow the list of candidate entries the directory must check. For best results, use not, !, only with and, &, for example (&(cn=Barbara)(!(sn=Jensen))). When you use not with or in a filter, the directory must construct a candidate list of everything except what your filter specifies.
Performing Specific Modifications
Modifications are atomic on the entry to which the modifications apply. When modifying multivalued attributes, delete and replace specific values. Do not replace an entire list of multiple values to change only a few values. Replacing specific values is particularly good practice when the changes must be replicated across a set of servers.
Moreover, when you have large values to store in an attribute, store a reference to the data instead of storing the data object.
Trust Result Codes
Directory Server trades tight consistency across replica servers for very high performance, availability, and scalability. By allowing loose consistency of data across sets of replica servers, Directory Server instances can respond very quickly to your application. Yet, data replication is not instantaneous. A short but detectable delay can ensue after a server returns success for a write operation, but before the effects are seen on other replicas.
Therefore, when your application receives a result code from Directory Server to indicate that an operation was successful, your application should trust the result code. When application requests are balanced across replicas, reading from another replica might result in errors due to a slight delay in replication.
Limit Dealings With Groups and Roles
When you want to know whether an account belongs to a group or a role, read only the necessary attribute values. Do not read the entire list of group members.
- Read the URL from the group definition.
- Examine the host, DN, and scope of the URL.
- Apply the filter part of the URL to the entry for the account.
For roles, compare the DN of the role to the nsRole attribute of the entry for the account, such as (nsrole=cn=management,ou=people,dc=example,dc=com). You can then retrieve all the values of the nsRole attribute for the account.
Read the DSE
The root DSE is the entry that is retrieved by ldapsearch -b "" -s base "(objectclass=*)". The root DSE describes server capabilities. The root DSE contains information about supported LDAP protocol versions, naming contexts (suffixes), LDAP v3 controls, LDAP v3 extensions, and authentication mechanisms. The root DSE can contain information about the server version.
Some directory administrators protect access to the root DSE. Yet, applications might read the root DSE to confirm that the server in fact supports functionality required by applications.
Use Resource-Intensive Features Sparingly
Directories offer powerful features that can nevertheless place a heavy load on the server. Two such features are persistent search, and server-side sorting.
Persistent search lets you start a search that does not stop when complete, but instead allows you to receive updates when entries are modified. To provide this feature, the server must handle your search when anything happens to an entry in its scope.
Server-side sorting requires that the server sort the entries that are returned during a search. Instead of returning entries as quickly as possible, the server must therefore get the list to return, and sort the list.
Avoid Hard Coding Certain Information
The container entry for a subtree might be not be identical on different directories. Rather than hard code the container entry throughout your application, locate the container entry. Then navigate beneath the container entry in the tree.
Object classes and attribute types for the same information can also differ from directory to directory. Use configuration files, properties files, or other easily modifiable variables rather than hard coding object class and attribute type identifiers into your application.
Be aware as well that object class and attribute type identifiers are not case-sensitive in LDAP. Your application should therefore recognize that inetOrgPerson and inetorgperson are equivalent, as are isMemberOf and ismemberof.
Define Schemas Only When Necessary
Schemas define the object classes and attribute types that are recognized by the directory. If your application can use a standard schema, use the standard schema. Directory Server contains schemas that define numerous standard object classes, and attribute types.
- Extend existing object classes by using AUXILIARY classes.
- Create new attributes rather than redefining existing attributes.
- Other applications might depend on existing attributes to keep their existing semantics.
- Obtain new object identifiers for the schema elements you define, rather than reusing existing object identifiers.
- Obtain new names for the schema elements you define, rather than reusing existing names.
- Update Directory Server schema over LDAP if you can.
LDAP v3 allows directories that are unable to handle your request to refer your application to other directories. Your application should follow those referrals.
When following referrals, realize that authentication procedures might not be exactly the same on different directories. Also, directories that refer to each other could potentially cause a referral loop. With LDAP C SDK and LDAP Java SDK, you can limit referral hops to prevent your application from being referred endlessly from one directory to another directory. The JNDI interface enables you to follow referrals automatically.
Treat a Directory as a Directory
A directory is typically a repository for identity data, and for information that you expect to keep for awhile and read often. You might typically find relational databases better adapted to hold transient data such as session keys and presence information, or voluminous accumulated data such as application logs.
Check Result Codes
When an LDAP request from your application fails on the server, the server sends back a result code, and possibly an explanatory message. Your application should check the result codes, and for explanatory messages. Common failure result codes include the following, which are expressed as decimal values. Others result codes are defined as well.
LDAP operations error. The server encountered an error while processing your request.
No such object. The entry is not present on the server. Also, no referral is defined for the entry.
Invalid credentials. Your application failed to authenticate properly.
LDAP unwilling to perform. The directory does not support the request. Alternatively, the directory is not currently in a state in which to complete your request. For example, the directory might be in read-only mode when your application requests a modification.
Object class violation. Your write request would cause an entry to no longer conform to the schema defined for the directory.
Already exists. Your application is requesting to add an entry that has the same DN as an entry already present in the directory.
RFC 4511 defines LDAP error codes.
Check Server Log Files
Directory Server logs messages related to server operation in its logs/errors file. If you have access to this file, you might find useful troubleshooting information there.
When debugging your application against Directory Server, you can adjust the log level, as well. See the server documentation for instructions.
Inspect Network Packets
Although LDAP is not a textual protocol, tools such as snoop, ethereal, and tcpdump can decode the packets, sometimes providing you with important debugging information.