Mozilla LDAP SDK Programmer's Guide/Using the LDAP Java Classes

From MozillaWiki
Jump to: navigation, search

This section covers general LDAP Java classes that are commonly used when writing LDAP clients.

Getting Information About LDAP Java SDK

You can get information about the version of LDAP Java SDK that you are using. Version information tells you the version of the LDAP Java classes. Version information can also tell you the highest version of the LDAP protocol that LDAP Java SDK supports.

To get this information, use the getProperty method of the LDAPConnection object.

LDAPConnection ld = new LDAPConnection();
try {
    System.out.println("LDAP Java Classes Version: " +
        (Float) ld.getProperty(LDAPConnection.LDAP_PROPERTY_SDK));
    System.out.println("Highest version of LDAP supported: " +
        (Float) ld.getProperty(LDAPConnection.LDAP_PROPERTY_PROTOCOL));
    System.out.println("Authentication methods supported: " +
        (String) ld.getProperty(LDAPConnection.LDAP_PROPERTY_SECURITY));
} catch (LDAPException e) {
    System.out.println("Could not get SDK properties.");
    System.out.println("Error: " + e.toString());
}

Although a setProperty method is provided, currently no properties exist that you can set. If you invoke the setProperty method, the method returns an LDAPException.

Handling Exceptions With LDAP Java SDK

In LDAP, the success or failure of an operation is specified by an LDAP result code sent back to the client. For example, the result code 0 indicates that the operation was successful. A non zero result code usually indicates that an error occurred.

Getting Information About the Error

In the LDAP Java classes, when an error occurs, an LDAPException is returned. Referrals cause an LDAPReferralException to be returned as described in Handling Referrals With LDAP Java SDK. An LDAPException contains the following information:

  • The LDAP result code for the error that occurred
  • A message that contains any additional information about the error from the server
    An error can occur when an entry specified by a DN cannot be found.

The LDAPException then also contains the DN of the closest matching entry that can be found.

To get information from the LDAPException, use one of the following methods:

  • To get the string representation of the exception, use the toString method.
  • To get the LDAP result code, use the getLDAPResultCode method.
  • To get any additional information sent by the server, use the getLDAPErrorMessage method.
  • To get the closest matching DN in cases where your client specified a DN to a nonexistent entry, use the getMatchedDN method.

To get the error message describing the LDAP result code, use the errorCodeToString method, as described in Getting the Error Message.

The following section of code gets and prints information about an LDAPException.

try {
    /* Attempt to perform an LDAP operation here. */
} catch (LDAPException e) {
    /* Get and print the result code and any other info. */
    int resultCode = e.getLDAPResultCode();
    String serverInfo = e.getLDAPErrorMessage();
    System.out.println("LDAP Result Code: " + resultCode);
    if (serverInfo != null) {
        System.out.println("Additional Info: " + serverInfo);
    }
    /*
     * If the exception was returned because an entry was
* not found, print the DN of the closest entry found.
     */
    switch (resultCode) {
    case LDAPException.NO_SUCH_OBJECT:
    case LDAPException.ALIAS_PROBLEM:
    case LDAPException.INVALID_DN_SYNTAX:
    case LDAPException.ALIAS_DEREFERENCING_PROBLEM:
        String matchedDN = e.getMatchedDN();
        if (matchedDN != null) {
            System.out.println("Closest Entry: " + matchedDN);
        }
        break;
    default:
        break;
    }
}

Getting the Error Message

To get the error message for an LDAP result code, use the errorCodeToString method.

try {
    /* Attempt to perform an LDAP operation here. */
} catch (LDAPException e) {
    /* Get and print the error message. */
    int resultCode = e.getLDAPResultCode();
    System.out.println("Error: " + e.errorCodeToString(resultCode));
}

Error messages corresponding to each LDAP result code are located either inside the file or under another directory in your CLASSPATH, in a properties file named or . locale can be a two-letter version of the locale, such as de, fr, or ja, or it can be a full version of the locale, such as en_US.

When you invoke the errorCodeToString method of an LDAPException, the method retrieves the error message string for the specified locale. If no locale is specified, the method retrieves the default locale from the properties file. The errorCodeToString method looks for locale-specific properties files in the following order, retrieving the first property that is found:

netscape/ldap/error/ErrorCodes_''language''_''country''.props
netscape/ldap/error/ErrorCodes_''language''.props
netscape/ldap/error/ErrorCodes.props

Handling Referrals With LDAP Java SDK

