Skip Headers
Oracle® Identity Management Application Developer's Guide
10g Release 2 (10.1.2)
Part No. B14087-01
  Go To Table Of Contents
Contents
Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Index
Index

Previous
Previous
Next
Next
 

3 Developing Applications with Oracle Extensions to the Standard APIs

This chapter presents the Oracle extensions to the LDAP APIs. It includes sample use cases.

This chapter contains these topics:

3.1 Using Oracle Extensions to the Standard APIs

The APIs that Oracle has added to the existing APIs fulfill these functions:

The primary users of the Oracle extensions are backend applications that must perform LDAP lookups for users, groups, applications, or hosted companies. This section explains how these applications integrate these API extensions into their program logic. The section contains these topics:

Figure 3-1 shows the placement of the API extensions in relation to existing APIs:

Figure 3-1 Oracle API Extensions

Description of oiddg008.gif follows
Description of the illustration oiddg008.gif

As Figure 3-1 shows, in the C, PL/SQL, and Java languages, the API extensions are layers that sit on top of existing APIs:

Applications must use the underlying APIs for such common tasks as establishing and closing connections and looking up directory entries not searchable with the API extensions.

Figure 3-2 shows what program flow looks like when the API extensions are used.

Figure 3-2 Programmatic Flow for API Extensions

Description of oiddg009.gif follows
Description of the illustration oiddg009.gif

As Figure 3-2 shows, an application first establishes a connection to Oracle Internet Directory. It can then use the standard API functions and the API extensions interchangeably.

3.1.1 Using the API Extensions in PL/SQL

Most of the extensions described in this chapter are helper functions. They access data about specific LDAP entities such as users, groups, realms, and applications. In many cases, these functions must pass a reference to one of these entities to the standard API functions. To do this, the API extensions use opaque data structures called handles. The steps that follow show an extension creating a user handle:

  1. Establish an LDAP connection or get one from a pool of connections.

  2. Create a user handle from user input. This could be a DN, a GUID, or a single sign-on user ID.

  3. Authenticate the user with the LDAP connection handle, user handle, or credentials.

  4. Free the user handle.

  5. Close the LDAP connection, or return the connection back to the connection pool.

3.1.2 Using the API Extensions in Java

This section describes:

  • The oracle.java.util package

  • The PropertySetCollection, PropertySet, and Property classes

3.1.2.1 The oracle.java.util Package

In Java, LDAP entities—users, groups, realms, and applications—are modeled as Java objects instead of as handles. This modeling is done in the oracle.java.util package. All other utility functionality is modeled either as individual objects—as, for example, GUID—or as static member functions of a utility class.

For example, to authenticate a user, an application must follow these steps:

  1. Create oracle.ldap.util.user object, given the user DN.

  2. Create a DirContext JNDI object with all of the required properties, or get one from a pool of DirContext objects.

  3. Invoke the User.authenticate function, passing in a reference to the DirContext object and the user credentials.

  4. If the DirContext object was retrieved from a pool of existing DirContext objects, return it to that pool.

Unlike their C and PL/SQL counterparts, Java programmers do not have to explicitly free objects. The Java garbage collection mechanism performs this task.

3.1.2.2 PropertySetCollection, PropertySet, and Property Classes

Many of the methods in the user, subscriber, and group classes return a PropertySetCollection object. The object represents a collection of one or more LDAP entries. Each of these entries is represented by a PropertySet object, identified by a DN. A property set can contain attributes, each represented as a property. A property is a collection of one or more values for the particular attribute it represents. An example of the use of these classes follows:

PropertySetCollection psc = Util.getGroupMembership( ctx,
                                                     myuser,
                                                     null,
                                                     true );
    // for loop to go through each PropertySet
    for (int i = 0; i < psc.size(); i++ ) {

    PropertySet ps = psc.getPropertySet(i);

   // Print the DN of each PropertySet
   System.out.println("dn:  " + ps .getDN());

   // Get the values for the "objectclass" Property
   Property objectclass = ps.getProperty( "objectclass" );

  
   // for loop to go through each value of Property "objectclass"
   for (int j = 0; j< objectclass.size(); j++) {

       // Print each "objectclass" value
       System.out.println("objectclass:  " + objectclass.getValue(j));
   }
}

The entity myuser is a user object. The psc object contains all the nested groups that myuser belongs to. The code loops through the resulting entries and prints out all the object class values of each entry.


