Oracle® Identity Management Application Developer's Guide
10g Release 2 (10.1.2) Part No. B14087-01 |
|
![]() Previous |
![]() Next |
This chapter presents the Oracle extensions to the LDAP APIs. It includes sample use cases.
This chapter contains these topics:
The APIs that Oracle has added to the existing APIs fulfill these functions:
User management
Applications can set or retrieve various user properties
Group management
Applications can query group properties
Realm management
Applications can set or retrieve properties about identity management realms
Server discovery management
Applications can locate a directory server in the Domain Name System (DNS)
SASL management
Applications can authenticate to the directory using SASL Digest-MD5
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:
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.
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.
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:
Establish an LDAP connection or get one from a pool of connections.
Create a user handle from user input. This could be a DN, a GUID, or a single sign-on user ID.
Authenticate the user with the LDAP connection handle, user handle, or credentials.
Free the user handle.
Close the LDAP connection, or return the connection back to the connection pool.
This section describes:
The oracle.java.util
package
The PropertySetCollection
, PropertySet
, and Property
classes
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:
Create oracle.ldap.util.user
object, given the user DN.
Create a DirContext
JNDI object with all of the required properties, or get one from a pool of DirContext
objects.
Invoke the User.authenticate function, passing in a reference to the DirContext
object and the user credentials.
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.
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 thePropertySetCollection , PropertySet , and Property classes
|
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 .
|
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.
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.
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.
This section explains how the Java, PL/SQL, and C LDAP APIs are used to manage end users. It contains these topics:
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.
This section looks at the user management features of the APIs.
As stated earlier, all user-related functionality is abstracted in a Java class called oracle.ldap.util.User
. The process works like this:
Construct a oracle.ldap.util.User
object based on a DN, GUID, or simple name.
Invoke User.authenticate(DirContext, Credentials)
to authenticate the user if necessary.
Invoke User.getProperties(DirContext)
to get the attributes of the user entry.
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.
Invoke PropertyType.getDefinition(DirContext)
to get the metadata required to parse the properties returned in step 4.
Parse the extended properties and continue with application-specific logic. This parsing is also performed by application-specific logic.
Oracle Internet Directory does not support the C 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.
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.
Invoke DBMS_LDAP_UTL.set_user_handle_properties(user_hd, property_type, property)
to associate a realm with the user handle.
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.
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.
This section looks at the user authentication features of the APIs.
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 }
This section looks at the user creation features of the APIs.
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
This section describes user object retrieval features of the Java, PL/SQL, and C LDAP APIs.
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
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:
A fully qualified LDAP distinguished name
A global unique identifier
A simple group name along with a subscriber name
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:
A fully qualified LDAP distinguished name
A global unique identifier
A simple enterprise name
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
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:
The DNS name of the server providing LDAP service
The port number of the corresponding port
Any parameters that enable the client to choose an appropriate server from multiple servers
DSD also allows clients to discover the directory host name information from the ldap.ora
file itself.
This section contains these topics:
See Also:
|
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.
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+"'"); } }
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
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
.
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
.
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. |
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. |
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. |
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()
.
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+"'"); } } } }
Oracle Internet Directory supports two mechanisms for SASL-based authentication. This section describes the two methods. It contains these topics:
SASL Authentication by Using the DIGEST-MD5 Mechanism
SASL Authentication by Using External 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).
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
SASL Digest-MD5 authenticates a user as follows:
The directory server sends data that includes various authentication options that it supports and a special token to the LDAP client.
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.
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.
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. |
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.
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; } }
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:
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
.
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. |
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.
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.
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
.
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).
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.
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.
The PL/SQL LDAP API for this release has the following limitations:
The LDAP session handles obtained from the API are valid only for the duration of the database session. The LDAP session handles cannot be written to a table and reused in other database sessions.
Only synchronous versions of LDAP API functions are supported in this release.
The PL/SQL LDAP API requires a database connection to work. It cannot be used in client-side PL/SQL engines (like Oracle Forms) without a valid database connection.