An LDAP server can receive a request for a DN that is not under its directory tree. The server can then refer clients to another LDAP server that might contain that DN. The response is known as a referral.

This section explains how to set up your LDAP client to handle referrals automatically.

Understanding Referrals

Suppose an LDAP server has a directory that starts under dc=example,dc=com. Your client might send the server a request to modify the entry with the DN uid=bjensen,ou=People,o=example.com. The entry is not under dc=example,dc=com. One of the following can occur.

  • If the server is not configured to send a referral, an LDAPException is returned with the LDAP result code LDAPException.NO_SUCH_OBJECT.
  • If the server is configured to refer you to another LDAP server, the server sends a referral back to your client.

Depending on how your LDAP client is configured, one of the following can occur:

  • If your client handles referrals automatically, your client connects to the LDAP server specified in the referral and requests to modify the entry. The client binds anonymously to that server. To bind as a specific user, refer to Enabling or Disabling Referral Handling.
  • If your client does not handle referrals automatically, an LDAPReferralException is returned. You can get the LDAP URL specified in the referral by catching the exception, and then invoking the getURLs method.

By default, clients built with LDAP Java SDK are configured to follow referrals automatically.

Another concept that is similar to a referral is a search reference. A search reference is an entry with the object class referral. The ref attribute of this object contains an LDAP URL that points to another LDAP server.

When your client searches a subtree of the directory that contains search references, the server returns a mix of matching entries and search references. As you iterate through the enumeration of search results, you can encounter a search reference although your client does not handle referrals automatically. An LDAPReferralException is then returned.

Enabling or Disabling Referral Handling

By default, clients built with LDAP Java SDK automatically follow referrals to other servers. To change the way your client handles referrals, use one of two methods. Use the setOption method of the LDAPConnection object to change the behavior for all LDAP operations. Alternatively, use the setReferrals method of the LDAPConstraints object to change the behavior for a specific search request.

  • To prevent the client from automatically following referrals, pass LDAPv3.REFERRALS and false as arguments to the setOption method. Alternatively, pass false as the argument to the setReferrals method.
  • To enable the client to follow referrals automatically again, pass LDAPv3.REFERRALS and true as arguments to the setOption method. Alternatively, pass true as the argument to the setReferrals method.

Limiting Referral Hops

You can specify the maximum number of referral hops that should be followed in a sequence of referrals. You can set the preference for the connection. You can also set the maximum as a constraint for specific search operations. The maximum is called the referral hop limit.

For example, suppose you set a limit of two referral hops. If LDAP server A refers to server B, B to C, and C to D, your client is being referred three times in a row. Your client does not follow the referral to LDAP server D because this referral exceeds the referral hop limit.

If the referral hop limit is exceeded, an LDAPReferralException is returned.

To set the referral hop limit, use either of two methods. Use the LDAPv3.REFERRALS_HOP_LIMIT preference with the setOption method of the LDAPConnection object to change the behavior for all LDAP operations. Alternatively, use the setHopLimit method of the LDAPConstraints object to change the behavior for a specific search request.

By default, the maximum number of referral hops is 10.

Binding When Following Referrals

If the connection is set up so that referrals are always followed, the LDAP server that you connect to can refer you to another server. By default, the client binds anonymously such that no user names or passwords are specified when following referrals.

To authenticate to the LDAP server that you are referred to, specify how to get the DN and password for authentication. You need to define a class that implements the LDAPRebind interface. Then, specify an object of this new class with either of two methods. Use the LDAPv3.REFERRALS_REBIND_PROC preference with the setOption method of the LDAPConnection object to set the preference for all LDAP operations.

Alternatively, use the setRebindProc method of the LDAPConstraints object to change the behavior for a specific search request.

The LDAPRebind interface specifies a getRebindAuthentication method that returns an LDAPRebindAuth object. The getRebindAuthentication method and the LDAPRebindAuth object that the method returns are used to get the DN and password for authentication.

The following steps explain how this works.

  1. The LDAP server sends a referral back to the client. The referral contains an LDAP URL that points to another LDAP server.
  2. The client creates a new LDAPConnection object.
  3. The client connects to the host and port specified in the LDAP URL.
  4. You can use the getRebindProc method to find your object, the object that implements the LDAPRebind interface. The client then invokes the getRebindAuthentication method, passing in the host and port specified in the LDAP URL.
  5. The getRebindAuthentication method in your object returns an LDAPRebindAuth object.
  6. The client invokes the getDN and getPassword methods of the returned LDAPRebindAuth object to get the DN and password to use for authentication.
  7. The client invokes the authenticate method of the LDAPConnection object and passes the DN and password to authenticate to the server.