See Also:

"Java Sample Code" on page B-23 for more sample uses of the PropertySetCollection, PropertySet, and Property classes

3.1.3 How the Standard APIs and The Oracle Extensions Are Installed

Table 3-1 explains how the APIs and their extensions are installed.

Table 3-1 How the APIs are Installed

Language Installation Method
Java API Installed as part of the LDAP client installation. The file, ldapjclnt10.jar, is found at ORACLE_HOME/jlib.
PL/SQL API Installed as part of the Oracle database server. Load it by using a script called catldap.sql, located at ORACLE_HOME/rdbms/admin.
C API To build applications with the C API, include the header file located at ORACLE_HOME/ldap/public/ldap.h; then link dynamically to the library located at ORACLE_HOME/lib/libclntsh.so.10.1.

3.2 Creating an Application Identity in the Directory

Before an application can use the LDAP APIs and their extensions, it must establish an LDAP connection. Once it establishes a connection, it must have permission to perform operations. But neither task can be completed if the application lacks an identity in the directory.

3.2.1 Creating an Application Identity

Creating an application identity in the directory is relatively simple. Such an entry requires only two object classes: orclApplicationEntity and top. You can use either Oracle Directory Manager or an LDIF file to create the entry. In LDIF notation, the entry looks like this:

dn: orclapplicationcommonname=application_name
changetype: add
objectclass:top
objectclass: orclApplicationEntity
userpassword: password

The value provided for userpassword is the value that the application uses to bind to the directory.

3.2.2 Assigning Privileges to an Application Identity

To learn about the privileges available to an application, see the chapter about delegating privileges for an Oracle technology deployment in Oracle Internet Directory Administrator's Guide. After identifying the right set of privileges, add the application entity DN to the appropriate directory groups. The link just provided explains how to perform this task using either Oracle Directory Manager or the ldapmodify command.

3.3 User Management Functionality

This section explains how the Java, PL/SQL, and C LDAP APIs are used to manage end users. It contains these topics:

3.3.1 User Operations Performed by Directory-Enabled Applications

Directory-enabled applications need to perform the following operations:

  • Retrieve properties of user entries

    These properties are stored as attributes of the user entry itself—in the same way, for example, that a surname or a home address is stored.

  • Retrieve extended user preferences

    These preferences apply to a user but are stored in a DIT different from the DIT containing user entries. Extended user preferences are either user properties common to all applications or user properties specific to an application. Those of the first type are stored in a common location in the Oracle Context. Those of the second type are stored in the application-specific DIT.

  • Query the group membership of a user

  • Authenticate a user given a simple name and credential

    Typically an application uses a fully qualified DN, GUID, or simple user name to identify a user. In a hosted environment, the application may use both a user name and a realm name for identification.

3.3.2 User Management APIs

This section looks at the user management features of the APIs.

3.3.2.1 Java API for User Management

As stated earlier, all user-related functionality is abstracted in a Java class called oracle.ldap.util.User. The process works like this:

  1. Construct a oracle.ldap.util.User object based on a DN, GUID, or simple name.

  2. Invoke User.authenticate(DirContext, Credentials) to authenticate the user if necessary.

  3. Invoke User.getProperties(DirContext) to get the attributes of the user entry.

  4. Invoke User.getExtendedProperties(DirContext, PropCategory, PropType) to get the extended properties of the user. PropCategory is either shared or application-specific. PropType is the object that represents the type of property desired. If PropType is null, all properties in a given category are retrieved.

  5. Invoke PropertyType.getDefinition(DirContext) to get the metadata required to parse the properties returned in step 4.

  6. Parse the extended properties and continue with application-specific logic. This parsing is also performed by application-specific logic.

3.3.2.2 C API for User Management

Oracle Internet Directory does not support the C API for user management.

3.3.2.3 PL/SQL API for User Management

The steps that follow show how the DBMS_LDAP_UTL package is used to create and use a handle that retrieves user properties from the directory.

  1. Invoke DBMS_LDAP_UTL.create_user_handle(user_hd, user_type, user_id) to create a user handle from user input. The input can be a DN, a GUID, or a single sign-on user ID.

  2. Invoke DBMS_LDAP_UTL.set_user_handle_properties(user_hd, property_type, property) to associate a realm with the user handle.

  3. Invoke DBMS_LDAP_UTL.get_user_properties(ld, user_handle, attrs, ptype, ret_pset_coll) to place the attributes of a user entry into a result handle.

  4. Invoke DBMS_LDAP_UTL.get_property_names(pset, property_names) and DBMS_LDAP_UTL.get_property_values(pset, property_name, property_values) to extract user attributes from the result handle that you obtained in step 3.

