Oracle® Identity Management Application Developer's Guide
10g Release 2 (10.1.2) B14087-02 |
|
Previous |
Next |
This chapter takes a high-level look at the operations that the standard LDAP API enables. It explains how to integrate your applications with the API. Before presenting these topics, the chapter revisits the Lightweight Directory Access Protocol (LDAP).
This chapter contains these topics:
Sample code is available at this URL:
http://www.oracle.com/technology/sample_code/
Look for the Oracle Identity Management link under Sample Applications–Oracle Application Server.
LDAP began as a lightweight front end to the X.500 Directory Access Protocol. LDAP simplifies the X.500 Directory Access Protocol in the following ways:
It uses TCP/IP connections. These are lightweight compared to the OSI communication stack required by X.500 implementations
It eliminates little-used and redundant features of the X.500 Directory Access Protocol
It uses simple formats to represent data elements. These formats are easier to process than the complicated and highly structured representations in X.500.
It uses a simplified version of the X.500 encoding rules used to transport data over networks.
LDAP uses four basic models to define its operations:
The LDAP naming model enables directory information to be referenced and organized. Each entry in a directory is uniquely identified by a distinguished name (DN). The DN tells you exactly where an entry resides in the directory hierarchy. A directory information tree (DIT) is used to represent this hierarchy.
Figure 2-1 illustrates the relationship between a distinguished name and a directory information tree.
The DIT in Figure 2-1 shows entries for two employees of Acme Corporation who are both named Anne Smith. It is structured along geographical and organizational lines. The Anne Smith represented by the left branch works in the Sales division in the United States. Her counterpart works in the Server Development division in the United Kingdom.
The Anne Smith represented by the right branch has the common name (cn
) Anne Smith. She works in an organizational unit (ou
) named Server Development, in the country (c
) of United Kingdom of Great Britain and Northern Ireland (uk
), in the organization (o
) Acme. The DN for this Anne Smith entry looks like this:
cn=Anne Smith,ou=Server Development,c=uk,o=acme
Note that the conventional format for a distinguished name places the lowest DIT component at the left. The next highest component follows, on up to the root.
Within a distinguished name, the lowest component is called the relative distinguished name (RDN). In the DN just presented, the RDN is cn=Anne Smith
. The RDN for the entry immediately above Anne Smith's RDN is ou=Server Development
. And the RDN for the entry immediately above ou=Server Development
is c=uk
, and so on. A DN is thus a sequence of RDNs separated by commas.
To locate a particular entry within the overall DIT, a client uniquely identifies that entry by using the full DN—not simply the RDN—of that entry. To avoid confusion between the two Anne Smiths in the global organization depicted in Figure 2-1, you use the full DN for each. If there are two employees with the same name in the same organizational unit, you can use other mechanisms. You may, for example, use a unique identification number to identify these employees.
The LDAP information model determines the form and character of information in the directory. This model uses the concept of entries as its defining characteristic. In a directory, an entry is a collection of information about an object. A telephone directory, for example, contains entries for people. A library card catalog contains entries for books. An online directory may contain entries for employees, conference rooms, e-commerce partners, or shared network resources such as printers.
In a typical telephone directory, a person entry contains an address and a phone number. In an online directory, each of these pieces of information is called an attribute. A typical employee entry contains attributes for a job title, an e-mail address, and a phone number.
In Figure 2-2, the entry for Anne Smith in Great Britain (uk) has several attributes. Each provides specific information about her. Those listed in the balloon to the right of the tree are emailaddrs
, printername
, jpegPhoto
, and app preferences
. Note that the rest of the bullets in Figure 2-2 are also entries with attributes, although these attributes are not shown.
Each attribute consists of an attribute type and one or more attribute values. The attribute type is the kind of information that the attribute contains—jobTitle
, for instance. The attribute value is the actual information. The value for the jobTitle
attribute, for example, might be manager
.
The LDAP functional model determines what operations can be performed on directory entries. Table 2-1 lists and describes the three types of functions:
Table 2-1 LDAP Functions
Function | Description |
---|---|
Search and read |
The read operation retrieves the attributes of an entry whose name is known. The list operation enumerates the children of a given entry. The search operation selects entries from a defined area of the tree based on some selection criteria known as a search filter. For each matching entry, a requested set of attributes (with or without values) is returned. The searched entries can span a single entry, an entry's children, or an entire subtree. Alias entries can be followed automatically during a search, even if they cross server boundaries. An abandon operation is also defined, allowing an operation in progress to be canceled. |
Modify |
This category defines four operations that modify the directory:
|
Authenticate |
This category defines a bind operation. A bind enables a client to initiate a session and prove its identity to the directory. Oracle Internet Directory supports several authentication methods, from simple clear-text passwords to public keys. The unbind operation is used to terminate a directory session. |
The LDAP security model enables directory information to be secured. This model has several parts:
Ensuring that the identities of users, hosts, and clients are correctly validated
Access Control and Authorization
Ensuring that a user reads or updates only the information for which that user has privileges
Data Integrity: Ensuring that data is not modified during transmission
Ensuring that data is not disclosed during transmission
Setting rules that govern how passwords are used
Authentication is the process by which the directory server establishes the identity of the user connecting to the directory. Directory authentication occurs when an LDAP bind operation establishes an LDAP session. Every session has an associated user identity, also referred to as an authorization ID.
Oracle Internet Directory provides three authentication options: anonymous, simple, and SSL.
If your directory is available to everyone, users may log in anonymously. In anonymous authentication, users leave the user name and password fields blank when they log in. They then exercise whatever privileges are specified for anonymous users.
In simple authentication, the client uses an unencrypted DN and password to identify itself to the server. The server verifies that the client's DN and password match the DN and password stored in the directory.
Secure Sockets Layer (SSL) is an industry standard protocol for securing network connections. It uses a certificate exchange to authenticate users. These certificates are verified by trusted certificate authorities. A certificate ensures that an entity's identity information is correct. An entity can be an end user, a database, an administrator, a client, or a server. A Certificate Authority (CA) is an application that creates public key certificates that are given a high level of trust by all parties involved.
You can use SSL in one of the three authentication modes presented in Table 2-2.
Table 2-2 SSL Authentication Modes
SSL Mode | Description |
---|---|
Neither the client nor the server authenticates itself to the other. No certificates are sent or exchanged. In this case, only SSL encryption and decryption are used. |
|
Only the directory server authenticates itself to the client. The directory server sends the client a certificate verifying that the server is authentic. |
|
Both client and server authenticate themselves to each other, exchanging certificates. |
In an Oracle Internet Directory environment, SSL authentication between a client and a directory server involves three basic steps:
The user initiates an LDAP connection to the directory server by using SSL on an SSL port. The default SSL port is 636
.
SSL performs the handshake between the client and the directory server.
If the handshake is successful, the directory server verifies that the user has the appropriate authorization to access the directory.
See Also: Oracle Advanced Security Administrator's Guide for more information about SSL |
The authorization process ensures that a user reads or updates only the information for which he or she has privileges. The directory server ensures that the user— identified by the authorization ID associated with the session—has the requisite permissions to perform a given directory operation. Absent these permissions, the operation is disallowed.
The mechanism that the directory server uses to ensure that the proper authorizations are in place is called access control. And an access control item (ACI) is the directory metadata that captures the administrative policies relating to access control.
An ACI is stored in Oracle Internet Directory as user-modifiable operational attributes. Typically a whole list of these ACI attribute values is associated with a directory object. This list is called an access control list (ACL). The attribute values on that list govern the access policies for the directory object.
ACIs are stored as text strings in the directory. These strings must conform to a well-defined format. Each valid value of an ACI attribute represents a distinct access control policy. These individual policy components are referred to as ACI Directives or ACIs and their format is called the ACI Directive format.
Access control policies can be prescriptive: their security directives can be set to apply downward to all entries at lower positions in the directory information tree (DIT). The point from which an access control policy applies is called an access control policy point (ACP).
Oracle Internet Directory uses SSL to ensure that data is not modified, deleted, or replayed during transmission. This feature uses cryptographic checksums to generate a secure message digest. The checksums are created using either the MD5 algorithm or the Secure Hash Algorithm (SHA). The message digest is included in each network packet.
Oracle Internet Directory uses public key encryption over SSL to ensure that data is not disclosed during transmission. In public-key encryption, the sender of a message encrypts the message with the public key of the recipient. Upon delivery, the recipient decrypts the message using his or her private key. The directory supports two levels of encryption:
The DES40 algorithm, available internationally, is a DES variant in which the secret key is preprocessed to provide forty effective key bits. It is designed for use by customers outside the USA and Canada who want to use a DES-based encryption algorithm.
Oracle is licensed to export the RC4 data encryption algorithm with a 40-bit key size to virtually all destinations where Oracle products are available. This makes it possible for international corporations to safeguard their entire operations with fast cryptography.
A password policy is a set of rules that govern how passwords are used. When a user attempts to bind to the directory, the directory server uses the password policy to ensure that the password provided meets the various requirements set in that policy.
When you establish a password policy, you set the following types of rules, to mention just a few:
The maximum length of time a given password is valid
The minimum number of characters a password must contain
The ability of users to change their passwords
The standard LDAP APIs enable you to perform the fundamental LDAP operations described in "LDAP Models". These APIs are available in C, PL/SQL, and Java. The first two are part of the directory SDK. The last is part of the JNDI package provided by Sun Microsystems. All three use TCP/IP connections. They are based on LDAP Version 3, and they support SSL connections to Oracle Internet Directory.
This section contains these topics:
Typically, an application uses the functions in the API in four steps:
Initialize the library and obtain an LDAP session handle.
Authenticate to the LDAP server if necessary.
Perform some LDAP operations and obtain results and errors, if any.
Close the session.
Figure 2-3 illustrates these steps.
When you build applications with the C API, you must include the header file ldap.h
, located at $ORACLE_HOME/ldap/public
. In addition, you must dynamically link to the library located at $ORACLE_HOME/lib/libclntsh.so.10.1
.
The DBMS_LDAP
package enables PL/SQL applications to access data located in enterprise-wide LDAP servers. The names and syntax of the function calls are similar to those of the C API. These functions comply with current recommendations of the Internet Engineering Task Force (IETF) for the C API. Note though that the PL/SQL API contains only a subset of the functions available in the C API. Most notably, only synchronous calls to the LDAP server are available in the PL/SQL API.
To begin using the PL/SQL LDAP API, use this command sequence to load DBMS_LDAP into the database:
Log in to the database, using SQL*Plus. Run the tool in the Oracle home in which your database is present. Connect as SYSDBA
.
SQL> CONNECT / AS SYSDBA
Load the API into the database, using this command:
SQL> @?/rdbms/admin/catladap.sql
Java developers can use the Java Naming and Directory Interface (JNDI) from Sun Microsystems to gain access to information in Oracle Internet Directory. The JNDI is found at this link:
http://java.sun.com/products/jndi
Although no Java APIs are provided in this chapter, the section immediately following, "Initializing the Session by Using JNDI", shows you how to use wrapper methods for the Sun JNDI to establish a basic connection.
All LDAP operations based on the C API require clients to establish an LDAP session with the LDAP server. For LDAP operations based on the PL/SQL API, a database session must first initialize and open an LDAP session. Most Java operations require a Java Naming and Directory Interface (JNDI) connection. The oracle.ldap.util.jndi
package, provided here, simplifies the work involved in achieving this connection.
The section contains the following topics:
The C function ldap_init()
initializes a session with an LDAP server. The server is not actually contacted until an operation is performed that requires it, allowing various options to be set after initialization.
ldap_init
has the following syntax:
LDAP *ldap_init (
const char *hostname, int portno
);
Table 2-3 lists and defines the function parameters.
Table 2-3 Parameters for ldap_init()
Parameter | Description |
---|---|
hostname |
Contains a space-separated list of directory host names or IP addresses represented by dotted strings. You can pair each host name with a port number as long as you use a colon to separate the two. The hosts are tried in the order listed until a successful connection is made. Note: A suitable representation for including a literal IPv6[10] address in the host name parameter is desired, but has not yet been determined or implemented in practice. |
portno |
Contains the TCP port number of the directory you would like to connect to. The default LDAP port of |
ldap_init()
and ldap_open()
both return a session handle, or pointer, to an opaque structure that must be passed to subsequent calls to the session. These routines return NULL
if the session cannot be initialized. You can check the error reporting mechanism for your operating system to determine why the call failed.
In the PL/SQL API, the function DBMS_LDAP.init()
initiates an LDAP session. This function has the following syntax:
FUNCTION init (hostname IN VARCHAR2, portnum IN PLS_INTEGER )
RETURN SESSION;
The function init
requires a valid host name and port number to establish an LDAP session. It allocates a data structure for this purpose and returns a handle of the type DBMS_LDAP.SESSION
to the caller. The handle returned from the call should be used in all subsequent LDAP operations defined by DBMS_LDAP for the session. The API uses these session handles to maintain state about open connections, outstanding requests, and other information.
A single database session can obtain as many LDAP sessions as required, although the number of simultaneous active connections is limited to 64. One database session typically has multiple LDAP sessions when data must be obtained from multiple servers simultaneously or when open sessions that use multiple LDAP identities are required.
Note: The handles returned from calls toDBMS_LDAP.init() are dynamic constructs. They do not persist across multiple database sessions. Attempting to store their values in a persistent form, and to reuse stored values at a later stage, can yield unpredictable results.
|
The oracle.ldap.util.jndi
package supports basic connections by providing wrapper methods for the JNDI implementation from Sun Microsystems. If you want to use the JNDI to establish a connection, see the following link:
http://java.sun.com/products/jndi
Here is an implementation of oracle.ldap.util.jndi
that establishes a non-SSL connection:
import oracle.ldap.util.jndi import javax.naming.*; public static void main(String args[]) { try{ InitialDirContext ctx = ConnectionUtil.getDefaultDirCtx(args[0], // host args[1], // port args[2], // DN args[3]; // password) // Do work } catch(NamingException ne) { // javax.naming.NamingException is thrown when an error occurs } }
Note:
|
Individuals or applications seeking to perform operations against an LDAP server must first be authenticated. If the dn
and passwd
parameters of these entities are null, the LDAP server assigns a special identity, called anonymous, to these users. Typically, the anonymous user is the least privileged user of the directory.
Once a bind operation is complete, the directory server remembers the new identity until another bind occurs or the LDAP session terminates (unbind_s
). The LDAP server uses the identity to enforce the security model specified by the enterprise in which it is deployed. The identity helps the LDAP server determine whether the user or application identified has sufficient privileges to perform search, update, or compare operations in the directory.
Note that the password for the bind operation is sent over the network in clear text. If your network is not secure, consider using SSL for authentication and other LDAP operations that involve data transfer.
This section contains these topics:
The C function ldap_simple_bind_s()
enables users and applications to authenticate to the directory server using a DN and password.
The function ldap_simple_bind_s()
has this syntax:
int ldap_simple_bind_s ( LDAP* ld, char* dn, char* passwd );
Table 2-4 lists and describes the parameters for this function.
Table 2-4 Arguments for ldap_simple_bind_s()
Argument | Description |
---|---|
ld |
A valid LDAP session handle |
dn |
The identity that the application uses for authentication |
passwd |
The password for the authentication identity |
If the dn
and passwd
parameters for are NULL
, the LDAP server assigns a special identity, called anonymous, to the user or application.
The PL/SQL function simple_bind_s
enables users and applications to use a DN and password to authenticate to the directory. simple_bind_s
has this syntax:
FUNCTION simple_bind_s ( ld IN SESSION, dn IN VARCHAR2, passwd IN VARCHAR2)
RETURN PLS_INTEGER;
Note that this function requires as its first parameter the LDAP session handle obtained from init
.
The following PL/SQL code snippet shows how the PL/SQL initialization and authentication functions just described might be implemented.
DECLARE
retval PLS_INTEGER; my_session DBMS_LDAP.session;
BEGIN
retval := -1; -- Initialize the LDAP session my_session := DBMS_LDAP.init('yow.acme.com',389); --Authenticate to the directory retval :=DBMS_LDAP.simple_bind_s(my_session,'cn=orcladmin', 'welcome');
In the previous example, an LDAP session is initialized on the LDAP server yow.acme.com
. This server listens for requests at TCP/IP port number 389
. The identity cn=orcladmin
, whose password is welcome
, is then authenticated. Once authentication is complete, regular LDAP operations can begin.
Searches are the most common LDAP operations. Applications can use complex search criteria to select and retrieve entries from the directory.
This section contains these topics:
Searching the Directory by Using DBMS_LDAP
Note: This release of theDBMS_LDAP API provides only synchronous search capability. This means that the caller of the search functions is blocked until the LDAP server returns the entire result set.
|
The programming required to initiate a typical search operation and retrieve results can be broken down into the following steps:
Decide what attributes must be returned; then place them into an array.
Initiate the search, using the scope options and filters of your choice.
Obtain an entry from result set.
Obtain an attribute from the entry obtained in step 3.
Obtain the values of the attributes obtained in step 4; then copy these values into local variables.
Repeat step 4 until all attributes of the entry are examined.
Repeat Step 3 until there are no more entries
Figure 2-4 uses a flow chart to represent these steps.
The scope of a search determines how many entries the directory server examines relative to the search base. You can choose one of the three options described in Table 2-5 and illustrated in Figure 2-5.
Table 2-5 Options for search_s() or search_st() Functions
Option | Description |
---|---|
SCOPE_BASE |
The directory server looks only for the entry corresponding to the search base. |
SCOPE_ONELEVEL |
The directory server confines its search to the entries that are the immediate children of the search base entry. |
SCOPE_SUBTREE |
The directory server looks at the search base entry and the entire subtree beneath it. |
In Figure 2-5, the search base is the shaded circle. The shaded rectangle identifies the entries that are searched.
A search filter is an expression that enables you to confine your search to certain types of entries. The search filter required by the search_s()
and search_st()
functions follows the string format defined in RFC 1960 of the Internet Engineering Task Force (IETF). As Table 2-6 shows, there are six kinds of search filters. These are entered in the format attribute operator value
.
Table 2-6 Search Filters
Filter Type | Format | Example | Matches |
---|---|---|---|
Equality |
(att=value)
|
(sn=Keaton) |
Surnames exactly equal to |
Approximate |
(att~=value)
|
(sn~=Ketan) |
Surnames approximately equal to |
Substring |
(attr=[leading]*[any]*[trailing] |
(sn=*keaton*)
(sn=keaton*)
(sn=*keaton)
(sn=ke*at*on) |
Surnames containing the string Surnames starting with Surnames ending with Surnames starting with |
Greater than or equal |
attr>=value |
(sn>=Keaton) |
Surnames lexicographically greater than or equal to |
Less than or equal |
(attr<=value) |
(sn<=Keaton) |
Surnames lexicographically less than or equal to |
Presence |
(attr=*)
|
(sn=*) |
All entries having the |
You can use boolean operators and prefix notation to combine these filters to form more complex filters. Table 2-7 provides examples. In these examples, the &
character represents AND, the |
character represents OR, and the !
character represents NOT.
Table 2-7 Boolean Operators
Filter Type | Format | Example | Matches |
---|---|---|---|
AND |
(&(filter1)(filter2)). . .) |
(&(sn=keaton)(objectclass=inetOrgPerson)) |
Entries with surname of |
OR |
(|(filter1)(filter2)). . .) |
(|(sn~=ketan)(cn=*keaton)) |
Entries with surname approximately equal to |
NOT |
(!(filter))
|
(!(mail=*)) |
Entries without a mail attribute. |
The complex filters in Table 2-7 can themselves be combined to create even more complex, nested filters.
The C function ldap_search_s()
performs a synchronous search of the directory.
The syntax for ldap_search_s()
looks like this:
int ldap_search_s ( LDAP* ld, char* base, int scope, char* filter int attrsonly, LDAPMessage** res );
ldap_search_s
works with several supporting functions to refine the search. The steps that follow show how all of these C functions fit into the program flow of a search operation. Chapter 11, "C API Reference", examines all of these functions in depth.
Decide what attributes must be returned; then place them into an array of strings. The array must be null terminated.
Initiate the search, using ldap_search_s()
. Refine your search with scope options and filters.
Obtain an entry from the result set, using either the ldap_first_entry()
function or the ldap_next_entry()
function.
Obtain an attribute from the entry obtained in step 3. Use either the ldap_first_attribute()
function or the ldap_next_attribute()
function for this purpose.
Obtain all the values for the attribute obtained in step 4; then copy these values into local variables. Use the ldap_get_values()
function or the ldap_get_values_len()
function for this purpose.
Repeat step 4 until all attributes of the entry are examined.
Repeat step 3 until there are no more entries.
Table 2-8 Arguments for ldap_search_s()
Argument | Description |
---|---|
ld |
A valid LDAP session handle |
base |
The DN of the search base. |
scope |
The breadth and depth of the DIT to be searched. |
filter |
The filter used to select entries of interest. |
attrs |
The attributes of interest in the entries returned. |
attrso |
If set to |
res |
This argument returns the search results. |
You use the function DBMS_LDAP.search_s()
to performs directory searches if you use the PL/SQL API.
Here is the syntax for DBMS_LDAP.search_s()
:
FUNCTION search_s
( ld IN SESSION, base IN VARCHAR2, scope IN PLS_INTEGER, filter IN VARCHAR2, attrs IN STRING_COLLECTION, attronly IN PLS_INTEGER, res OUT MESSAGE )
RETURN PLS_INTEGER;
The function takes the arguments listed and described in Table 2-9.
Table 2-9 Arguments for DBMS_LDAP.search_s() and DBMS_LDAP.search_st()
Argument | Description |
---|---|
ld |
A valid session handle |
base |
The DN of the base entry in the LDAP server where search should start |
scope |
The breadth and depth of the DIT that needs to be searched |
filter |
The filter used to select entries of interest |
attrs |
The attributes of interest in the entries returned |
attronly |
If set to |
res |
An |
search_s
works with several supporting functions to refine the search. The steps that follow show how all of these PL/SQL functions fit into the program flow of a search operation.
Decide what attributes need to be returned; then place them into the DBMS_LDAP.STRING_COLLECTION
data-type.
Perform the search, using either DBMS_LDAP.search_s()
or DBMS_LDAP.search_st()
. Refine your search with scope options and filters.
Obtain an entry from the result set, using eitherDBMS_LDAP.first_entry()
or DBMS_LDAP.next_entry()
.
Obtain an attribute from the entry obtained in step 3. Use either DBMS_LDAP.first_attribute()
or DBMS_LDAP.next_attribute()
for this purpose.
Obtain all the values for the attribute obtained in step 4; then copy these values into local variables. Use either DBMS_LDAP.get_values()
or DBMS_LDAP.get_values_len()
for this purpose.
Repeat step 4 until all attributes of the entry are examined.
Repeat step 3 until there are no more entries.
This section contains these topics:
Once an LDAP session handle is obtained and all directory-related work is complete, the LDAP session must be destroyed. In the C API, the ldap_unbind_s()
function is used for this purpose.
ldap_unbind_s()
has this syntax:
int ldap_unbind_s ( LDAP* ld );
A successful call to ldap_unbind_s()
closes the TCP/IP connection to the directory. It de-allocates system resources consumed by the LDAP session. Finally it returns the integer LDAP_SUCCESS
to its callers. Once ldap_unbind_s()
is invoked, no other LDAP operations are possible. A new session must be started with ldap_init()
.
The DBMS_LDAP.unbind_s()
function destroys an LDAP session if the PL/SQL API is used. unbind_s
has the following syntax:
FUNCTION unbind_s (ld IN SESSION ) RETURN PLS_INTEGER;
unbind_s
closes the TCP/IP connection to the directory. It de-allocates system resources consumed by the LDAP session. Finally it returns the integer DBMS_LDAP.SUCCESS
to its callers. Once the unbind_s
is invoked, no other LDAP operations are possible. A new session must be initiated with the init
function.