apache > db
Apache DB Project
 
Font size:      

External Directory Service

External Directory Service

A directory service stores names and attributes of those names. A typical use for a directory service is to store user names and passwords for a computer system. Derby uses the Java naming and directory interface (JNDI) to interact with external directory services that can provide authentication of users' names and passwords.

Derby can use the following services:

LDAP Directory Service

You can allow Derby to authenticate users against an existing LDAP directory service within your enterprise. LDAP (lightweight directory access protocol) provides an open directory access protocol running over TCP/IP. An LDAP directory service can quickly authenticate a user's name and password.

To use an LDAP directory service, set derby.authentication.provider to LDAP.

Examples of LDAP service providers are:

  • Netscape Directory Server

    Netscape Directory Server is an LDAP directory server. In addition, the Netscape Directory Synchronization Service synchronizes entries in a Windows NT directory with the entries in Netscape's Directory Server. It allows you to use the Windows NT directory as a repository for Derby users.

  • UMich slapd (freeware for the UNIX platform from the University of Michigan)
  • AE SLAPD for Windows NT, from AEInc

Libraries for LDAP User Authentication

To use an LDAP directory service with Derby, you need the following libraries in your class path:

  • jndi.jar

    JNDI classes

  • ldap.jar

    LDAP provider from Sun

  • providerutil.jar

    JNDI classes for a provider

Derby does not provide these libraries; they are available from Sun on the JNDI page at Use the 1.1.x versions of these libraries, not the 1.2.x versions. You might need to do two separate downloads to obtain all the required libraries.

Setting Up Derby to Use Your LDAP Directory Service

When specifying LDAP as your authentication service, you must specify the location of the server and its port number.

  • derby.authentication.server

    Set the property derby.authentication.server to the location and port number of the LDAP server. For example:

    derby.authentication.server=godfrey:389
    

Guest Access to Search for DNs

In an LDAP system, users are hierarchically organized in the directory as a set of entries. An entry is a set of name-attribute pairs identified by a unique name, called a DN (distinguished name). An entry is unambiguously identified by a DN, which is the concatenation of selected attributes from each entry in the tree along a path leading from the root down to the named entry, ordered from right to left. For example, a DN for a user might look like this:

cn=mary,ou=People,o=FlyTours.com
 
uid=mary,ou=People,o=FlyTours.com

The allowable entries for the name are defined by the entry's objectClass.

An LDAP client can bind to the directory (successfully log in) if it provides a user ID and password. The user ID must be a DN, the fully qualified list of names and attributes. This means that the user must provide a very long name.

Typically, the user knows only a simple user name (e.g., the first part of the DN above, WilliamS). With Derby, you do not need the full DN, because an LDAP client (Derby) can go to the directory first as a guest or even an anonymous user, search for the full DN, then rebind to the directory using the full DN (and thus authenticate the user).

Derby typically initiates a search for a full DN before binding to the directory using the full DN for user authentication. Derby does not initiate a search in the following cases:

  • You have set derby.authentication.ldap.searchFilter to derby.user.
  • A user DN has been cached locally for the specific user with the derby.user.UserName property.

For more information, see derby.authentication.ldap.searchFilter in Tuning Derby.

Some systems permit anonymous searches; other require a user DN and password. You can specify a user's DN and password for the search with the properties listed below. In addition, you can limit the scope of the search by specifying a filter (definition of the object class for the user) and a base (directory from which to begin the search) with the properties listed below.

  • derby.authentication.ldap.searchAuthDN (optional)

    Specifies the DN with which to bind (authenticate) to the server when searching for user DNs. This parameter is optional if anonymous access is supported by your server. If specified, this value must be a DN recognized by the directory service, and it must also have the authority to search for the entries.

    If not set, it defaults to an anonymous search using the root DN specified by the derby.authentication.ldap.searchBase property. For example:

    uid=guest,o=FlyTours.com
    
  • derby.authentication.ldap.searchAuthPW (optional)

    Specifies the password to use for the guest user configured above to bind to the directory service when looking up the DN. If not set, it defaults to an anonymous search using the root DN specified by the derby.authentication.ldap.searchBase property.

    myPassword
    
  • derby.authentication.ldap.searchBase (optional)

    Specifies the root DN of the point in your hierarchy from which to begin a guest search for the user's DN. For example:

    ou=people,o=FlyTours.com
    

    When using Netscape Directory Server, set this property to the root DN, the special entry to which access control does not apply (optional).

To narrow the search, you can specify a user's objectClass.

  • derby.authentication.ldap.searchFilter (optional)

    Set derby.authentication.ldap.searchFilter to a logical expression that specifies what constitutes a user for your LDAP directory service. The default value of this property is objectClass=inetOrgPerson. For example:

    objectClass=person
    

Performance Issues

For performance reasons, the LDAP directory server should be in the same LAN as Derby. Derby does not cache the user's credential information locally and thus must connect to the directory server every time a user connects.

Connection requests that provide the full DN are faster than those that must search for the full DN.

Windows NT Users