3.3.3 User Authentication

This section looks at the user authentication features of the APIs.

3.3.3.1 Java API for User Authentication

User authentication is a common LDAP operation that compares the credentials that a user provides at login with the user's credentials in the directory. Oracle Internet Directory supports the following:

  • Arbitrary attributes can be used during authentication

  • Appropriate password policy exceptions are returned by the authentication method. Note, however, that the password policy applies only to the userpassword attribute.

The following is a piece code that shows how the API is used to authenticate a user:

 // User user1 - is a valid User Object
        try
        {
                user1.authenticateUser(ctx,
User.CREDTYPE_PASSWD, "welcome");
 
                // or
                // user1.authenticateUser(ctx, <any
attribute>, <attribute value>);
        }
        catch (UtilException ue)
        {
                // Handle the password policy error
accordingly
                if (ue instanceof PasswordExpiredException)
                        // do something
                else if (ue instanceof GraceLoginException)
                        // do something
        }

3.3.3.2 PL/SQL API for User Authentication

Use DBMS_LDAP_UTL.authenticate_user(session, user_handle, auth_type, cred, binary_cred) to authenticate a user to the directory. This function compares the password provided by the user with the password attribute in the user's directory entry.

3.3.3.3 C API for User Authentication

Oracle Internet Directory does not support the C API for user authentication.

3.3.4 User Creation

This section looks at the user creation features of the APIs.

3.3.4.1 Java API for User Creation

The subscriber class uses the createUser() method to programmatically create users. The object classes required by a user entry are configurable through Oracle Delegated Administration Services. The createUser() method assumes that the client understands the requirement and supplies the values for the mandatory attributes during user creation. If the programmer does not supply the required information the server will return an error.

The following snippet of sample code demonstrates the usage.

// Subscriber sub is a valid Subscriber object
// DirContext ctx is a valid DirContext
 
// Create ModPropertySet object to define all the attributes and their values.
ModPropertySet mps = new ModPropertySet();
mps.addProperty(LDIF.ATTRIBUTE_CHANGE_TYPE_ADD,"cn", "Anika");
mps.addProperty(LDIF.ATTRIBUTE_CHANGE_TYPE_ADD,"sn", "Anika");
mps.addProperty(LDIF.ATTRIBUTE_CHANGE_TYPE_ADD,"mail",
"Anika@oracle.com");
 
// Create user by specifying the nickname and the ModPropertySet just defined
User newUser = sub.createUser( ctx, mps);
 
// Print the newly created user DN
System.out.println( newUser.getDN(ctx) );
 
// Perform other operations with this new user

3.3.4.2 PL/SQL API for User Creation

Oracle Internet Directory does not support the PL/SQL API for user creation.

3.3.4.3 C API for User Creation

Oracle Internet Directory does not support the PL/SQL API for user creation.

3.3.5 User Object Retrieval

This section describes user object retrieval features of the Java, PL/SQL, and C LDAP APIs.

3.3.5.1 Java API for User Object Retrieval

The subscriber class offers the getUser() method to replace the public constructors of the User class. A user object is returned based on the specified information.

The following is a piece of sample code demonstrating the usage:

// DirContext ctx is contains a valid directory connection with
sufficient privilege to perform the operations
 
// Creating RootOracleContext object
RootOracleContext roc = new RootOracleContext(ctx);
 
// Obtain a Subscriber object representing the default
subscriber
Subscriber sub = roc.getSubscriber(ctx,
Util.IDTYPE_DEFAULT, null, null);
 
// Obtain a User object representing the user whose
nickname is "Anika"
User user1 = sub.getUser(ctx, Util.IDTYPE_SIMPLE, "Anika",
null);
// Do work with this user
 
The getUser() method can retrieve users based on DN, GUID
and simple name.  A getUsers() method is also available to
perform a filtered search to return more than one user at a
time.  The returned object is an array of User objects.
For example,
 
// Obtain an array of User object where the user's nickname
starts with "Ani"
User[] userArr = sub.getUsers(ctx, Util.IDTYPE_SIMPLE,
"Ani", null);
// Do work with the User array