Basically, you need to define the following:

  • A class that implements the LDAPRebind interface
  • A getRebindAuthentication that takes a host name and port number.
  • This method creates an LDAPRebindAuth object that specifies the DN and password to use for authentication.

Using In-Memory Cache With LDAP Java SDK

LDAP Java SDK includes an LDAPCache class that allows you to create an in-memory cache of search results for your client. When you send a search request, you receive results. The search request and its results are then cached. The next time your client issues the same search request, the results are read from the cache.

How the Cache Operates

Each item in the cache represents a search request and its results. When you create the cache, you can specify the maximum size of the cache. You can also specify the maximum amount of time that an item can be cached.

  • When an item's age exceeds that time limit, the item is removed from the cache. The cache is checked once a minute for expired items.
  • If adding a new item causes the cache to exceed its maximum size, items are removed from the cache. Removal makes space for the new item. Items are removed on a first in, first out basis.

Each item is uniquely identified by the search criteria, which includes the following:

  • Host name and port number of the LDAP server
  • Base DN of the search
  • Search filter
  • Scope of the search
  • Attributes to be returned in the search results
  • DN used to authenticate the client when binding to the server
  • LDAP v3 controls specified in the search request

After a search request is cached, if your client performs the same search again, the results are read from the cache instead of from the server. Note that if any part of a search request differs from a cached search request, the results are read from the server. For example, a different DN might be used when authenticating to the server. Alternatively, the search request might specify that a different set of attributes should be returned. In either case, the results are not read from the cache. Instead, the search request is sent to the server.

Finally, when creating the cache, you can specify a list of the base DNs in search requests that you want to cache. For example, if you specify ou=People,dc=example,dc=com as a base DN to cache, your client caches search requests where the base DN is ou=People,dc=example,dc=com.

Setting Up an In-Memory Cache

To set up a cache for your connection, do the following:

  • Construct a new LDAPCache object that represents the cache.
  • Invoke the setCache method of an LDAPConnection object to associate the cache with the connection.

For example, the following section of code creates a cache with the maximum size of 1 Mbyte. Items in the cache expire and are automatically removed after one hour.

try {
    LDAPConnection ld = new LDAPConnection();
    /* Create a cache for the connection */
    int MAX_TIME_CACHED = 3600; // 3600 seconds == 1 hour
    int MAX_SIZE = 1000000;     // 1000000 bytes == 1 MB
    LDAPCache myCache = new LDAPCache(MAX_TIME_CACHED, MAX_SIZE);
    ld.setCache(myCache);
    /* Connect to server */
    ld.connect("ldap.example.com", LDAPv3.DEFAULT_PORT);
    /*
     * Perform operations...
     */
} catch (LDAPException e) {
    System.out.println("Error: " + e.toString());
}

Caching Requests by Base DN

If you do not want all search requests cached, specify an array of base DNs for search requests to cache in the LDAPCache constructor. For example, the following section of code constructs a cache that only tracks search requests that specify the base DNs ou=People,dc=example,dc=com and ou=Groups,dc=example,dc=com.

/* Create a cache for the connection */
int MAX_TIME_CACHED = 3600;
int MAX_SIZE = 1000000;
String [] BASE_DN_CACHED = {"ou=People,dc=example,dc=com",
    "ou=Groups,dc=example,dc=com"};
LDAPCache myCache = new LDAPCache(MAX_TIME_CACHED, MAX_SIZE,
    BASE_DN_CACHED);

Sharing a Cache Among Connections

You can also share the same in-memory cache among different connections.

  • Invoke the getCache method of an LDAPConnection object to get the LDAPCache object that is used.
  • Invoke the setCache method of a different LDAPConnection object to associate the retrieved LDAPCache object with the connection.

When you clone an LDAPConnection object, the new object automatically shares the same LDAPCache object with the original object.

Flushing the Cache

To flush items from the cache, invoke the flushEntries method of the LDAPCache object. You can flush either selected items or all items from the cache.

To flush selected items from the cache, specify the base DN of the search requests that you want to flush. Specify a DN and search scope as arguments to the flushEntries method. If the base DN of a cached search request falls within the scope you specified, the search request is flushed from the cache.

For example, the following section of code flushes selected search requests from the cache. If the base DN of a search request falls under the ou=People,dc=example,dc=com subtree, the item is removed from the cache.