Netscape provides LDAP functionality for Windows NT systems with its Netscape Directory Synchronization service, which synchronizes the Windows NT users with the Netscape Directory Server. SSL is recommended in this configuration.

Restrictions

Derby does not support LDAP groups.

JNDI-Specific Properties for External Directory Services

Derby allows you to set a few advanced JNDI properties, which you can set in any of the supported ways of setting Derby properties. Typically you would set these at the same level (database or system) for which you configured the external authentication service.

The list of supported properties can be found in Appendix A: JNDI Context Environment in the Java Naming and Direction API at http://java.sun.com/products/jndi/reference/api/index.html. The external directory service must support the property.

Each JNDI provider has its set of properties that you can set within the Derby system.

For example, you can set the property java.naming.security.authentication to allow user credentials to be encrypted on the network if the provider supports it. You can also specify that SSL be used with LDAP (LDAPS).

User-Defined Class

Set derby.authentication.provider to the full name of a class that implements the public interface org.apache.derby.authentication.UserAuthenticator.

By writing your own class that fulfills some minimal requirements, you can hook Derby up to an external authentication service other than LDAP. To do so, specify an external authentication service by setting the property derby.authentication.provider to a class name that you want Derby to load at startup.

The class that provides the external authentication service must implement the public interface org.apache.derby.authentication.UserAuthenticator and throw exceptions of the type java.sql.SQLException where appropriate.

Using a user-defined class makes Derby adaptable to various naming and directory services.

A very simple example of a class that implements the interface follows.

import org.apache.derby.authentication.UserAuthenticator;
import java.io.FileInputStream;
import java.util.Properties;
import java.sql.SQLException;
/**
  * A simple example of a specialized Authentication scheme.
  * The system property 'derby.connection.requireAuthentication'
  * must be set
  * to true and 'derby.connection.specificAuthentication' must
  * contain the full class name of the overriden authentication
  * scheme,  i.e., the name of this class.
  *
  * @see org.apache.derby.authentication.UserAuthenticator 
  */
 
public class MyAuthenticationSchemeImpl implements
UserAuthenticator {
    private static final String USERS_CONFIG_FILE = "myUsers.cfg";
    private static Properties usersConfig;
 
   // Constructor
    // We get passed some Users properties if the 
    //authentication service could not set them as 
    //part of System properties.
    //
    public MyAuthenticationSchemeImpl() {
    }
    /* static block where we load the users definition from a
users configuration file.*/
 
    static {
       /* load users config file as Java properties
        File must be in the same directory where
        Derby  gets started.
       (otherwise full path must be specified) */
       FileInputStream in = null;
       usersConfig = new Properties();
       try {
           in = new FileInputStream(USERS_CONFIG_FILE);
           usersConfig.load(in);
           in.close();
       } catch (java.io.IOException ie) {
           // No Config file. Raise error message
           System.err.println(
             "WARNING: Error during Users Config file
retrieval");
           System.err.println("Exception: " + ie);
       }
    }
    /**
     * Authenticate the passed-in user's credentials.
     * A more complex class could make calls
     * to any external users directory.
     *
     * @param userName               The user's name
     * @param userPassword           The user's password 
     * @param databaseName           The database 
     * @param infoAdditional jdbc connection info.
     * @exception SQLException on failure
     */
    public boolean authenticateUser(String userName,
     String userPassword,
     String databaseName,
     Properties info)
       throws SQLException 
    {
      /* Specific Authentication scheme logic.
        If user has been authenticated, then simply return.
        If user name and/or password are invalid, 
        then raise the appropriate exception.
 
       This example allows only users defined in the
       users config properties object.
 
       Check if the passed-in user has been defined for the system.
       We expect to find and match the property corresponding to
       the credentials passed in. */
       if (userName == null)
          // We do not tolerate 'guest' user for now.
           return false;
       //
       // Check if user exists in our users config (file)
       // properties set.
       // If we did not find the user in the users config set, then
       // try to find if the user is defined as a System property.
       //
       String actualUserPassword;
       actualUserPassword = usersConfig.getProperty(userName);
       if (actualUserPassword == null)
           actualUserPassword = System.getProperty(userName);
       if (actualUserPassword == null)
            // no such passed-in user found
            return false;
            // check if the password matches
       if (!actualUserPassword.equals(userPassword))
       return false;
       // Now, check if the user is a valid user of the database
       if (databaseName != null)
       {
             /* if database users restriction lists present, then check 
            if there is one for this database and if so, 
            check if the user is a valid one of that database.
            For this example, the only user we authorize in database
            DarkSide is user 'DarthVader'. This is the only database
            users restriction list we have for this example.
            We authorize any valid (login) user to access the
            OTHER databases in the system.
            Note that database users ACLs could be set in the same
            properties file or a separate one and implemented as you
            wish. */
            //
           if (databaseName.equals("DarkSide")) {
              // check if user is a valid one.
              if (!userName.equals("DarthVader"))
                  // This user is not a valid one of the passed-in
                  return false;
           }
       }
       // The user is a valid one in this database
       return true;
    }
}

Previous Page
Next Page
Table of Contents
Index