3.3.5.2 PL/SQL API for User Object Retrieval

Oracle Internet Directory does not support the PL/SQL API for user object retrieval.

3.3.5.3 C API for User Object Retrieval

Oracle Internet Directory does not support the C API for user object retrieval.

3.4 Group Management Functionality

This section describes the group management features of the Java, PL/SQL, and C LDAP APIs.

Groups are modeled in Oracle Internet Directory as a collection of distinguished names. Directory-enabled applications must access Oracle Internet Directory to obtain the properties of a group and to verify that a given user is a member of that group.

A group is typically identified by one of the following:

3.5 Identity Management Realm Functionality

This section describes the identity management realm features of the Java, PL/SQL, and C LDAP APIs.

An identity management realm is an entity or organization that subscribes to the services offered in the Oracle product stack. Directory-enabled applications must access Oracle Internet Directory to obtain realm properties such as user search base or password policy.

A realm is typically identified by one of the following:

3.5.1 Realm Object Retrieval for the Java API

This section describes how the Java API can be used to retrieve objects in identity management realms.

The RootOracleContext class represents the root Oracle Context. Much of the information needed for identity management realm creation is stored within the root Oracle Context. The RootOracleContext class offers the getSubscriber() method. It replaces the public constructors of the subscriber class and returns an identity management realm object based on the specified information.

The following is a piece of sample code demonstrating the usage:

// DirContext ctx contains a valid directory
// connection with sufficient privilege to perform the
// operations
 
// Creating RootOracleContext object
RootOracleContext roc = new RootOracleContext(ctx);
 
// Obtain a Subscriber object representing the
// Subscriber with simple name "Oracle"
Subscriber sub = roc.getSubscriber(ctx,
Util.IDTYPE_SIMPLE, "Oracle", null);
 
// Do work with the Subscriber object

3.6 Server Discovery Functionality

Directory server discovery (DSD) enables automatic discovery of the Oracle directory server by directory clients. It enables deployments to manage the directory host name and port number information in the central DNS server. All directory clients perform a DNS query at runtime and connect to the directory server. Directory server location information is stored in a DNS service location record (SRV).

An SRV contains:

DSD also allows clients to discover the directory host name information from the ldap.ora file itself.

This section contains these topics:


See Also:

  • "Discovering LDAP Services with DNS" by Michael P. Armijo at this URL:

    http://www.ietf.org/
    
    
  • "A DNS RR for specifying the location of services (DNS SRV)", Internet RFC 2782 at the same URL.


3.6.1 Benefits of Oracle Internet Directory Discovery Interfaces

Typically, the LDAP host name and port information is provided statically in a file called ldap.ora which is located on the client in ORACLE_HOME/network/admin. For large deployments with many clients, this information becomes very cumbersome to manage. For example, each time the host name or port number of a directory server is changed, the ldap.ora file on each client must be modified.

Directory server discovery eliminates the need to manage the host name and port number in the ldap.ora file. Because the host name information resides on one central DNS server, the information must be updated only once. All clients can then discover the new host name information dynamically from the DNS when they connect to it.

DSD provides a single interface to obtain directory server information without regard to the mechanism or standard used to obtain it. Currently, Oracle directory server information can be obtained either from DNS or from ldap.ora using a single interface.

3.6.2 Usage Model for Discovery Interfaces

The first step in discovering host name information is to create a discovery handle. A discovery handle specifies the source from which host name information will be discovered. In case of the Java API, the discovery handle is created by creating an instance of the oracle.ldap.util.discovery.DiscoveryHelper class.

DiscoveryHelper disco = new DiscoveryHelper(DiscoveryHelper.DNS_DISCOVER);

The argument DiscoveryHelper.DNS_DISCOVER specifies the source. In this case the source is DNS.

Each source may require some inputs to be specified for discovery of host name information. In the case of DNS these inputs are:

  • domain name

  • discover method

  • SSL mode

Detailed explanation of these options is given in Determining Server Name and Port Number From DNS.

// Set the property for the DNS_DN
disco.setProperty(DiscoveryHelper.DNS_DN,"dc=us,dc=fiction,dc=com");
// Set the property for the DNS_DISCOVER_METHOD
disco.setProperty(DiscoveryHelper.DNS_DISCOVER_METHOD
                                 ,DiscoveryHelper.USE_INPUT_DN_METHOD);