LDAPCache myCache;
/* Perform search requests... */
/*
 * Flush search requests with base DNs under
 * ou=People,dc=example,dc=com.
 */
myCache.flushEntries("ou=People,dc=example,dc=com",
    LDAPConnection.SCOPE_SUB);

To flush all items from the cache, pass null as the first argument of the flushEntries method:

myCache.flushEntries(null, 0);

Getting Cache Statistics

You can invoke the following methods of the LDAPCache object to get statistics on the cache.

  • To get the total amount of available space in bytes that are left in the cache, invoke the getAvailableSize method.
  • To get the array of base DNs of the search requests to be cached, invoke the getBaseDNs method.
  • To get the total number of items that have been flushed from the cache, not including items flushed when invoking the flushEntries method, invoke the getNumFlushes method.
  • To get the maximum size of the cache in bytes, invoke the getSize method.
  • To get the maximum amount of time that an item can be cached in seconds, get the getTimeToLive method.

You can also get a running count of the number of requests that access the cache.

  • To get the total number of requests for retrieving items from the cache, invoke the getTotalOperation method.
  • To get the total number of requests that retrieved an item from the cache, invoke the getNumHits method.
  • To get the total number of requests that failed to find and retrieve an item from the cache, invoke the getNumMisses method.

For example, the following section of code gets and prints cache statistics.

LDAPConnection ld;
if ((ld != null) && ld.isConnected()) {
    LDAPCache connCache = ld.getCache();
    if (connCache != null) {
        System.out.println("Cache size:\t\t" +
            connCache.getSize()/1000 + " kbytes");
        System.out.println("Available:\t\t" +
            connCache.getAvailableSize()/1000 + " kbytes");
        System.out.println( "Maximum age:\t\t" +
            connCache.getTimeToLive()/1000 + " seconds");
        System.out.println("Total hits:\t\t" +
            connCache.getNumHits() + " hits" );
        System.out.println("Total misses:\t\t" +
            connCache.getNumMisses() + " misses" );
        System.out.println("Total requests:\t\t" +
            connCache.getTotalOperations() + " requests");
    } else {
        System.out.println(
            "No cache associated with the connection.");
    }
}

Cloning a Connection With LDAP Java SDK

You can create several LDAPConnection objects that share a single physical network connection to the LDAP server by invoking the LDAPConnection.clone method. Clones have the following properties:

  • If you clone an object before a connection is made to the server, the cloned object does not share the same connection as the original object.
  • Each clone can disconnect from the server without affecting the connection for the other clones. The network connection remains in an open state until all clones have either disconnected or gone out of scope.
  • If the clone disconnects or reconnects, the clone is completely dissociated from the source object and other clones.
  • A cloned LDAPConnection object has a separate set of session preferences and constraints. In other words, the clone is associated with its own LDAPSearchConstraints object.
    Changes to an option or to a search constraint only affect requests issued using that object.
    For example, suppose an LDAPConnection object allows a maximum of 100 results to be returned from a search. If you clone an LDAPConnection object, you can change the maximum number of results in the clone from 100 to 200. Yet, the initial object still allows only 100 results to be returned.
  • All clones are authenticated to the server as the same user.
    If you authenticate again to the server as a different user, the current clone is disconnected. The clone connects separately to the server. The LDAPConnection object is no longer a clone of another LDAPConnection object.

Manipulating Distinguished Names With LDAP Java SDK

A distinguished name (DN) uniquely identifies an entry in the directory tree. You can get the DN for an entry as explained in Getting Distinguished Names. Alternatively, you can specify a DN to read an entry from the directory as explained in Reading an Entry With LDAP Java SDK. LDAP Java SDK includes a utility class, LDAPDN, that provides methods for manipulating DNs.

If you want to access individual components of a distinguished name or a relative distinguished name, invoke the LDAPDN.explodeDN method or the LDAPDN.explodeRDN method.

Both methods return an array of String objects that represent the individual components of the distinguished name. You can specify whether or not you want the names of the components included in the array by using the notypes parameter.

  • Set notypes to false if you want to include component attribute types in the array.
LDAPDN.explodeDN("uid=bjensen,ou=People,dc=example,dc=com", false);

The method returns the array {"uid=bjensen", "ou=People", "dc=example", "dc=com"}.

  • Set notypes to true if you do not want component attribute types returned in the array.
LDAPDN.explodeDN("uid=bjensen,ou=People,dc=example,dc=com", true);

The method returns the array {"bjensen", "People", "example", "com"}.