// Set the property for the SSLMODE
disco.setProperty(DiscoveryHelper.SSLMODE,"0");

Now the information can be discovered.

// Call the discover method
disco.discover(reshdl);

The discovered information is returned in a result handle (reshdl). Now the results can be extracted from the result handle.

ArrayList result =
(ArrayList)reshdl.get(DiscoveryHelper.DIR_SERVERS);
if (result != null)
{
   if (result.size() == 0) return;
   System.out.println("The hostnames are :-");
   for (int i = 0; i< result.size();i++)
   {
      String host = (String)result.get(i);
System.out.println((i+1)+".
'"+host+"'");
   }
}

3.6.3 Determining Server Name and Port Number From DNS

Determining a host name and port number from a DNS lookup involves obtaining a domain and then searching for SRV resource records based on that domain. If there is more than one SRV resource record, they are sorted by weight and priority. The SRV resource records contain host names and port numbers required for connection. This information is retrieved from the resourcerecords and returned to the user.

There are three approaches for determining the domain name required for lookup:

  • Mapping the distinguished name (DN) of the naming context

  • Using the domain component of local machine

  • Looking up the default SRV record in the DNS

3.6.3.1 Mapping the DN of the Naming Context

The first approach is to map the distinguished name (DN) of naming context into domain name using the algorithm given here.

The output domain name is initially empty. The DN is processed sequentially from right to left. An RDN is able to be converted if it meets the following conditions:

  • It consists of a single attribute type and value

  • The attribute type is dc

  • The attribute value is non-null

If the RDN can be converted, then the attribute value is used as a domain name component (label).

The first such value becomes the rightmost, and the most significant, domain name component. Successive converted RDN values extend to the left. If an RDN cannot be converted, then processing stops. If the output domain name is empty when processing stops, then the DN cannot be converted into a domain name.

For the DN cn=John Doe,ou=accounting,dc=example,dc=net, the client converts the dc components into the DNS name example.net.

3.6.3.2 Search by Domain Component of Local Machine

Sometimes a DN cannot be mapped to a domain name. For example, the DN o=Oracle IDC,Bangalore cannot be mapped to a domain name. In this case, the second approach uses the domain component of the local machine on which the client is running. For example, if the client machine domain name is mc1.acme.com, the domain name for the lookup is acme.com.

3.6.3.3 Search by Default SRV Record in DNS

The third approach looks for a default SRV record in the DNS. This record points to the default server in the deployment. The domain component for this default record is _default.

Once the domain name has been determined, it is used to send a query to DNS. The DNS is queried for SRV records specified in Oracle Internet Directory-specific format. For example, if the domain name obtained is example.net, the query for non-SSL LDAP servers is for SRV resource records having the owner name _ldap._tcp._oid.example.net.

It is possible that no SRV resource records are returned from the DNS. In such a case the DNS lookup is performed for the SRV resource records specified in standard format. For example, the owner name would be _ldap._tcp.example.net.


See Also:

The chapter about directory administration in Oracle Internet Directory Administrator's Guide

The result of the query is a set of SRV records. These records are then sorted and the host information is extracted from them. This information is then returned to the user.


Note:

The approaches mentioned here can also be tried in succession, stopping when the query lookup of DNS is successful. Try the approaches in the order as described in this section. DNS is queried only for SRV records in Oracle Internet Directory-specific format. If none of the approaches is successful, then all the approaches are tried again, but this time DNS is queried for SRV records in standard format.

3.6.4 Environment Variables for DNS Server Discovery

The following environment variables override default behavior for discovering a DNS server.

Table 3-2 Environment Variables for DNS Discovery

Environment Variable Description
ORA_LDAP_DNS
IP address of the DNS server containing the SRV records. If the variable is not defined, then the DNS server address is obtained from the host machine.
ORA_LDAP_DNSPORT
Port number on which the DNS server listens for queries. If the variable is not defined, then the DNS server is assumed to be listening at standard port number 53.
ORA_LDAP_DOMAIN
Domain of the host machine. If the variable is not defined, then the domain is obtained from the host machine itself.

3.6.5 Programming Interfaces for DNS Server Discovery

The programming interface provided is a single interface to discover directory server information without regard to the mechanism or standard used to obtain it. Information can be discovered from various sources. Each source can use its own mechanism to discover the information. For example, the LDAP host and port information can be discovered from the DNS acting as the source. Here DSD is used to discover host name information from the DNS.


See Also:

For detailed reference information and class descriptions, refer to the Javadoc located on the product CD.

3.6.6 Java APIs for Server Discovery

A new Java class, the public class, has been introduced:

public     class                 oracle.ldap.util.discovery.DiscoveryHelper

This class provides a method for discovering specific information from the specified source.

Table 3-3 Methods for Directory Server Discovery

Method Description
discover
Discovers the specific information from a given source
setProperty
Sets the properties required for discovery
getProperty
Accesses the value of properties

Two new methods are added to the existing Java class oracle.ldap.util.jndi.ConnectionUtil:

  • getDefaultDirCtx: This overloaded function determines the host name and port information of non-SSL ldap servers by making an internal call to oracle.ldap.util.discovery.DiscoveryHelper.discover().

  • getSSLDirCtx: This overloaded function determines the host name and port information of SSL ldap servers by making an internal call to oracle.ldap.util.discovery.DiscoveryHelper.discover().

3.6.7 Examples: Java API for Directory Server Discovery

The following is a sample Java program for directory server discovery:

import java.util.*;
import java.lang.*;
import oracle.ldap.util.discovery.*;
import oracle.ldap.util.jndi.*;
 
public class dsdtest
{
  public static void main(String s[]) throws Exception
  {
    HashMap reshdl = new HashMap();
    String result = new String();
    Object resultObj = new Object();
    DiscoveryHelper disco = new
DiscoveryHelper(DiscoveryHelper.DNS_DISCOVER);
 
// Set the property for the DNS_DN
disco.setProperty(DiscoveryHelper.DNS_DN,"dc=us,dc=fiction,dc=com")
;
 
// Set the property for the DNS_DISCOVER_METHOD
disco.setProperty(DiscoveryHelper.DNS_DISCOVER_METHOD
                                 ,DiscoveryHelper.USE_INPUT_DN_METHOD);
 
// Set the property for the SSLMODE
disco.setProperty(DiscoveryHelper.SSLMODE,"0");
 
// Call the discover method
int res=disco.discover(reshdl);
if (res!=0)
   System.out.println("Error Code returned by the discover method is :"+res) ;
 
// Print the results
printReshdl(reshdl);
}
 
public static void printReshdl(HashMap reshdl)
{
  ArrayList result = (ArrayList)reshdl.get(DiscoveryHelper.DIR_SERVERS);
 
if (result != null)
{
  if (result.size() == 0) return;
  System.out.println("The hostnames are :-");
  for (int i = 0; i< result.size();i++)
  {
      String host = (String)result.get(i);
      System.out.println((i+1)+".
'"+host+"'");
   }
  }
 }
}

3.7 SASL Authentication Functionality

Oracle Internet Directory supports two mechanisms for SASL-based authentication. This section describes the two methods. It contains these topics:

3.7.1 SASL Authentication by Using the DIGEST-MD5 Mechanism

SASL Digest-MD5 authentication is the required authentication mechanism for LDAP Version 3 servers (RFC 2829). LDAP Version 2 does not support Digest-MD5.

The Digest-MD5 mechanism is described in RFC 2831 of the Internet Engineering Task Force. It is based on the HTTP Digest Authentication (RFC 2617).


See Also:

Internet Engineering Task Force Web site:
http://www.ietf.org

This section contains these topics:

  • Steps Involved in SASL Authentication by Using DIGEST-MD5

  • JAVA APIs for SASL Authentication by Using DIGEST-MD5

  • C APIs for SASL authentication using DIGEST-MD5

  • SASL Authentication by Using External Mechanism

3.7.1.1 Steps Involved in SASL Authentication by Using DIGEST-MD5

SASL Digest-MD5 authenticates a user as follows:

  1. The directory server sends data that includes various authentication options that it supports and a special token to the LDAP client.

  2. The client responds by sending an encrypted response that indicates the authentication options that it has selected. The response is encrypted in such a way that proves that the client knows its password.

  3. The directory server then decrypts and verifies the client's response.

To use the Digest-MD5 authentication mechanism, you can use either the Java API or the C API to set up the authentication.

3.7.1.2 JAVA APIs for SASL Authentication by Using DIGEST-MD5

When using JNDI to create a SASL connection, you must set these javax.naming.Context properties:

  • Context.SECURITY_AUTHENTICATION = "DIGEST-MD5"

  • Context.SECURITY_PRINCIPAL

The latter sets the principal name. This name is a server-specific format. It can be either of the following:

  • The DN—that is, dn:—followed by the fully qualified DN of the entity being authenticated

  • The string u:followed by the user identifier.

    The Oracle directory server accepts just a fully qualified DN such as cn=user,ou=my department,o=my company.


Note:

The SASL DN must be normalized before it is passed to the C or Java API that calls the SASL bind. To generate SASL verifiers, Oracle Internet Directory supports only normalized DNs.

3.7.2 SASL Authentication by Using External Mechanism

The following is from section 7.4 of RFC 2222 of the Internet Engineering Task Force.

The mechanism name associated with external authentication is "EXTERNAL". The client sends an initial response with the authorization identity. The server uses information, external to SASL, to determine whether the client is authorized to authenticate as the authorization identity. If the client is so authorized, the server indicates successful completion of the authentication exchange; otherwise the server indicates failure.

The system providing this external information may be, for example, IPsec or SSL/TLS.

If the client sends the empty string as the authorization identity (thus requesting the authorization identity be derived from the client's authentication credentials), the authorization identity is to be derived from authentication credentials that exist in the system which is providing the external authentication.

Oracle Internet Directory provides the SASL external mechanism over an SSL mutual connection. The authorization identity (DN) is derived from the client certificate during the SSL network negotiation.

3.8 Proxying on Behalf of End Users

Often applications must perform operations that require impersonating an end user. An application may, for example, want to retrieve resource access descriptors for an end user. (Resource access descriptors are discussed in the concepts chapter of Oracle Internet Directory Administrator's Guide.)

A proxy switch occurs at run time on the JNDI context. An LDAP v3 feature, proxying can only be performed using InitialLdapContext, a subclass of InitialDirContext. If you use the Oracle extension oracle.ldap.util.jndi.ConnectionUtil to establish a connection (the example following), InitialLdapContext is always returned. If you use JNDI to establish the connection, make sure that it returns InitialLdapContext.

To perform the proxy switch to an end user, the user DN must be available. To learn how to obtain the DN, see the sample implementation of the oracle.ldap.util.User class at this URL:

http://www.oracle.com/technology/sample_code/id_mgmt

This code shows how the proxy switch occurs:

import oracle.ldap.util.jndi.*;
import javax.naming.directory.*;
import javax.naming.ldap.*;
import javax.naming.*;

public static void main(String args[])
{
  try{
       InitialLdapContext appCtx=ConnectionUtil.getDefaultDirCtx(args[0], // host
                                                                 args[1], // port
                                                                 args[2], // DN
                                                                 args[3]; // pass)
         // Do work as application
         // . . .
         String userDN=null;
         // assuming userDN has the end user DN value
         // Now switch to end user
         ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, userDN);
         ctx.addToEnvironment("java.naming.security.credentials", "");
         Control ctls[] = {
           new ProxyControl()
         };
         ((LdapContext)ctx).reconnect(ctls);
         // Do work on behalf of end user
         // . . .
      }
    catch(NamingException ne)
      {
       // javax.naming.NamingException is thrown when an error occurs 
      }
}

The ProxyControl class in the code immediately preceding implements a javax.naming.ldap.Control. To learn more about LDAP controls, see the section about supported controls in the schema appendix of Oracle Internet Directory Administrator's Guide. Here is an example of what the ProxyControl class might look like:

import javax.naming.*;
import javax.naming.ldap.Control;
import java.lang.*;
 
public class ProxyControl implements Control {
 
   public byte[] getEncodedValue() {
        return null;
   }
 
   public String getID() {
      return "2.16.840.1.113894.1.8.1";
   }
 
   public boolean isCritical() {
      return false;
   }
}

3.9 Creating Dynamic Password Verifiers

You can modify standard APIs to generate application passwords dynamically—that is, when users log in to an application. This feature has been designed to meet the needs of applications that provide parameters for password verifiers only at runtime.

This section contains the following topics:

3.9.1 Request Control for Dynamic Password Verifiers

Creating a password verifier dynamically involves modifying the LDAP authentication APIs ldap_search or ldap_modify to include parameters for password verifiers. An LDAP control called DynamicVerifierRequestControl is the mechanism for transmitting these parameters. It takes the place of the password verifier profile used to create password verifiers statically. Nevertheless, dynamic verifiers, like static verifiers, require that the directory attributes orclrevpwd (synchronized case) and orclunsyncrevpwd (unsynchronized case) be present and that these attributes be populated.

Note that the orclpwdencryptionenable attribute of the password policy entry in the user's realm must be set to 1 if orclrevpwd is to be generated. If you fail to set this attribute, an exception is thrown when the user tries to authenticate. To generate orclunsyncrevpwd, you must add the crypto type 3DES to the entry cn=defaultSharedPINProfileEntry,cn=common,cn=products,cn=oraclecontext.

3.9.2 Syntax for DynamicVerifierRequestControl

The request control looks like this:

DynamicVerifierRequestControl
controlOid:  2.16.840.1.113894.1.8.14  
criticality:  FALSE
controlValue: an OCTET STRING whose value is the BER encoding of the following type:

ControlValue ::= SEQUENCE {

                  version [0]
                  crypto  [1] CHOICE OPTIONAL {
                     SASL/MD5  [0] LDAPString,
                     SyncML1.0 [1] LDAPString,
                     SyncML1.1 [2] LDAPString, 
                     CRAM-MD5  [3] LDAPString },
                  username [1] OPTIONAL LDAPString,
                  realm    [2] OPTIONAL LDAPString,
                  nonce    [3] OPTIONAL LDAPString,
                 }

Note that the parameters in the control structure must be passed in the order in which they appear. Table 3-4 defines these parameters.

Table 3-4 Parameters in DynamicVerifierRequestControl

Parameter Description
controlOID
The string that uniquely identifies the control structure.
crypto
The hashing algorithm. Choose one of the four identified in the control structure.
username
The distinguished name (DN) of the user. This value must always be included.
realm
A randomly chosen realm. It may be the identity management realm that the user belongs to. It may even be an application realm. Required only by the SASL/MD5 algorithm.
nonce
An arbitrary, randomly chosen value. Required by SYNCML1.0 and SYNCML1.1.

3.9.3 Parameters Required by the Hashing Algorithms

Table 3-5 lists the four hashing algorithms that are used to create dynamic password verifiers. The table also lists the parameters that each algorithm uses as building blocks. Note that, although all algorithms use the user name and password parameters, they differ in their use of the realm and nonce parameters.

Table 3-5 Parameters Required by the Hashing Algorithms

Algorithm Parameters Required
SASL/MD5 username, realm, password
SYNCML1.0 username, password, nonce
SYNCML1.1 username, password, nonce
CRAM-MD5 username, password

3.9.4 Configuring the Authentication APIs

Applications that require password verifiers to be generated dynamically must include DynamicVerifierRequestControl in their authentication APIs. Either ldap_search or ldap_compare must incorporate the controlOID and the control values as parameters. They must BER-encode the control values as shown in "Syntax for DynamicVerifierRequestControl"; then they must send both controlOID and the control values to the directory server.

3.9.4.1 Parameters Passed If ldap_search Is Used

If you want the application to authenticate the user, use ldap_search to pass the control structure. If ldap_search is used, the directory passes the password verifier that it creates to the client.

ldap_search must include the DN of the user, the controlOID, and the control values. If the user's password is a single sign-on password, the attribute passed is authpassword. If the password is a numeric pin or another type of unsynchronized password, the attribute passed is orclpasswordverifier;orclcommonpin.

3.9.4.2 Parameters Passed If ldap_compare Is Used

If you want Oracle Internet Directory to authenticate the user, use ldap_compare to pass the control structure. In this case, the directory retains the verifier and authenticates the user itself.

Like ldap_search, ldap_compare must include the DN of the user, the controlOID, the control values, and the user's password attribute. For ldap_compare, the password attribute is orclpasswordverifier;orclcommonpin (unsynchronized case).

3.9.5 Response Control for Dynamic Password Verifiers

When it encounters an error, the directory sends the LDAP control DynamicVerifierResponseControl to the client. This response control contains the error code. To learn about the error codes that the response control sends, see the troubleshooting chapter in Oracle Internet Directory Administrator's Guide.

3.9.6 Obtaining Privileges for the Dynamic Verifier Framework

If you want the directory to create password verifiers dynamically, you must add your application identity to the VerifierServices group of directory administrators. If you fail to perform this task, the directory returns an LDAP_INSUFFICIENT_ACCESS error.

3.10 Dependencies and Limitations for the PL/SQ LDAP API

The PL/SQL LDAP API for this release has the following limitations: