Skip Headers
Oracle® Fusion Middleware Developer's Guide for Oracle Access Management
11g Release 2 (11.1.2)

Part Number E27134-03
Go to Documentation Home
Home
Go to Table of Contents
Contents
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
PDF · Mobi · ePub

2 Developing Access Clients

Oracle Access Management Access Manager (Access Manager) provides a pure Java software developer kit (SDK) and application programming interfaces (APIs) for creating custom Access Clients. This chapter discusses how to develop a custom Access Client and provides the following sections:

2.1 About Developing Access Clients

A Webgate is a Web server plug-in that intercepts HTTP requests for resources and forwards them to the OAM Server for authentication and authorization. A Webgate is a Web server agent that acts as the actual enforcement point for access requests. Several Webgates are provided out-of-the-box and are ready for installation on an Oracle HTTP Server, where it intercepts access requests.

An Access Client is a custom Webgate that has been developed using the 11g Access SDK and APIs. When a standard Webgate is not suitable, a custom Access Client can be written and deployed for processing requests from users or application for either Web or non-Web resources (non-HTTP).

This section provides the following topics:

2.1.1 About the Access SDK and APIs

The 11g Access SDK and APIs are intended for Java application developers for the development of tightly coupled, performant integrations. In addition to this guide, for more information see Oracle Fusion Middleware Access SDK Java API Reference for Oracle Access Management Access Manager.

The Access SDK is a platform independent package that Oracle has certified on a variety of enterprise platforms (using both 32-bit and 64-bit modes) and hardware combinations. It is provided on JDK versions that are supported across Oracle Fusion Middleware applications.

The oracle.security.am.asdk package provides the 11g Java APIs. The 11g version is very similar to the 10g JNI APIs, with enhancements for use with the 11g OAM Server. The 11g Access SDK provides backwards compatibility by supporting 10g based com.oblix.access interfaces. From a functional perspective, the 11g Access SDK maintains parity with the 10g (10.1.4.3) Access SDK to ensure that you can re-write existing custom code using the 11g API layer.

Note:

The 10g (10.1.4.3) com.oblix.access package and classes are deprecated. A deprecated API is not recommended for use, generally due to improvements, and a replacement API is usually given. Deprecated APIs may be removed in future implementations.

Oracle strongly recommends that developers use the 11g Access SDK for all new development.

Once the Access SDK is installed, do not change the relative locations of the subdirectories and files. Doing so may prevent an accurate build and proper operation of the API. The following Access SDK packages are included:

  • oracle.security.am.asdk: An authentication and authorization API that provides enhancements to take advantage of 11g OAM Server functionality. The 11g Access SDK API can be used with either Oracle Access Manager 10gR3 (10.1.4.3) or Oracle Access Manager 11gR1 (11.1.1.5+) version of the server.

  • com.oblix.access: This is the 10g version of the authentication and authorization API with some enhancements for the 11g release. It is available for backward compatibility with programs written with the 10g JNI ASDK.

The 11g Access SDK includes authentication and authorization functionality. However, it does not include Administrative APIs (for instance, there is no 11g Policy Manager API).

The most common use of the Access SDK is to enable the development of a custom integration between Access Manager and other applications (Oracle or third party). Usage examples include:

  • Developing a custom Access Client for a Web server or an application server for which Oracle does not provide an out-of-the-box integration.

  • Accessing session information that may be stored as part of the Access Manager authentication process.

  • Verifying the validity of the Access Manager session cookie rather than trusting an HTTP header for the user principal.

Table 2-1 describes the primary features of the 11g Access SDK.

Table 2-1 11g Access SDK Features

Feature Description

Installation

Client Package: Is comprised of a single zip file that contains oamasdk-api.jar, as well as other JPS jar files needed for 11g agent operations. Supporting files (for signing and TLS negotiations) are not included and should be generated separately.

Server Related Code: Is included as part of the core Access Manager server installation.

Note: Access Clients and plug-ins developed with Oracle Access Manager 10g (10.1.4.3) can be used with 11g release. Oracle Access Manager 10g (10.1.4.3) bundle patches are used to distribute Java SDK code enhancements for use with 11g environments.

Built In Versioning

Enables you to:

  • Determine the Access SDK version that is installed.

  • Validate compatible versions it can operate with (Oracle Access Manager 10g (10.1.4.3) and 11g).

    If there is a mismatch, Access SDK functions halt and an informative message is logged and presented.

Logging

The Access SDK logging mechanism enables you to specify the level (informational, warning, and error level) of detail you want to see in a local file. Messages provide enough detail for you to resolve an issue. For example, if an incompatible Access SDK package is used, the log message includes details about a version mismatch and what version criteria should be followed.

If the SDK generates large amounts of logs within a given period of time, you can configure a rollover of the logs based on a file limit or a time period. For example, if a file limit has been reached (or a certain amount of time has passed), the log file is copied to an archive directory and a new log file is started.


2.1.2 About Installing Access SDK

To install the Java Access SDK Client for Access Manager 11g, perform the following steps:

  1. Download the oam-java-asdk.jar file from Oracle Technology Network.

  2. Extract the contents of the file oam-java-asdk.zip to a local directory.

  3. Add oamasdk-api.jar to your CLASSPATH. Choose from the following depending upon your needs:

    • If you are using a non-JRF environment, add the following jar files to your CLASSPATH:

      identitystore.jar
      jps-api.jar
      jps-common.jar
      jps-internal.jar
      jps-unsupported-api.jar
      oraclepki.jar
      osdt_cert.jar
      osdt_core.jar
      osdt_xmlsec.jar
      
    • If you are configuring an Access Client in 10g mode, add the following jar files to your CLASSPATH:

      jps-api.jar
      
    • If you are configuring an Access Client in 11g mode, add the following jar files to your CLASSPATH:

      jps-api.jar
      jps-common.jar
      jps-internal.jar
      jps-unsupported-api.jar
      oraclepki.jar
      osdt_cert.jar
      osdt_core.jar
      osdt_xmlsec.jar
      
  4. If you are using a JRF environment, add the follow to system-jazn-data.xml in order to run in OAM_11G mode:

    <grant>
      <grantee>
        <codesource>
          <url>... ...</url>
        </codesource>
      </grantee>
      <permissions>
        <permission>
          <class>oracle.security.jps.service.credstore.CredentialAccessPermission</class>
          <name>context=SYSTEM,mapName=OAMAgent,keyName=*</name>
          <actions>read</actions>
        </permission>
      <permissions>
    <grant>
    

2.1.3 About Custom Access Clients

The Access SDK enables development of custom integrations with Access Manager for controlling access to protected resources such as authentication, authorization, and auditing. This access control is generally accomplished by developing and deploying custom Access Clients, which are applications or plug-ins that invoke the Access Client API to interface with the Access SDK runtime.

Access Client-side caching is used internally within the Access SDK runtime to further minimize the processing overhead. The Access SDK runtime, together with the OAM Server, transparently performs dynamic configuration management, whereby any Access Client configuration changes made using the administration console are automatically reflected in the affected Access SDK runtimes.

You can develop different types of custom Access Clients, depending on their desired function, by utilizing all, or a subset of, the Access Client API. The API is generally agnostic about the type of protected resources and network protocols used to communicate with the users. For example, the specifics of HTTP protocol and any use of HTTP cookies are outside of the scope of Access SDK. You can develop Access Clients to protect non-HTTP resources as easily as agents protecting HTTP resources.

The typical functions that a custom Access Client can perform, individually or in combination with other Access Clients, are as follows:

  • Authenticate users by validating their credentials against Access Manager and its configured user repositories.

  • Authenticate users and check for authorization to access a resource.

  • Authenticate users and create unique Access Manager sessions represented by session tokens.

  • Validate session tokens presented by users, and authorize their access to protected resources.

  • Terminate Access Manager sessions given a session token or a named session identifier.

  • Enumerate Access Manager sessions of a given user by specifying named user identifier.

  • Save or retrieve custom Access Manager session attributes.

Some Access Client operations are restricted for use by the designated Access Client instances. For example, see OperationNotPermitted in Oracle Fusion Middleware Access SDK Java API Reference for Oracle Access Management Access Manager.

Access Clients process user requests for access to resources within the LDAP domain protected by the OAM Server. Typically, you embed custom Access Client code in a servlet (plug-in) or a standalone application that receives resource requests. This code uses Access Manager API libraries to perform authentication and authorization services on the OAM Server.

If a resource is not protected, the Access Client grants the user free access to the requested resource. If the resource is protected and the user is authorized to provide certain credentials to gain access, the Access Client attempts to retrieve those user credentials so that the OAM Server can validate them. If authentication of the user and authorization for the resource succeeds, the Access Client makes the resource available to the user.

Access Clients can differ according to a variety of factors, as described in Table 2-2.

Table 2-2 Access Client Variations

Variation Description

Type of application

Standalone application versus server plug-ins.

Development Language

Each development language provides a choice of interfaces to the underlying functionality of the API.

For 11g, Java is the only development language for custom Access Clients.

Resource Type

Protect both HTTP and non-HTTP resources.

Credential Retrieval

Enable HTTP FORM-based input, the use of session tokens, and command-line input, among other methods.


After it has been written and deployed, a custom Access Client is managed by an Oracle Access Management administrator the same as a standard Webgate. For information about managing a custom Access Client using the administration console, see Oracle Fusion Middleware Administrator's Guide for Oracle Access Management.

2.1.3.1 When to Create a Custom Access Client

Typically, you deploy a custom Access Client instead of a standard Webgate when you need to control access to a resource for which Oracle Access Manager does not already supply an out-of-the-box solution. This might include:

  • Protection for non-HTTP resources.

  • Protection for a custom web server developed to implement a special feature (for example, a reverse proxy).

  • Implementation of single sign-on (SSO) to protect a combination of HTTP and non-HTTP resources.

    For example, you can create an Access Client that facilitates SSO within an enterprise environment that includes an Oracle WebLogic Server cluster as well as non-Oracle WebLogic Server resources.

2.1.3.2 Access Client Architecture

Each Access Client is built from the following three types of resources:

  1. Custom Access Client code.

    Built into a servlet or standalone application. For the 11g release, you write Access Client code using the Java language platform.

  2. Configuration information.

    • OBAccessClient.xml file: Primary configuration file, which contains configuration information that constitutes an Access Client profile.

    • cwallet.sso and jps-config.xml files: For an 11g agent only.

    • If the transportation security mode is Simple or Cert, then the following files are required.

      • oamclient-truststore.jks – JKS format trust store file which should contain CA certificate of the certificate issuing authority.

      • oamclient-keystore.jks – JKS format key store file which should contain certificate and private key issued for the Access Client.

      • password.xml – An XML file that holds the value of global pass phrase. Same password is also used to unprotect private key file.

  3. Access Manager API libraries.

    Facilitates interaction between the Access Client and OAM Server.

Figure 2-1 shows the relationship between the Access Client components installed on a host server.

Figure 2-1 Architectural Detail of an Access Client

Architectural detail of an AccessGate.
Description of "Figure 2-1 Architectural Detail of an Access Client "

2.1.4 About Access Client Request Processing

Regardless of the variability introduced by the types of resources discussed in Section 2.1.3.2, "Access Client Architecture", most Access Clients follow the same basic steps to process user requests.

When a user or application submits a resource request to a servlet or application running on the server where the Access Client is installed, the Access Client code embedded in that servlet or application initiates the basic process shown in Figure 2-2.

Figure 2-2 illustrates the process of handling a resource request.

Figure 2-2 Process Overview: Handling a Resource Request

Handling a resource request.
Description of "Figure 2-2 Process Overview: Handling a Resource Request "

Process Overview: Handling a Resource Request

  1. The application or servlet containing the Access Client code receives a user request for a resource.

  2. The Access Client constructs a ResourceRequest structure, which the Access Client code uses when it asks the OAM Server whether the requested resource is protected.

  3. The OAM Server responds.

  4. Depending upon the situation, one of the following occurs:

    • If the resource is not protected, the Access Client grants or denies access to the resource depending on the value of the DenyOnNotProtected flag. Default value is true.

      For Access Manager 11g agent, DenyOnNotProtected flag in always true and cannot be changed.

    • If the resource is protected, the Access Client constructs an AuthenticationScheme structure, which it uses to ask the OAM Server what credentials the user needs to supply. This step is only necessary if the Access Client supports the use of different authentication schemes for different resources.

  5. The OAM Server responds.

  6. The application uses a form or some other means to ask for user credentials. In some cases, the user credentials may already have been submitted as part of:

    • A valid session token.

    • Input from a web browser.

    • Arguments to the command-line script or keyboard input that launched the Access Client application.

  7. The user responds to the application.

  8. The Access Client constructs an UserSession structure, which presents the user credentials to the OAM Server, which maps them to a user profile in the Oracle Access Manager user directory.

  9. If the credentials prove valid, the Access Client creates a session token for the user, then it sends a request for authorization to the OAM Server. This request contains the user identity, the name of the target resource, and the requested operation.

    For an Access Client developed using the Access SDK, a SSO token is issued as a string type with no name. Use getSessionToken() on an existing UserSession object to return that session's token. If you have an existing token, it can be used to construct a user session object. The token is encrypted and opaque to a user, but internally, can be either in 10g or 11g format.

  10. The Access Client grants the user access to the resource, providing that the user is authorized for the requested operation on the particular resource.

The flow illustrated in Figure 2-2 represents only the main path of the authorization process. Typically, additional code sections within the servlet or application handle branch situations where:

  • The requested resource is not protected.

  • The authentication challenge method associated with the protected resource is not supported by the application.

  • The user fails to supply valid credentials under the specified conditions.

  • Some other error condition arises.

  • The developer has built additional custom code into the Access Client to handle special situations or functionality.

When writing a custom Access Client, it is possible to authenticate users over the backchannel.

2.2 Developing Access Clients

The following topics are discussed in this section:

2.2.1 Structure of an Access Client

The structure of a typical Access Client application roughly mirrors the sequence of events required to set up an Access Client session.

Access Client Application Structure Overview

  1. Include or import requisite libraries.

  2. Get resource.

  3. Get authentication scheme.

  4. Gather user credentials required by authentication scheme.

  5. Create user session.

  6. Check user authorization for resource.

  7. Clean up (Java uses automatic garbage collection).

  8. Shut down.

2.2.2 Typical Access Client Execution Flow

All HTTP FORM-based Access Client applications and plug-ins follow the same basic pattern, as illustrated Figure 2-3.

Figure 2-3 shows a process flow for form-based applications:

Figure 2-3 Process Flow for Form-based Applications

A process flow for form-based applications.
Description of "Figure 2-3 Process Flow for Form-based Applications"

Process Overview: Access Client Execution for Form-based Applications

  1. Import libraries.

  2. Initialize the SDK.

  3. Create ResourceRequest object.

  4. Determine if the requested resource is protected.

    Resource Not Protected: If the resource is not protected, the Access Client grants or denies access to the resource depending on the value of the DenyOnNotProtected flag. Default value is true. For Access Manager 11g agent, DenyOnNotProtected flag in always true and cannot be changed.

  5. Requested Resource is Protected: Create an AuthenticationScheme object.

  6. Authentication Scheme HTTP FORM-based: Create a structure for user ID and password, create UserSession object, determine if the user is authenticated.

  7. Authentication Scheme Not HTTP FORM-based: Deny access and report reason, shut down the API and end program.

  8. User is Authenticated: Determine if the user is authorized (Step 10).

  9. User is Not Authenticated: Deny access and report reason, shut down the API and end program.

  10. User is Authorized: Grant access, shut down the API, and end program.

  11. User Not Authorized: Deny access and report reason, shut down the API and end program.

Note:

To run this test application, or any of the other examples, you must make sure that your Access System is installed and set up correctly. Specifically, check that it has been configured to protect resources that match exactly the URLs and authentication schemes expected by the sample programs. For details on creating application domains and protecting resources with application domains, see Oracle Fusion Middleware Administrator's Guide for Oracle Access Management.

2.2.3 Sample Code: Simple Access Client

This example is a simple Access Client program. It illustrates how to implement the bare minimum tasks required for a working Access Client:

  • Connect to the OAM Server

  • Log in using an authentication scheme employing the HTTP FORM challenge method

  • Check authorization for a certain resource using an HTTP GET request

  • Catch and report Access SDK API exceptions

Typically, this calling sequence is quite similar among Access Clients using the FORM challenge method. FORM-method Access Clients differ principally in the credentials they require for authentication and the type of resources they protect.

A complete listing for JAccessClient.java appears in Example 2-1. You can copy this code verbatim into the text file JAccessClient.java and execute it on the computer where your Access Manager SDK is installed.

See Section 2.2.4, "Annotated Sample Code: Simple Access Client" for an annotated version of this example to help you become familiar with 11g Java Access Manager API calls.

Example 2-1 JAccessClient.java

import java.util.Hashtable;
import oracle.security.am.asdk.*;

public class JAccessClient {
   public static final String ms_resource = "//Example.com:80/secrets/
         index.html";         
   public static final String ms_protocol = "http";
   public static final String ms_method = "GET";
   public static final String ms_login = "jsmith";
   public static final String ms_passwd = "j5m1th";
   public static final String m_configLocation = "/myfolder";
   public static void main(String argv[]) {
          AccessClient ac = null; 
      try {
          ac = AccessClient.createDefaultInstance(m_configLocation,
 AccessClient.CompatibilityMode.OAM_10G);
          
         ResourceRequest rrq = new ResourceRequest(ms_protocol, ms_resource,
               ms_method);
         if (rrq.isProtected()) {
            System.out.println("Resource is protected.");
            AuthenticationScheme authnScheme = new AuthenticationScheme(rrq);
            if (authnScheme.isForm()) {
               System.out.println("Form Authentication Scheme.");
               Hashtable creds = new Hashtable();
               creds.put("userid", ms_login);
               creds.put("password", ms_passwd);
               UserSession session = new UserSession(rrq, creds);
               if (session.getStatus() == UserSession.LOGGEDIN) {
                  if (session.isAuthorized(rrq)) {
                     System.out.println("User is logged in and authorized for the"
                           +"request at level " + session.getLevel());
                  } else {
                     System.out.println("User is logged in but NOT authorized");
                  }
                        //user can be loggedout by calling logoff method on the session object
               } else {
                  System.out.println("User is NOT logged in");
               }
            } else {
               System.out.println("non-Form Authentication Scheme.");
            }
         } else {
            System.out.println("Resource is NOT protected.");
         }
      }
      catch (AccessException ae) {
         System.out.println("Access Exception: " + ae.getMessage());
      }
      ac.shutdown();
   }
}

2.2.4 Annotated Sample Code: Simple Access Client

Import standard Java library class Hashtable to hold credentials.

import java.io.Hashtable;

Import the library containing the Java implementation of the Access SDK API classes.

import oracle.security.am.asdk.*;

This application is named JAccessClient.

public class JAccessClient {

Since this is the simplest of example applications, we are declaring global constants to represent the parameters associated with a user request for access to a resource.

Typically, a real-world application receives this set of parameters as an array of strings passed from a requesting application, HTTP FORM-based input, or command-line input. For example:

public static final String ms_resource = "//Example.com:80/secrets/index.html";
   public static final String ms_protocol = "http";
   public static final String ms_method = "GET";
   public static final String ms_login = "jsmith";
   public static final String ms_passwd = "j5m1th";

Launch the main method on the Java interpreter. An array of strings named argv is passed to the main method. In this particular case, the user jsmith, whose password is j5m1th, has requested the HTTP resource //Example.com:80/secrets/index.html. GET is the specific HTTP operation that will be performed against the requested resource. For details about supported HTTP operations and protecting resources with application domains, see Oracle Fusion Middleware Administrator's Guide for Oracle Access Management.

public static void main(String argv[]) {

Place all relevant program statements in the main method within a large try block so that any exceptions are caught by the catch block at the end of the program.

AccessClient ac = null;

 try {

To initialize the Access SDK, create an AccessClient instance by providing the directory location of configuration file ObAccessClient.xml. There are multiple ways to provide configuration location to initialize the Access SDK. For more information refer to Oracle Fusion Middleware Access SDK Java API Reference for Oracle Access Management Access Manager.

You only need to create an instance of AccessClient and it initializes Access SDK API. AccessClient.CompatibilityMode.OAM_10G indicates that Access SDK will be initialized to work in an older 10g agent mode that is compatible with both the 10g and 11g servers. By default, if this compatibility mode is not provided, then default OAM_11G is used, and the agent will be operating in 11g agent mode and can only talk with 11g OAM Servers.

ac = AccessClient.createDefaultInstance(m_configLocation ,
 AccessClient.CompatibilityMode.OAM_10G); 

Create a new resource request object named rrq using the ResourceRequest constructor with the following three parameters:

  • ms_protocol, which represents the type of resource being requested. When left unspecified, the default value is HTTP. EJB is another possible value, although this particular example does not cover such a case. You can also create custom types, as described in the Oracle Fusion Middleware Administrator's Guide for Oracle Access Management.

  • ms_resource, which is the name of the resource. Since the requested resource type for this particular example is HTTP, it is legal to prepend a host name and port number to the resource name, as in the following:

    //Example.com:80/secrets/index.html
    
  • ms_method, which is the type of operation to be performed against the resource. When the resource type is HTTP, the possible operations are GET and POST. For EJB-type resources, the operation must be EXECUTE. For custom resource types, you define the permitted operations when you set up the resource type. For more information on defining resource types and protecting resources with application domains, see the Oracle Fusion Middleware Administrator's Guide for Oracle Access Management.

ResourceRequest rrq = new ResourceRequest(ms_protocol,
   ms_resource, ms_method);

Determine whether the requested resource rrq is protected by an authentication scheme.

if (rrq.isProtected()) {

If the resource is protected, report that fact.

System.out.println("Resource is protected.");

Use the AuthenticationScheme constructor to create an authorization scheme object named authnScheme. Specify the resource request rrq so that AuthenticationScheme checks for the specific authorization scheme associated with that particular resource.

AuthenticationScheme authnScheme =new AuthenticationScheme(rrq);

Determine if the authorization scheme is FORM-based.

if (authnScheme.isForm()) {

If the authorization scheme does use HTTP FORM as the challenge method, report that fact, then create a hashtable named creds to hold the name:value pairs representing the user name (userid) and the user password (password). Read the values for ms_login and ms_passwd into the hashtable.

System.out.println("Form Authentication Scheme.");
Hashtable creds = new Hashtable();
creds.put("userid", ms_login);
creds.put("password", ms_passwd);

Using the UserSession constructor, create a user session object named session. Specify the resource request as rrq and the authentication scheme as creds so that UserSession can return the new structure with state information as to whether the authentication attempt has succeeded.

UserSession session = new UserSession(rrq, creds);

Invoke the getStatus method on the UserSession state information to determine if the user is now successfully logged in (authenticated).

if (session.getStatus() == UserSession.LOGGEDIN) {

If the user is authenticated, determine if the user is authorized to access the resource specified through the resource request structure rrq.

if (session.isAuthorized(rrq)) {
  System.out.println(
    "User is logged in " +
    "and authorized for the request " +

Determine the authorization level returned by the getLevel method for the user session named session.

"at level " + session.getLevel());

If the user is not authorized for the resource specified in rrq, then report that the user is authenticated but not authorized to access the requested resource.

} else {
  System.out.println("User is logged in but NOT authorized");

If the user is not authenticated, report that fact. (A real world application might give the user additional chances to authenticate).

} else {
  System.out.println("User is NOT logged in");

If the authentication scheme does not use an HTTP FORM-based challenge method, report that fact. At this point, a real-world application might branch to facilitate whatever other challenge method the authorization scheme specifies, such as basic (which requires only userid and password), certificate (SSL or TLS over HTTPS), or secure (HTTPS through a redirection URL). For more information about challenge Methods and configuring user authentication, see the Oracle Fusion Middleware Administrator's Guide for Oracle Access Management.

} else {
  System.out.println("non-Form Authentication Scheme.");
}

If the resource is not protected, report that fact. (By implication, the user gains access to the requested resource, because the Access Client makes no further attempt to protect the resource).

} else {
  System.out.println("Resource is NOT protected.");
}
}

If an error occurs anywhere within the preceding try block, get the associated text message from object ae and report it.

catch (AccessException ae) {
  System.out.println(
  "Access Exception: " + ae.getMessage());
}

If the application needs to logout user, then it can invoke logoff method on the object of UserSession class.

Now that the program is finished calling the OAM Server, shut down the API, thus releasing any memory the API might have maintained between calls.

ac.shutdown();
}
}

Exit the program. You don't have to deallocate the memory used by the structures created by this application because Java Garbage Collection automatically cleans up unused structures when it determines that they are no longer needed.

2.2.5 Sample Code: Java Login Servlet

This example follows the basic pattern of API calls that define an Access Client, as described in Section 2.2.3, "Sample Code: Simple Access Client". However, this example is implemented as a Java servlet running within a Web server, or even an application server. In this environment, the Access Client servlet has an opportunity to play an even more important role for the user of a Web application. By storing a session token in the user's HTTP session, the servlet can facilitate single sign-on for the user. In other words, the authenticated OAM Server session information that the first request establishes is not discarded after one authorization check. Instead, the stored session token is made available to server-side application components such as beans and other servlets, so that they do not need to interrupt the user again and again to request the same credentials. For a detailed discussion of session tokens, ObSSOCookies, and configuring single sign-on, see the Oracle Fusion Middleware Administrator's Guide for Oracle Access Management.

This example Java servlet does not provide SSO to resources protected by mod_osso, Access Manager Webgates, or OpenSSO Policy Agents.

This sample login servlet accepts userid/password parameters from a form on a custom login page, and attempts to log the user in to Access Manager. On successful login, the servlet stores a session token in the UserSession object. This enables subsequent requests in the same HTTP session to bypass the authentication step (providing the subsequent requests use the same authentication scheme as the original request), thereby achieving single sign-on.

A complete listing for the Java login servlet is shown in Example 2-2. This code can provide the basis for a plug-in to a web server or application server. Section 2.2.6, "Annotated Sample Code: Java Login Servlet" provides an annotated version of this code.

Example 2-2 Java Login Servlet Example

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
import oracle.security.am.asdk.*;
 
public class LoginServlet extends HttpServlet {
 
   public void init(ServletConfig config) throws ServletException {
      try {
          
           AccessClient ac = AccessClient.createDefaultInstance("/myfolder" ,
 AccessClient.CompatibilityMode.OAM_10G);                  
      } catch (AccessException ae) {
         ae.printStackTrace();
      }
   }
 
   public void service(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
      AuthenticationScheme authnScheme = null;
      UserSession user = null;
      ResourceRequest resource = null;
       response.setContentType("text/html");
      PrintWriter out = response.getWriter(); 
      out.println("<HTML>");
      out.println("<HEAD><TITLE>LoginServlet: Error Page</TITLE></HEAD>");
      out.println("<BODY>");
      HttpSession session = request.getSession( false);
      String requestedPage = request.getParameter("request");
      String reqMethod = request.getMethod();
      Hashtable cred = new Hashtable();
      try {
         if (requestedPage == null || requestedPage.length()==0) {
            out.println("<p>REQUESTED PAGE NOT SPECIFIED\n");
            out.println("</BODY></HTML>");
            return;
         }
         resource = new ResourceRequest("http", requestedPage, "GET");
         if (resource.isProtected()) {
            authnScheme = new AuthenticationScheme(resource);
            if (authnScheme.isBasic()) {
               if (session == null) {
                  String sUserName = request.getParameter("userid");
                  String sPassword = request.getParameter("password");
                  if (sUserName != null) {
                     cred.put("userid", sUserName);
                     cred.put("password", sPassword);
                     user = new UserSession(resource, cred);
                     if (user.getStatus() == UserSession.LOGGEDIN) {
                        if (user.isAuthorized(resource)) {
                           session = request.getSession( true);
                           session.putValue( "user", user);
                           response.sendRedirect( requestedPage );
                        } else {
                           out.println("<p>User " + sUserName + " not" +
                                " authorized for " + requestedPage + "\n");
                        }
                     } else {
                        out.println("<p>User" + sUserName + "NOT LOGGED IN\n");
                     }
                  } else {
                     out.println("<p>USERNAME PARAM REQUIRED\n");
                  }
               } else {
                  user = (UserSession)session.getValue("user");
                  if (user.getStatus() == UserSession.LOGGEDIN) {
                     out.println("<p>User " + user.getUserIdentity() + " already"+
                           "LOGGEDIN\n");
                  }
               }
            } else {
               out.println("<p>Resource Page" + requestedPage + " is not"+
                    " protected with BASIC\n");
            }
         } else {
            out.println("<p>Page " + requestedPage + " is not protected\n");
         } 
      } catch (AccessException ex) {
          out.println(ex);
      }
   out.println("</BODY></HTML>");
   }
} 

2.2.6 Annotated Sample Code: Java Login Servlet

Import standard Java packages to support input, output, and basic functionality.

import java.io.*;
import java.util.*;

Import two packages of Java extensions to provide servlet-related functionality.

import javax.servlet.*;
import javax.servlet.http.*;

Import the package oracle.security.am.asdk.jar, which is the Java implementation of the Access SDK API.

import oracle.security.am.asdk.*;

This servlet, which builds on the functionality of the generic HttpServlet supported by the Java Enterprise Edition, is named LoginServlet.

public class LoginServlet extends HttpServlet {

The init method is called once by the servlet engine to initialize the Access Client. In init method, Access SDK can be initialized by instantiating AccessClient by passing the location of the configuration file ObAccessClient.xml file. For more information for creating Access Client, refer to Oracle Fusion Middleware Access SDK Java API Reference for Oracle Access Management Access Manager. The OAM_10G compatibility flag initializes Access SDK in a mode such that it is compatible with both 10g and 11g servers The OAM_10G compatibility flag initializes Access SDK in an old 10g agent mode that is compatible with both 10g and 11g servers. By default, if this compatibility mode is not provided, then default OAM_11G flag is used and the agent will operate in 11g agent mode and can only talk with 11g OAM Server.

In the case of initialization failure, report that fact, along with the appropriate error message.

public void init() { 
      AccessClient ac =
 AccessClient.createDefaultInstance("/myfolder" ,
 AccessClient.CompatibilityMode.OAM_10G);
   } catch (AccessException ae) { 
         ae.printStackTrace(); 
   } 
} 

Invoke the javax.servlet.service method to process the user's resource request.

public void service(HttpServletRequest request, HttpServletResponse response)
  throws IOException, ServletException {

Initialize members as null. These will store the Access structures used to process the resource request, then set the response type used by this application to text/html.

AuthenticationScheme authnScheme = null;
UserSession user = null;
ResourceRequest resource = null;
response.setContentType("text/html");

Open an output stream titled LoginServlet: Error Page and direct it to the user's browser.

PrintWriter out = response.getWriter();
out.println("<HTML>");
out.println("<HEAD><TITLE>LoginServlet: Error Page</TITLE></HEAD>");
out.println("<BODY>");

Determine if a session already exists for this user. Invoke the getSession method with false as a parameter, so the value of the existing servlet session (and not the UserSession) will be returned if it is present; otherwise, NULL will be returned.

HttpSession session = request.getSession(false);

Retrieve the name of the target resource, assign it to the variable requestedPage, then retrieve the name of the HTTP method (such as GET, POST, or PUT) with which the request was made and assign it to the variable reqMethod.

String requestedPage = request.getParameter(Constants.REQUEST);
String reqMethod = request.getMethod();

Create a hashtable named cred to hold the user's credentials.

Hashtable cred = new Hashtable();

If the variable requestedPage is returned empty, report that the name of the target resource has not been properly specified, then terminate the servlet.

try { 
   if (requestedPage == null) { 
out.println("<p>REQUESTED PAGE NOT SPECIFIED\n"); 
out.println("</BODY></HTML>"); 
return; 
   } 

If the name of the requested page is returned, create a ResourceRequest structure and set the following:

  • The resource type is HTTP

  • The HTTP method is GET

  • resource is the value stored by the variable requestedPage

resource = new ResourceRequest("http", requestedPage, "GET");

If the target resource is protected, create an AuthenticationScheme structure for the resource request and name it authnScheme.

if (resource.isProtected()) {
   authnScheme = new AuthenticationScheme(resource);

If the authentication scheme associated with the target resource is HTTP basic and no user session currently exists, invoke javax.servlet.servletrequest.getParameter to return the user's credentials (user name and password) and assign them to the variables sUserName and sPassword, respectively.

For the authnScheme.isBasic call in the following statement to work properly, the user name and password must be included in the query string of the user's HTTP request, as in the following:

http://host.example.com/resource?username=bob&userpassword=bobspassword

where resource is the resource being requested, bob is the user making the request, and bobspassword is the user's password.

Additional Code for authnScheme.isForm

Note:

If you substitute authnScheme.isForm for authnScheme.isBasic, you need to write additional code to implement the following steps.

  1. Process the original request and determine that form-based login is required.

  2. Send a 302 redirect response for the login form and also save the original resource information in the HTTP session.

  3. Authenticate the user by processing the posted form data with the user's name and password.

  4. Retrieve the original resource from the HTTP resource and sends a 302 redirect response for the original resource.

  5. Process the original request once again, this time using the UserSession stored in the HTTP session.

if (authnScheme.isBasic()) { 
   if (session == null) { 
      String sUserName = request.getParameter(Constants.USERNAME); 
      String sPassword = request.getParameter(Constants.PASSWORD); 

If the user name exists, read it, along with the associated password, into the hashtable named cred.

if (sUserName != null) {
   cred.put("userid", sUserName);
   cred.put("password", sPassword);

Create a user session based on the information in the ResourceRequest structure named resource and the hashtable cred.

user = new UserSession(resource, cred);

If the status code for the user returns as LOGGEDIN, that user has authenticated successfully.

if (user.getStatus() == UserSession.LOGGEDIN) {

Determine if the user is authorized to access the target resource.

if (user.isAuthorized(resource)) {

Create a servlet user session (which is not to be confused with an UserSession) and add the name of the user to it.

session = request.getSession( true);
session.putValue( "user", user);

Redirect the user's browser to the target page.

response.sendRedirect(requestedPage);

If the user is not authorized to access the target resource, report that fact.

} else {
    out.println("<p>User " + sUserName + " not authorized
      for " + requestedPage + "\n");
 }

If the user is not properly authenticated, report that fact.

} else {
    out.println("<p>User" + sUserName + "NOT LOGGED IN\n");
}

If the user name has not been supplied, report that fact.

} else {
out.println("<p>USERNAME PARAM REQUIRED\n");
}

If a session already exists, retrieve USER and assign it to the session variable user.

} else {
    user = (UserSession)session.getValue("user");

If the user is logged in, which is to say, the user has authenticated successfully, report that fact along with the user's name.

if (user.getStatus() == UserSession.LOGGEDIN) { 
      out.println("<p>User " + user.getUserIdentity() + " already 
      LOGGEDIN\n"); 
 }
}

If the target resource is not protected by a basic authentication scheme, report that fact.

} else {
   out.println("<p>Resource Page" + requestedPage + " is not protected
         with BASIC\n");
}

If the target resource is not protected by any authentication scheme, report that fact.

} else {
   out.println("<p>Page " + requestedPage + " is not protected\n");
} 

If an error occurs, report the backtrace.

} catch (AccessException ex) {
   oe.println(ex);
}

Complete the output stream to the user's browser.

out.println("</BODY></HTML>");
  }
}

2.2.7 Sample Code: Additional Methods

Building on the basic pattern established in the sample application JAccessClient.java, discussed in Section 2.2.3, "Sample Code: Simple Access Client", the following sample program invokes several additional OAM Server methods. For instance, it inspects the session object to determine which actions, also named responses, are currently configured in the policy rules associated with the current authentication scheme.

For this demonstration to take place, you must configure some actions through the OAM Server prior to running the application. For details about authentication action and configuring user authentication, see Oracle Fusion Middleware Administrator's Guide for Oracle Access Management. The complete listing for this sample application appears in Example 2–3. An annotated version of the code is provided in Section 2.2.8, "Annotated Sample Code: Additional Methods".

Example 2-3 access_test_java.java

import java.util.*;
import oracle.security.am.asdk.*;
 
public class access_test_java {
 
  public static void main(String[] arg) {
    String userid, password, method, url, configDir, type,
 location;
    ResourceRequest res;
    Hashtable parameters = null;
    Hashtable cred = new Hashtable();
    AccessClient ac = null; 
    if (arg.length < 5) {
      System.out.println("Usage: EXPECTED: userid password Type
 HTTP-method"
          +" URL [Installdir [authz-parameters] [location]]]");
      return;
    } else {
      userid    = arg[0];
      password  = arg[1];
      type      = arg[2];
      method    = arg[3];
      url      = arg[4];
    }
    if (arg.length >= 6) {
      configDir = arg[5];
    } else {
      configDir = null;
    }
    if (arg.length >= 7 && arg[6] != null) {
      parameters = new Hashtable();
      StringTokenizer tok1 = new StringTokenizer(arg[6], "&");
      while (tok1.hasMoreTokens()) {
        String nameValue = tok1.nextToken();
        StringTokenizer tok2 = new StringTokenizer(nameValue,
 "=");
        String name = tok2.nextToken();
        String value = tok2.hasMoreTokens() ? tok2.nextToken() :
 "";
        parameters.put(name, value);
      }
    }
    location = arg.length >= 8 ? arg[7] : null;
    try {
      ac = AccessClient.createDefaultInstance(configDir ,
 AccessClient.CompatibilityMode.OAM_10G);
          
    } catch (AccessException ae) {
      System.out.println("OAM Server SDK Initialization
 failed");
      ae.printStackTrace();
      return;
    }
    cred.put("userid", userid);
    cred.put("password", password);
    try {
      res = new ResourceRequest(type, url, method);
      if (res.isProtected()) {
        System.out.println("Resource " + type + ":" + url + "
 protected"); 
      } else {
        System.out.println("Resource " + type + ":" + url + "
 unprotected");
      }
    } catch (Throwable t) {
      t.printStackTrace();
      System.out.println("Failed to created new resource
 request");
      return;
    }
    UserSession user = null;
    try {
      user = new UserSession(res, cred);
    } catch (Throwable t) {
      t.printStackTrace();
      System.out.println("Failed to create new user session");
      return;
    }
    try {
    if (user.getStatus() == UserSession.LOGGEDIN) {
      if (location != null) user.setLocation(location);
      System.out.println("user status is " + user.getStatus());
      
        if (parameters != null ? user.isAuthorized(res,
 parameters) :
              user.isAuthorized(res)) {
          System.out.println("Permission GRANTED");
          System.out.println("User Session Token =" +
              user.getSessionToken());
          if (location != null) {
            System.out.println("Location = " +
 user.getLocation());
          } 
        } else {
          System.out.println("Permission DENIED");
          if (user.getError() == UserSession.ERR_NEED_MORE_DATA)
 {
            int nParams =
 res.getNumberOfAuthorizationParameters();
            System.out.print("Required Authorization Parameters
 (" + 
                nParams + ") :");
            Enumeration e =
 res.getAuthorizationParameters().keys();
            while (e.hasMoreElements()) {
              String name = (String) e.nextElement();
              System.out.print(" " + name);
            }
            System.out.println();
          }
        }      
   } 
   else 
   {      
           System.out.println("user status is " + user.getStatus());  
   } 
    } catch (AccessException ae)
    {    
          System.out.println("Failed to get user authorization");      
    }
   String[] actionTypes = user.getActionTypes();   
   for(int i =0; i < actionTypes.length; i++) 
   {      
           Hashtable actions = user.getActions(actionTypes[i]);
           Enumeration e = actions.keys();
           int item = 0; 
           System.out.println("Printing Actions for type " +
 actionTypes[i]);
           while(e.hasMoreElements())
           {
                   String name = (String)e.nextElement();
                   System.out.println("Actions[" + item +"]: Name " + name + "
 value " +  actions.get(name));
                   item++;   
           }
        }
   AuthenticationScheme auths;
   try 
   {
           auths = new AuthenticationScheme(res);
       if (auths.isBasic())
       {
             System.out.println("Auth scheme is Basic");
       }
       else 
       {
             System.out.println("Auth scheme is NOT Basic");
       }
   }
   catch (AccessException ase)
   {   
           ase.printStackTrace();
           return;
   }
   try 
   {      
           ResourceRequest resNew = (ResourceRequest) res.clone();   
           System.out.println("Clone resource Name: " +
 resNew.getResource());
   } 
   catch (Exception e) 
   {    
           e.printStackTrace(); 
   }  
   res = null;  
   auths = null; 
   ac.shutdown();
   }
  }

2.2.8 Annotated Sample Code: Additional Methods

Import standard Java libraries to provide basic utilities, enumeration, and token processing capabilities.

import java.util.*;

Import the Access SDK API libraries.

import oracle.security.am.asdk.*;

This class is named access_test_java.

public class access_test_java {

Declare seven variable strings to store the values passed through the array named arg.

public static void main(String[] arg) {
   String userid, password, method, url, configDir, type, location;

Set the current ResourceRequest to res.

ResourceRequest res;

Initialize the hashtable parameters to null, just in case they were not already empty.

Hashtable parameters = null;

Create a new hashtable named cred.

Hashtable cred = new Hashtable();

Initialize AccessClient reference to null.

AccessClient ac = null;

If the array named arg contains less than five strings, report the expected syntax and content for command-line input, which is five mandatory arguments in the specified order, as well as the optional variables configDir, authz-parameters, and location.

if (arg.length < 5) {
  System.out.println("Usage: EXPECTED: userid password type
    HTTP-method URL [configDir [authz-parameters] [location]]]");

Since fewer than five arguments were received the first time around, break out of the main method, effectively terminating program execution.

return;
} else {

If the array named arg contains five or more strings, assign the first five arguments (arg[0] through arg[4]) to the variables userid, password, type, method, and url, respectively.

userid = arg[0];
  password = arg[1];
  type = arg[2];
  method = arg[3];
  url = arg[4];
}

If arg contains six or more arguments, assign the sixth string in the array to the variable configDir.

if (arg.length >= 6)
  configDir = arg[5];

If arg does not contain six or more arguments (in other words, we know it contains exactly five arguments, because we have already determined it does not contain fewer than five) then set configDir to NULL.

else
  configDir = null;

If arg contains at least seven strings, and arg[6] (which has been implicitly assigned to the variable authz-parameters) is not empty, create a new hashtable named parameters. The syntax for the string authz-parameters is: p1=v1&p2=v2&...

if (arg.length >= 7 && arg[6] != null) {
  parameters = new Hashtable();

Create a string tokenizer named tok1 and parse arg[6], using the ampersand character (&) as the delimiter. This breaks arg[6] into an array of tokens in the form pn=vn, where n is the sequential number of the token.

StringTokenizer tok1 = new StringTokenizer(arg[6], "&");

For all the items in tok1, return the next token as the variable nameValue. In this manner, nameValue is assigned the string pn=vn, where n is the sequential number of the token.

while (tok1.hasMoreTokens()) {
  String nameValue = tok1.nextToken();

Create a string tokenizer named tok2 and parse nameValue using the equal character (=) as the delimiter. In this manner, pn=vn breaks down into the tokens pn and vn.

StringTokenizer tok2 = new StringTokenizer(nameValue, "=");

Assign the first token to the variable name.

String name = tok2.nextToken();

Assign the second token to value. If additional tokens remain in tok2, return the next token and assign it to value; otherwise, assign an empty string to value.

String value = tok2.hasMoreTokens() ? tok2.nextToken() : "";

Insert name and value into the hashtable parameters.

parameters.put(name, value);
  }
}

If there are eight or more arguments in arg, assign arg[7] to the variable location; otherwise make location empty.

location = arg.length >= 8 ? arg[7] : null;

Create AccessClient instance using configDir, in case if its null provide configuration file location using other options. For more information for creating Access Client, see Oracle Fusion Middleware Access SDK Java API Reference for Oracle Access Management Access Manager.

try {
 ac = AccessClient.createDefaultInstance(configDir , 
   AccessClient.CompatibilityMode.OAM_10G); 
}

If the initialization attempt produces an error, report the appropriate error message (ae) to the standard error stream along with the backtrace.

catch (AccessException ae) {
  System.out.println("
OAM Server SDK Initialize failed");
  ae.printStackTrace();

Break out of the main method, effectively terminating the program.

return;
}

Read the variables, user ID, and password into the hashtable named cred.

cred.put("userid", userid);
cred.put("password", password);

Create a ResourceRequest object named res, which returns values for the variables type, url and method from the OAM Server.

try {
res = new ResourceRequest(type, url, method);

Determine whether the requested resource res is protected and display the appropriate message.

if (res.isProtected())
  System.out.println("Resource " + type ":" + url + " protected");
else
  System.out.println("Resource " + type + ":" + url + " unprotected");
}

If the attempt to create the ResourceRequest structure does not succeed, report the failure along with the error message t.

catch (Throwable t) {
  t.printStackTrace();
  System.out.println("Failed to create new resource request");

Break out of the main method, effectively terminating the program.

return;
}

Set the UserSession parameter user to empty.

UserSession user = null;

Create a UserSession structure named user so that it returns values for the ResourceRequest structure res and the AuthenticationScheme structure cred.

try
  user = new UserSession(res, cred);

If the attempt to create the UserSession structure does not succeed, then report the failure along with the error message t.

catch (Throwable t) {
  t.printStackTrace();
  System.out.println("Failed to create new user session");

Break out of the main method, effectively terminating the program.

return;
}

Determine if the user is currently logged in, which is to say, authentication for this user has succeeded.

try
{
if (user.getStatus() == UserSession.LOGGEDIN) {

If the user is logged in, determine whether the variable location is not empty. If location is not empty, set the location parameter for AccessClient to the value of the variable location, then report that the user is logged in along with the status code returned by the OAM Server.

if (location != null) user.setLocation(location);
System.out.println("user status is " + user.getStatus());

Check authorization. To accomplish this, determine whether parameters exists. If it does, determine whether the user is authorized with respect to the target resource when the parameters stored in parameters are attached. If parameters does not exist, simply determine whether the user is authorized for the target resource.

try {
  if (parameters != null ? user.isAuthorized(res, parameters) :
    user.isAuthorized(res)) {

If the user is authorized to access the resource when all the appropriate parameters have been specified, report that permission has been granted.

System.out.println("Permission GRANTED");

Display also a serialized representation of the user session token.

System.out.println("User Session Token =" + user.getSessionToken());

If the variable location is not empty, report the location.

if (location != null) {
  System.out.println("Location = " + user.getLocation());
}

If the user is not authorized to access the resource, report that permission has been denied.

} else {
System.out.println("Permission DENIED");

If UserSession returns ERR_NEED_MORE_DATA, set the variable nParams to the number of parameters required for authorization, then report that number to the user.

if (user.getError() == UserSession.ERR_NEED_MORE_DATA) {
  int nParams = res.getNumberOfAuthorizationParameters();
  System.out.print("Required Authorization Parameters (" +
    nParams + ") :");

Set e to the value of the keys parameter in the hashtable returned by the getAuthorizationParameters method for the ResourceRequest object named "res."

Enumeration e = res.getAuthorizationParameters().keys();

Report the names of all the elements contained in e.

while (e.hasMoreElements()) {
  String name = (String) e.nextElement();
  System.out.print(" " + name);
}
System.out.println();
}

Otherwise, simply proceed to the next statement.

else
  }
}

If the user is not logged in, report the current user status.

else
  System.out.println("user status is " + user.getStatus());

In the case of an error, report that the authorization attempt failed.

catch (AccessException ae)
  System.out.println("Failed to get user authorization");
}

Now report all the actions currently set for the current user session. Do this by creating an array named actionTypes from the strings returned by the getActionTypes method. Next, read each string in actionTypes into a hashtable named actions. Report the name and value of each of the keys contained in actions.

String[] actionTypes = user.getActionTypes();
for(int i =0; actionTypes[i] != null; i++){
  Hashtable actions = user.getActions(actionTypes[i]);
  Enumeration e = actions.keys();
  int item = 0;
  System.out.println("Printing Actions for type " + actionTypes[i]);
  while(e.hasMoreElements()) {
String name = (String)e.nextElement();
System.out.println("Actions[" + item +"]: Name " + name + " value " +
  actions.get(name));
item++;
  }
}

Attempt to create an AuthenticationScheme object named auths for the ResourceRequest object res.

AuthenticationScheme auths;
try
  auths = new AuthenticationScheme(res);

If the AuthenticationScheme creation attempt is unsuccessful, report the failure along with the error message ase.

catch (AccessException ase) {
  ase.printStackTrace();

Break out of the main method, effectively terminating the program.

return;
}

Determine if the authorization scheme is basic.

try
{
if (auths.isBasic())

If it is, report the fact.

System.out.println("Auth scheme is Basic");

If it is not basic, report the fact.

else
  System.out.println("Auth scheme is NOT Basic");

Use the copy constructor to create a new ResourceRequest object named resNEW from the original object res.

ResourceRequest resNew = (ResourceRequest) res.clone();

Report the name of the newly cloned object.

System.out.println("Clone resource Name: " + resNew.getResource());

If the ResourceRequest object cannot be cloned for any reason, report the failure along with the associated backtrace.

}
catch (Exception e) {
  e.printStackTrace();
}

Set the ResourceRequest object res and the AuthenticationScheme object auths to NULL, then disconnect the Access SDK API.

res = null;
    auths = null;
    ac.shutdown();
  }
}

2.2.9 Sample Code: Certificate-Based Authentication in Java

The following is a code snippet that demonstrates implementing an Access Client in Java that processes an X.509 certificate. This snippet is appropriate when an administrator configures certificate-based authentication in the Access System.

Note that the certificate must be Base 64-encoded. The OAM Server uses this certificate only to identify the user. It does not perform validation such as the validity period, if the root certification is trusted or not, and so on.

File oCertFile = new File("sample_cert.pem");
 FileInputStream inStream = new FileInputStream(oCertFile);
 CertificateFactory cf =
 CertificateFactory.getInstance("X.509");

// cert must point to a valid java.security.cert.X509Certificate instance.
X509Certificate cert = (X509Certificate)
cf.generateCertificate(inStream);
 
// Convert the certificate into a byte array
    byte[] encodecCert = cert.getEncoded();
 
// Encode the byte array using Base 64-encoding and convert it into a string
String base64EncodedCert = new String(Base64.encodeBase64 (encodedCert));
 
// Create hashtable to hold credentials
    Hashtable creds = new Hashtable();
 
// Store the Base 64-encoded under the key "certificate"
    cred.put("certificate", base64EncodedCert);
 
// Create ResourceResource request object including all information about the // // resource being accessed
    ResourceRequest resourceRequest = new ResourceRequest(resourceType, resourceUrl, operation);
 
// Create a UserSession with the requestRequest and the cred hashtable
    UserSession userSession = new UserSession(resourceRequest, creds);
 
// The above statement will throw an exception if the certificate cannot be mapped // to a valid user by the OAM Server.

The following import statements are associated with the snippet:

import java.security.cert.CertificateFactory;
     import java.security.cert.X509Certificate;
     import java.io.FileInputStream;
     import oracle.security.am.common.nap.util.Base64;

2.3 Messages, Exceptions, and Logging

This section describes the messages and exceptions used by the Access SDK to indicate status or errors.

The execution log generated by the Access SDK is also described. The execution log provides information about operations performed. For example, operation status, any errors or exceptions that occur, and any general information that is helpful for troubleshooting.

The following topics are discussed in this section:

2.3.1 Messages

The Access SDK provides support for localized messages that indicate status or error conditions. Error messages, which are provided to the application as exceptions, are also localized. These localized error messages are logged in the Access SDK log file.

2.3.2 Exceptions

The following types of exceptions are used to indicate error conditions to an application:

  • OperationNotPermittedException

    The Access SDK provides a set of session management APIs. Only privileged Access Clients can perform these session management operations. AllowManagementOperations flag must be set for the specified agent profile to initialize Access SDK.

    If the Access Client is not allowed to perform these operations, the 11g OAM Server returns an error. When the server returns an error, the Access SDK will throw this exception.

  • AccessException

    The Access SDK API throws an AccessException whenever an unexpected, unrecoverable error occurs during the performance of any operation.

2.3.3 Logging

The Access SDK uses Java logging APIs for producing logs. Specifically, the oracle.security.am.asdk package contains the AccessLogger class, which produces the Access SDK log.

To generate the Access SDK log, you must provide a logging configuration file when you start the application. Provide this log configuration file as a Java property while running the application, where the Java property -Djava.util.logging.config.file is the path to logging.properties.

For example:

java -Djava.util.logging.config.file=JRE_DIRECTORY/lib/logging.properties

The logging.properties file defines the number of Loggers, Handlers, Formatters, and Filters that are constructed and ready to go shortly after the VM has loaded. Depending on the situation, you can also configure the necessary logging level.

You must provide the log file path against the java.util.logging.FileHandler.pattern property in the logging.properties file. If you provide only the file name, the file will be created under the current directory.

The following is an example logging.properties file:

# "handlers" specifies a comma separated list of log Handler 
# classes.  These handlers will be installed during VM startup.
# Note that these classes must be on the system classpath.
# By default we only configure a ConsoleHandler, which will only
# show messages at the INFO and above levels.
# Add handlers to the root logger.
# These are inherited by all other loggers.
handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler
 
# Set the logging level of the root logger.
# Levels from lowest to highest are
# FINEST, FINER, FINE, CONFIG, INFO, WARNING and SEVERE.
# The default level for all loggers and handlers is INFO.
.level= ALL
 
# Configure the ConsoleHandler.
# ConsoleHandler uses java.util.logging.SimpleFormatter by default. 
# Even though the root logger has the same level as this,
# the next line is still needed because we're configuring a handler,
# not a logger, and handlers don't inherit properties from the root logger.
java.util.logging.ConsoleHandler.level =INFO
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
 
# The following special tokens can be used in the pattern property
# which specifies the location and name of the log file.
#   / - standard path separator
#   %t - system temporary directory
#   %h - value of the user.home system property
#   %g - generation number for rotating logs
#   %u - unique number to avoid conflicts
# FileHandler writes to %h/demo0.log by default.
java.util.logging.FileHandler.pattern=%h/asdk%u.log
 
 
# Configure the FileHandler.
# FileHandler uses java.util.logging.XMLFormatter by default. 
#java.util.logging.FileHandler.limit = 50000
#java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.FileHandler.level=ALL

The following is a sample of the log output:

Apr 19, 2011 5:20:39 AM AccessClient createClient
FINER: ENTRY
Apr 19, 2011 5:20:39 AM ObAAAServiceClient setHostPort
FINER: ENTRY
Apr 19, 2011 5:20:39 AM ObAAAServiceClient setHostPort
FINER: RETURN
Apr 19, 2011 5:20:39 AM ObAAAServiceClient setHostPort
FINER: ENTRY
Apr 19, 2011 5:20:39 AM ObAAAServiceClient setHostPort
FINER: RETURN
Apr 19, 2011 5:20:39 AM AccessClient createClient
FINER: RETURN
Apr 19, 2011 5:20:39 AM AccessClient initialize
FINER: read config from server, re-init if needed
Apr 19, 2011 5:20:39 AM AccessClient updateConfig
FINER: ENTRY
Apr 19, 2011 5:20:39 AM AccessClient readConfigFromServer
FINER: ENTRY
Apr 19, 2011 5:20:39 AM ObAAAServiceClient getClientConfigInfo
FINER: ENTRY
Apr 19, 2011 5:20:39 AM ObAAAServiceClient sendMessage
FINER: ENTRY
Apr 19, 2011 5:20:39 AM oracle.security.am.common.nap.util.NAPLogger log
FINER: Getting object using poolid primary_object_pool_factory
Apr 19, 2011 5:20:39 AM oracle.security.am.common.nap.util.pool.PoolLogger logEntry
FINER: PoolLogger : main entered: KeyBasedObjectPool.acquireObject
Apr 19, 2011 5:20:39 AM oracle.security.am.common.nap.util.NAPLogger log
FINEST: Creating pool with id = primary_object_pool_factory
Apr 19, 2011 5:20:39 AM oracle.security.am.common.nap.util.pool.PoolLogger log
FINER: PoolLogger:main : Maximum Objects = 1Minimum Objects1
Apr 19, 2011 5:20:39 AM oracle.security.am.common.nap.util.pool.PoolLogger logEntry
FINER: PoolLogger : main entered: constructObject
Apr 19, 2011 5:20:39 AM oracle.security.am.common.nap.ObMessageChannelImpl <init>

2.4 Building an Access Client Program

The following topics are discussed in this section:

2.4.1 Setting the Development Environment

The required environment is as follows:

  • Install JDK 1.6.0 or higher.

  • Install 11g Access SDK.

  • Define a JAVA_HOME environment variable to point to JDK installation directory. For example, on UNIX-like operating systems, execute the following command:

    setenv JAVA_HOME <JDK install dir>/bin
    
  • Modify the PATH environment variable to the same location where JAVA_HOME/bin points. For example, on UNIX-like operating systems, execute the following command:

    setenv PATH $JAVA_HOME/bin:$PATH
    
  • Modify the CLASSPATH environment variable to point to JDK and Access SDK jar files. For example, on UNIX-like operating systems, execute the following command:

    setenv CLASSPATH $JAVA_HOME/lib/tools.jar:$ACCESSSDK_INSTALL_DIR/oamasdk-api.jar:$CLASSPATH
    

    For a list of all jar files required in the CLASSPATH variable, see Section 2.1.2, "About Installing Access SDK".

2.4.2 Compiling a New Access Client Program

After the development environment is configured (see Section 2.4.1, "Setting the Development Environment"), you can compile your Access Client program using a command similar to the following:

Javac –cp <location of Access SDK jar> SampleProgram.java

Modify details such as CLASSPATH and Access Client program name as needed. For more information about the jar files to add to CLASSPATH, see Section 2.1.2, "About Installing Access SDK".

2.5 Configuring and Deploying Access Clients

After development, the Access Client must be deployed in a live Access Manager 11g environment before you can test and use it. This section describes the configuration steps required before deploying an Access Client developed using the Access SDK. The Access Client deployment process is similar to that of other Access Manager agents.

This section provides the following topics:

2.5.1 Task Overview: Configuring and Deploying an Custom Access Client

The following overview outlines the tasks that must be performed by a user with Oracle Access Management administrator credentials. It is assumed that the Access Client program is already developed and compiled.

  1. Retrieve the Access SDK jar file and copy this to the computer you will use to build the Access Client. For more information, see Section 2.1.2, "About Installing Access SDK".

  2. Copy the Access Client to the computer hosting the application to be protected.

  3. Configure the Access Client.

  4. Verify you have the required Java environment available.

    If your Access Client is in a standalone environment, you can use Java Development Kit (JDK) or Java Runtime Environment (JRE). If your Access Client is a servlet application, you can use Java EE or the Java environment available with your Java EE container.

  5. Verify that the Access SDK jar file is in the CLASSPATH. If in a non-JRF environment (standalone application), verify that the necessary JPS jar files are in the CLASSPATH. For more information, see Section 2.1.2, "About Installing Access SDK".

  6. To deploy the Access Client, see "Registering Agents and Applications by Using the Console" in Oracle Fusion Middleware Administrator's Guide for Oracle Access Management.

2.5.2 Configuration Requirements

An Access SDK configuration consists of the following files:

  • ObAccessClient.xml

    This configuration file (ObAccessClient.xml) holds various details, such as Access Manager server host, port, and other configuration items, that decide behavior of the Access Client. For example, idle session time.

    An alternative to using ObAccessClient.xml is to initialize the 11.1.2 Access SDK by providing a bootstrap configuration. An access client or application can use a bootstrap configuration from its own configuration store or other method. Configuration details such as host and port number of the OAM Server can be invoked using AccessClient.createDefaultInstance. For more information about programmatic initialization, see Oracle Fusion Middleware Access SDK Java API Reference for Oracle Access Management Access Manager.

  • cwallet.sso

    This Oracle wallet file is an artifact created when an 11g agent is registered with Access Manager. The cwallet.sso file contains the secret key that is used by OAM Server when encrypting a token issued for the agent.

    The cwallet.sso file can be stored in the same location as other files, or elsewhere. The path must be declared in jps-config.xml and is relative to the jps-config.xml location.

  • jps-config.xml

    This file is required by the libraries used to read the cwallet.sso file. It must reside in the Access SDK configuration directory. It can reside in either of the following locations:

    • default under <current working dir>/config/jps-config.xml (template is extracted from unzipping the client install zip file), where <current working dir> is the directory where the client install zip file was unzipped. Or,

    • can be specified through -Doracle.security.jps.config=jps-config.xml file location. You must pass the location as a property in the Java command.

    A sample jps-config.xml file is included in the client install package zip file.

  • JKS Keystores for SSL

    This file is required only if the transport security mode is Simple or Cert. Both the 10g OAM Server and 11g OAM Server supports transport security modes Open, Simple and Cert to communicate with agents. Credentials are passed using the Oracle Access Protocol (OAP). When OAP is used in Open mode the communication is vulnerable to eavesdropping, so Open mode is discouraged in production environments. Open mode is recommended in testing environments only.

    An Access Client developed using Access SDK is called an agent. Depending on the mode in which OAM Server is configured, an Access Client will have to be configured to communicate in the same mode.

    Each 11g agent has its own agent key, unlike the 10g agent that shares the same global key across all 10g agents. The 11g agent key is stored in cwallet.sso. This key is used to encrypt the 11g format SSO token, the accessClientPasswd, and the global passphrase (stored in password.xml) used in Simple or Cert transport security mode. The SSO token issued for one agent cannot be used directly for another agent, unless you obtain a scoped session token from a master token. For more information, see Oracle Fusion Middleware Administrator's Guide for Oracle Access Management.

    For Simple or Cert transport security mode, the following is required:

    • oamclient-truststore.jks

    • oamclient-keystore.jks

    • password.xml

    For more information, see Section 2.1.3.2, "Access Client Architecture" and Section 2.5.3, "Generating the Required Configuration Files".

  • password.xml

    This file is required only if the transport security mode is Simple or Cert. This file contains a password in encrypted form. This password is the one using which SSL key file is protected.

    For more information, see Section 2.5.3, "Generating the Required Configuration Files".

  • Log Configuration

    Is required in order to generate a log file. For more information, see Section 2.3.3, "Logging".

2.5.3 Generating the Required Configuration Files

The ObAccessClient.xml configuration file can be obtained by registering an Access Client as either an 10g or 11g agent with the OAM 11g Server, using the administration console or a remote registration tool. When registering 11g agents the cwallet.sso file is also created. For more information, see Oracle Fusion Middleware Administrator's Guide for Oracle Access Management.

The administration console will also create a password.xml file.

An Access Client application developed with the oracle.security.am.asdk API can specify the location to obtain the configuration file and other required files. This is done by initializing the Access SDK and providing the directory location where the configuration files exist.

For information about options available to specify location of the configuration files to the Access SDK, see Oracle Fusion Middleware Access SDK Java API Reference for Oracle Access Management Access Manager.

2.5.4 SSL Certificate and Key Files

The 11g Access SDK uses SSL certificates and key files from a database commonly known as trust stores or key stores. It requires these stores to be in JKS (Java Key Standard) format.

2.5.4.1 Simple Transport Security Mode

In Simple transport mode, the JKS keystores are auto-generated by the OAM Server. The generated keystores are located in WLS_OAM_DOMAIN_HOME/output/webgate-ssl/.

2.5.4.2 Cert Transport Security Mode

In Cert transport security mode, the certificates for the server and agent should be requested from a certifying authority. Optionally, the Simple mode self-signed certificates can also be used as a certifying authority, for purposes of issuing Cert mode certificates.

Follow these steps to prepare for Cert mode:

  1. Import a CA certificate of the certifying authority using the certificate and key pair issued for Access Client and OAM Server. Follow the steps in Section 2.5.4.2.1, "Importing the CA Certificate". Instead of cacert.pem or cacert.der, substitute the CA certificate file of the issuing authority.

  2. If 10g JNI ASDK install is available, it provides a way to generate certificate and key file for the Access Client. These certificates will be in PEM format.

    For more information about how to generate a certificate using an imported CA certificate, see Oracle Fusion Middleware Administrator's Guide for Oracle Access Management.

    To import this certificate, key pair in the oamclient-keystore.jks in PEM format, follow instructions in Section 2.5.4.2.2, "Setting Up The Keystore".

2.5.4.2.1 Importing the CA Certificate

This step is not required when using the 11g Java Access SDK.

The CA certificate must be imported to the trust store when using the 10g JNI SDK. The 10g Access SDK provides a self-signed CA certificate that can be used in Simple mode, and is used for issuing certificates to the Access Client. 11g OAM Server provides a self-signed CA certificate.

  • 10g Access SDK: The CA certificate (cacert.pem) is located in ASDK_INSTALL_DIR/oblix/tools/openssl/simpleCA.

  • OAM 11g Server: The CA certificate (cacert.der) is located in $MIDDLEWARE_HOME/user_projects/domains/base_domain/config/fmwconfig.

Execute the following command to import the PEM or DER format CA certificate into trust store:

  1. Edit cacert.pem or cacert.der using a text editor to remove all data except what is contained within the CERTIFICATE blocks, and save the file. For example:

    -----BEGIN CERTIFICATE-----
            Content to retain
    -----END CERTIFICATE-----
    
  2. Execute the following command, modifying as needed for your environment:

    keytool -importcert -file <ca cert file cacert.pem or cacert.der> -trustcacerts -keystore oamclient-truststore.jks -storetype JKS

  3. Enter keystore password when prompted. This must be same as the global pass phrase used in the OAM Server.

2.5.4.2.2 Setting Up The Keystore

The Access Client's SSL certificate and private key file must be added to the keystore. The SSL certificate and private key file must be generated in Simple mode so the Access Client can communicate with OAM Server.

  • 10g Access SDK: provides for generating a certificate and key file for the Access Client. These certificates are in PEM format.

  • 11g OAM Server: Use the tool Remote Registration and administration console for generating a certificate file (aaa_cert.pem) and key file (aaa_key.pem) in PEM format for the Access Client.

Execute the following commands in order to import the certificate and key file into keystore oamclient-keystore.jks.

  1. Edit aaa_cert.pem using any text editor to remove all data except that which is contained within the CERTIFICATE blocks, and save the file. For example:

    -----BEGIN CERTIFICATE-----
            Content to retain
    -----END CERTIFICATE-----
    
  2. Execute the following command, modifying as needed for your environment:

    openssl pkcs8 -topk8 -nocrypt -in aaa_key.pem -inform PEM -out aaa_key.der -outform DER

    This command will prompt for a password. The password must be the global pass phrase.

  3. Execute the following command, modifying as needed for your environment:

    openssl x509 -in aaa_cert.pem -inform PEM -out aaa_cert.der -outform DER

  4. Execute the following command, modifying as needed for your environment:

    java -cp importcert.jar oracle.security.am.common.tools.importcerts.CertificateImport -keystore oamclient-keystore.jks -privatekeyfile aaa_key.der -signedcertfile aaa_cert.der -storetype jks -genkeystore yes

    In this command, aaa_key.der and aaa_cert.der are the private key and certificate pair in DER format.

  5. Enter the keystore password when prompted. This must be same as global pass phrase.

2.6 Compatibility: 11g versus 10g Access SDK and APIs

The following topics are discussed in this section:

The 11g Access Manager API enables developers to write custom Access Client code in Java, which is functionally equivalent to the 10g (10.1.4.3) Java Access Client. With Access Manager 11g, your Java code will interact with underlying Java binaries in the API.

The automatic built-in Java garbage collector deallocates the memory for unused objects when it (the garbage collector) deems appropriate. Garbage collectors do not guarantee when an object will be cleaned up, but do ensure that all objects are destroyed when they are no longer referenced, and no memory leak occurs.

10g and 11g Access Manager API functionality has been organized into seven basic classes. Table 2-3 lists the corresponding class names for the Java language platform.

Table 2-3 Comparison: 11g versus 10g Access API Classes

Purpose of the Class 11g Java Class 10g Java Class

Creates and manipulates structures that handle user authentication

AuthenticationScheme class from oracle.security.am.asdk

ObAuthenticationScheme implements ObAuthenticationSchemeInterface

Creates and manipulates structures that handle user requests for resources

ResourceRequest class from oracle.security.am.asdk

ObResourceRequest implements ObResourceRequestInterface

Creates and manipulates structures that handle user sessions, which begin when the user authenticates and end when the user logs off or the session times out.

Creates and manipulates structure that handles a unified session for the user, which begins when user is authenticated for the first time and ends when the user logs off or the session times out.

UserSession class from oracle.security.am.asdk

PseudoUserSession class from oracle.security.am.asdk

ObUserSession implements ObUserSessionInterface

ObPseudoUserSession

Retrieves and modifies Access Client configuration information

AccessClient class from oracle.security.am.asdk

ObConfig

Handles errors thrown by the Access Manager API

AccessException, OperationNotPermittedException from oracle.security.am.asdk

ObAccessException

Notifies the change in configuration to the calling application.

ConfigUpdateCallback class from oracle.security.am.asdk

 

2.6.1 Compatibility of the 11g Access SDK

The 11g Access SDK implements the same functionality that is supported by the 10g JNI ASDK. This functionality is implemented so that you can use it to develop custom Access Clients that work seamlessly with both the 10g and 11g OAM Server.

The Access SDK also implements some new and modified functionality that can only be used with an 11g OAM Server. Consequently, the Access SDK can gracefully detect whether the application is trying to use this functionality with 10g OAM Server.

The new functionality in the 11g Access SDK (oracle.security.am.asdk) is as follows:

  • Enumerating sessions for the given user

  • Terminating the given session

  • Setting attributes in the given user session

  • Retrieving attributes set in the given session

  • Validating user credentials without establishing a session

  • Validating user credentials without establishing a session and performing authorization in the same request

Note:

The last two functions are also provided with the com.oblix.access package in the Access Manager 11g Access SDK.

Additionally, the Access SDK provides a modified implementation of the user logout functionality for removing the server side session. This functionality is not supported with 10g OAM Server.

2.6.2 Compatibility of 10g JNI ASDK and 11g Access SDK

There is a one-to-one mapping between the 10g JNI ASDK and the 11g Access SDK version of the com.oblix.access package.

Custom Access Clients developed using 10g JNI ASDK can continue to work with 11g Access SDK without any code changes.

The following classes have been added to the 11g Access SDK com.oblix.access package:

  • ObPseudoUserSession: This class provides the following functionality that can be used only with 11g OAM Server:

    • Validating user credentials without establishing a session.

    • Validating user credentials without establishing a session and performing authorization in the same request.

  • ObAccessRuntimeException: This class indicates a runtime error while performing operations that use ObAuthenticationScheme and ObResourceRequest classes.

2.6.3 Deprecated: 10g JNI ASDK

The 11g Access SDK provides support for interfaces in the 10g JNI ASDK com.oblix.access package. However, all APIs in com.oblix.access are marked as deprecated. These APIs will not be enhanced or supported in future Access Manager 11g Access SDK releases.

Oracle strongly recommends that developers use the 11g Access SDK for all new development.

2.7 Migrating Earlier Applications or Converting Your Code

This section describes the migration processes to follow if you want to use the 11g Access SDK. Migrating to the Access SDK can be necessary for the following reasons:

This section contains the following topics:

2.7.1 Modifying Your Development and Runtime Environment

Before migrating an application, ensure that your development environment is configured. Also ensure that the 11g Access SDK is configured correctly. For more information, see Section 2.5, "Configuring and Deploying Access Clients".

2.7.2 Migrating Your Application

You can migrate Access Clients and plug-ins developed with the 10g com.oblix.access package to operate with the 11g OAM Server. This section describes how programs written with the 10g JNI ASDK can be used with 11g OAM Server.

Note:

For information about the similarities and differences between the com.oblix.access APIs in 10g JNI ASDK and in 11g Access SDK, see Section 2.6.2, "Compatibility of 10g JNI ASDK and 11g Access SDK".

Support for the classes and interfaces provided in 10g JNI ASDK and in 11g Access SDK is identical.

In general, you are not required to change or recompile any application code when migrating applications to use com.oblix.access classes from 11g Access SDK.

A new runtime exception, ObAccessRuntimeException, was introduced in the com.oblix.access package. This exception is thrown when performing operations of AuthenticationScheme and ResourceRequest classes.

Oracle recommends that you perform proper exception handling in the application code. If this is done, the application should be recompiled with the 11g Access SDK jar file.

2.7.2.1 Configuration Specific to Migration

This discussion assumes that 10g ASDK component is installed and configured with the OAM Server. This scenario uses existing Access Client applications developed using the 10g JNI ASDK. The following assumptions are made:

  • The configuration items listed in Section 2.5.2, "Configuration Requirements" are referenced from the 10g ASDK installation directory (ASDK_INSTALL_DIR).

  • ObAccessClient.xml is read from ASDK_INSTALL_DIR/access/oblix/lib.

  • password.xml is read from ASDK_INSTALL_DIR/access/oblix/config if the transport security mode is Simple or Cert.

Simple Mode

To configure the 10g ASDK component in Simple mode, see the Oracle Access Manager Administration Guide for the 10g release.

Perform the following steps:

  1. Import the aaa_cert.pem and aaa_key.pem files into oamclient-keystore.jks.

    The aaa_cert.pem and aaa_key.pem files are located in ASDK_INSTALL_DIR/access/oblix/config/simple.

  2. Located the self-signed CA certificate used for issuing Simple mode certificates in ASDK_INSTALL_DIR/access/oblix/tools/openssl/simpleCA.

  3. Import the self-signed CA certificate into oamclient-truststore.jks.

  4. Import the certificate and key files into the JKS store by following the steps in Section 2.5.4, "SSL Certificate and Key Files".

  5. Copy the JKS stores to ASDK_INSTALL_DIR/access/oblix/config/simple.

Cert Mode

To configure the 10g ASDK component in Cert mode, see the Oracle Access Manager Administration Guide for the 10g release.

Perform the following steps:

  1. Import the aaa_cert.pem and aaa_key.pem files into oamclient-keystore.jks. Import the aaa_chain.pem into oamclient-truststore.jks.

    The aaa_cert.pem, aaa_key.pemand aa_chain.pem files are located in ASDK_INSTALL_DIR/access/oblix/config.

  2. Import the certificate and key files into the JKS store by following the steps in Section 2.5.4, "SSL Certificate and Key Files".

  3. Copy the JKS stores to ASDK_INSTALL_DIR/access/oblix/config/simple.

Configuration File Location

An Access Client application migrated to use the com.oblix.access API can specify the 10g JNI ASDK configuration file locations as follows:

  • Either specify the direction location where the 10g ASDK is installed while initializing ASDK, or

  • Set an environment variable OBACCESS_INSTALL_DIR, which points to the directory location where the 10g JNI ASDK is installed.

The 11g Access SDK then determines the path of the required files based on the location passed to it.

Environment

To set your environment, follow the instructions in Section 2.4.1, "Setting the Development Environment". The 10g JNI ASDK is named jobaccess.jar. If jobaccess.jar is in your CLASSPATH, it must be removed.

2.7.3 Converting Your Code

This section describes how to use programs written with the 10g JNI ASDK with Access Manager 11g.

The 11g Java Access SDK supports the functionality of 10g JNI ASDK APIs in the com.oblix.access package. Implementing the same functionality in the 11g Access SDK enables backward compatibility with the 10g JNI ASDK. However, all of the APIs in com.oblix.access are deprecated. These APIs will not be enhanced or supported in future 11g Access SDK releases.

The oracle.security.am.asdk package contains a new authentication and authorization API. In addition to functionality supplied by the com.oblix.access package, the oracle.security.am.asdk package also contains enhancements that take advantage of 11g OAM Server functionality.

2.7.3.1 Understanding Differences Between 10g JNI ASDK and 11g Access SDK

The following table compares the APIs from the 10g JNI SDK com.oblix.access package with the APIs from the 11g Access SDK oracle.security.am.asdk package. Where applicable, this table also maps the classes between 10g JNI ASDK and 11g Access SDK.

Table 2-4 Package Differences: com.oblix.access and oracle.security.am.asdk

JNI ASDK com.oblix.access Package Access SDK oracle.security.am.asdk Package

Interface Summary:

  • ObAuthenticationSchemeInterface

  • ObResourceRequestInterface

  • ObUserSessionInterface

Interface Summary:

None

Class Summary:

  • ObAuthenticationScheme

  • ObConfig

  • ObDiagnostic

  • ObResourceRequest

  • ObUserSession

Class Summary:

  • AuthenticationScheme

  • AccessClient

  • Supported through AccessClient

  • ResourceRequest

  • UserSession

  • PseudoUserSession

  • BaseUserSession

Exception Summary:

ObAccessException

Exception Summary:

  • AccessException

  • OperationNotPermittedException

Enumeration Summary:

None

Enumeration Summary:

AccessClient.CompatibilityMode.OAM_10G

AccessClient.CompatibilityMode.OAM_11G


Note that the 11g Access SDK contains a new set of APIs that are functionally similar to the Oracle Access Manager 10g JNI SDK APIs, but with new interfaces.

2.7.3.2 Converting Code

You can migrate application code that was implemented using 10g JNI ASDK to achieve the same functionality in 11g Access SDK. This section explains how to modify existing application code to use the new API in 11g Access SDK.

2.7.3.2.1 Initializing and Uninitializing Access SDK

In the 10g JNI SDK, the com.oblix.access.ObConfig class provides a function to perform ASDK initialization and uninitialization. In 11g Access SDK, the oracle.security.am.asdk.AccessClient provides this function.

As with 10g JNI SDK, the Access Client application instance can work with a given configuration.

Depending on the requirement, you can use the AccessClient class in two different ways:

  • You can use the createDefaultInstance static function to create a single instance of the AccessClient class. Only a single default instance of this class is permitted. Invoking this method multiple times within a single instance of the Access Client application causes an exception.

    If you use the createDefaultInstance method, you must use the AccessClient class instance obtained using this method when instantiating any of AuthenticationScheme, ResourceRequest, or UserSession classes.

    If no AccessClient instance is specified when instantiating these classes, then the default instance is used.

    You can pass either AccessClient.CompatibilityMode.OAM_10G or AccessClient.CompatibilityMode.OAM_11G when initializing AccessClient objects. If not specified, then default OAM_11G would be used, in which case make sure the 11g agent is registered and the necessary 11g agent configuration files are set up properly.

  • You can use the createInstance static function to create a new AccessClient class instance initialized with a given configuration. This class is required when it is within the same running instance of an Access Client application, and the application must work with different Access Manager systems or different configurations. Each AccessClient class instance can log its messages to different log files by passing in an appropriate logger name while constructing the Access Client instances.

    You can pass either AccessClient.CompatibilityMode.OAM_10G or AccessClient.CompatibilityMode.OAM_11G when initializing AccessClient objects. If not specified, then default OAM_11G would be used, in which case make sure the 11g agent is registered and the necessary 11g agent configuration files are set up properly.

    If you use the createInstance method, you must use the AccessClient class instance obtained using this method when instantiating the AuthenticationScheme, ResourceRequest, or UserSession classes. Otherwise, if no AccessClient instance is specified when instantiating these classes, then the default instance is used.

While the application is shutting down, it should invoke the AccessClient class shutdown method to perform uninitialization as shown in the following examples:

  • For 10g JNI ASDK

    Public static void main (String args[]) {
      try {
       ObConfig.Initialize (); // Configuration is read from the location pointed by OBACCESS_INSTALL_DIR
                                             // environment variable
    

    OR

    ObConfig.Initialize (configLocation); //Configuration is read from the location provided
       ………..
       }catch (ObAccessException e){
       }
    ObConfig.shutdown();
    }//main ends here
    
  • For 11g Access SDK

    import java.io.*;
    import java.util.*;
    import oracle.security.am.asdk.*; //Import classes from OAM11g Access ASDK
    …………..
    Public static void main (String args[]) {
      try {
         ac = AccessClient.createDefaultInstance (“”, AccessClient.CompatibilityMode.OAM_10G); // Refer to Oracle Fusion Middleware Access SDK Java API Reference for Oracle Access Management Access Manager
    

    OR

    AccessClient.createInstance(“”,AccessClient.CompatibilityMode.OAM_10G); // Refer to Oracle Fusion Middleware Access SDK Java API Reference for Oracle Access Management Access Manager
       ………..
       }catch (AccessException e){
       }
    ac.shutdown();
    }//main ends here
    
2.7.3.2.2 Performing Access Operations

As shown in Table 2-4, there is a one-to-one mapping between the classes that are used to perform access operations. The classes in oracle.security.am.asdk are AuthenticationScheme, ResourceRequest, and UserSession.

Depending how the AccessClient class is instantiated, use the corresponding constructor of these classes.

Similar to 10g JNI ASDK, any error that occurs during initialization or while performing access operations, is reported as an exception. AccessException is the exception class used in 11g Access SDK as seen in the following examples:

  • For 10g JNI ASDK

    Public static void main (String args[]) {
      try {
       ObConfig.Initialize (); // Configuration is read from the location pointed by OBACCESS_INSTALL_DIR
                                             // environment variable
       ObResourceRequest rrq = new ObResourceRequest(ms_protocol, ms_resource,ms_method);
       if (rrq.isProtected()) {
         System.out.println("Resource is protected.");
         ObAuthenticationScheme authnScheme = new ObAuthenticationScheme(rrq);
         if (authnScheme.isForm()) {
           System.out.println("Form Authentication Scheme.");
           Hashtable creds = new Hashtable();
           creds.put("userid", ms_login);
           creds.put("password", ms_passwd);
           ObUserSession session = new ObUserSession(rrq, creds);
           if (session.getStatus() == ObUserSession.LOGGEDIN) {
             if (session.isAuthorized(rrq)) {
               System.out.println("User is logged in and authorized for the
               request at level " + session.getLevel());
             } else {
               System.out.println("User is logged in but NOT authorized");
             }
          } else {
            System.out.println("User is NOT logged in");
         }
       } else {
         System.out.println("non-Form Authentication Scheme.");
      }
    } else {
      System.out.println("Resource is NOT protected.");
    }
    }catch (ObAccessException oe) {
      System.out.println("Access Exception: " + oe.getMessage());
    }
    ObConfig.shutdown();
    }//main ends here
    
  • For 11g Access SDK

    import java.io.*;
    import java.util.*;
    import oracle.security.am.asdk.*; //Import classes from OAM11g Access ASDK
     
    Public static void main (String args[]) {
      AccessClient ac;
      try {
        ac = AccessClient.createDefaultInstance(“”,
         AccessClient.CompatibilityMode.OAM_10G);
     
        ResourceRequest rrq = new ResourceRequest(ms_protocol,ms_resource, ms_method);
     
        if (rrq.isProtected()) {
          System.out.println("Resource is protected.");
          AuthenticationScheme authnScheme =new AuthenticationScheme(rrq);
          if (authnScheme.isForm()) {
            System.out.println("Form Authentication Scheme.");
            Hashtable creds = new Hashtable();
            creds.put("userid", ms_login);
            creds.put("password", ms_passwd);
            creds.put("ip", ms_ip);
            creds.put("operation", ms_method);
            creds.put("resource", ms_resource);
            creds.put(“targethost”, ms_targethost);
     
            UserSession session = new UserSession(rrq, creds);
            if (session.getStatus() == UserSession.LOGGEDIN) {
              if (session.isAuthorized(rrq)) {
                System.out.println("User is logged in " +
                    "and authorized for the request " +"at level " + session.getLevel());
              } else {
                System.out.println("User is logged in but NOT authorized");
              }
            } else {
              System.out.println("User is NOT logged in");
            }
          }
        }catch (AccessException oe) {
          System.out.println("Access Exception: " + oe.getMessage());
        }
        ac.shutdown();
    } //main ends here
    

2.8 Best Practices

This section presents a number of ways to avoid problems and to resolve the most common problems that occur during development. The following topics are discussed in this section:

2.8.1 Avoiding Problems with Access Clients

Here are some suggestions for avoiding problems with the Access Clients you create:

  • Make sure that your Access Client attempts to connect to the correct OAM Server.

  • Make sure the configuration information on your OAM Server matches the configuration information on your Access Client. You can check the Access Client configuration information on your OAM Server, using the administration console. For details, see "Registering Agents and Applications" in Oracle Fusion Middleware Administrator's Guide for Oracle Access Management.

  • To ensure clean connect and disconnect from the OAM Server, use the initialize and shutdown methods in the AccessClient class.

  • The environment variable, OBACCESS_INSTALL_DIR, must be set on your Windows or UNIX-like host computer so that you can compile and link your Access Client. In general, you also want the variable to be set whenever your Access Client is running.

  • Use the exception handling features (try, throw, and catch) of the language used to write your custom Access Client code to trap and report problems during development.

2.8.1.1 Thread Safe Code

Your Access Client represents just one thread in your entire, multi threaded application.

To ensure safe operation within such an environment, Oracle recommends that developers observe the following practices:

  • Use a thread safe function instead of its single thread counterpart. For instance, use localtime_r instead of localtime.

  • Specify the appropriate build environment and compiler flags to support multithreading. For instance, use -D_REENTRANT. Also, use -mt for UNIX-like platforms and /MD for Windows platforms.

  • Take care to use in thread-safe fashion shared local variables such as FILE pointers.

2.8.2 Identifying and Resolving Access Client Problems

Here are some things to look at if your Access Client fails to perform:

  • Make sure that your OAM Server is running. On Windows systems, you can check this by navigating to Computer Management, then to Services, then to AccessServer, where AccessServer is the name of the OAM Server to which you want to connect your Access Client.

  • Make sure that Access Client performs user logout to ensure that OAM Server-side sessions are deleted. An accumulation of user sessions can prevent successful user authentication.

  • Check that the domain policies your code assumes are in place and enabled.

  • Read the Release Notes.

  • Check that your Access Client is not being answered by a lower-level Access System policy which overrides the one you think you are testing.

  • The 11g Access Tester enables you to check which policy applies to a particular resource. For details about using the Access Tester and protecting resources with application domains, see the Oracle Fusion Middleware Administrator's Guide for Oracle Access Management.

2.8.3 Resolving Environment Problems

This section provides information about resolving environment conflicts that can develop when using the 11g Java Access SDK.

2.8.3.1 Java EE Containers

Use this procedure to resolve Java class version conflicts when a web application using the 11g Access SDK.

A conflict can occur when a version of the library different from the one used by the Access SDK is loaded by another application hosted on the same Java EE container. The following is a sample error message that may display:

oracle/security/am/common/aaaclient/ObAAAServiceClient.&lt;init&gt;(Ljava/lang
/String;[CILjava/lang/String;Ljava/lang/String;[C[CZIJJLjava/lang/Integer;Ljava/u
til/List;Ljava/util/List;)V 
at oracle.security.am.asdk.AccessClient.createClient(AccessClient.java:798) 
at oracle.security.am.asdk.AccessClient.initialize(AccessClient.java:610) 
at oracle.security.am.asdk.AccessClient.&lt;init&gt;(AccessClient.java:527) 
at
oracle.security.am.asdk.AccessClient.createDefaultInstance(AccessClient.java:234) 
at com.newco.authenticateIdentity.AuthenticateIdentityAccessClient.authenticateUser(
AuthenticateIdentityAccessClient.java:52)

This issue is related to how classes are loaded into the Java EE container. For more information, see your container's documentation discussing class loading.

To solve this problem, configure class loader filtering for the web application that needs a specific library version. For more information and steps, see the documentation for your application server.

2.8.3.2 Oracle WebLogic Server

Use WebLogic Server FilteringClassLoader to specify packages that are always loaded from the application, rather than loaded using the system class loader.

To resolve this issue, perform these steps:

  1. Verify the weblogic-application.xml file exists in the META-INF folder of your application. If it does not, create this file and add the following contents:

    <?xml version="1.0" encoding="UTF-8"?>
    <weblogic-application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.bea.com/ns/weblogic/weblogic-application/1.0/we
    blogic-application.xsd"
    xmlns="http://www.bea.com/ns/weblogic/weblogic-application">
    
    <prefer-application-packages>
      <?xml version="1.0" encoding="UTF-8"?>
    <weblogic-application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.bea.com/ns/weblogic/weblogic-application/1.0/we
    blogic-application.xsd"
    xmlns="http://www.bea.com/ns/weblogic/weblogic-application">
    
    <prefer-application-packages>
    <package-name>Package to be loaded</package-name>
    <package-name>Package to be loaded</package-name>
    </prefer-application-packages>
    </weblogic-application>
    

    where Package to be loaded is the corresponding package from the log file. For example, assume the problem is ObAAAServiceClient, then the corresponding package name is oracle.security.am.common.aaaclient. Add as follows:

    <package-name>oracle.security.am.common.aaaclient.*<package-name>
    

    All classes associated with this package will be loaded by the application loader, even if identical classes having a different version are specified in the CLASSPATH of the System class loader.

  2. Stop the application.

  3. Delete the previously deployed version of the application.

  4. Install the application.

  5. Access the resource.

    The error should be gone and the application is running smoothly.

2.8.3.3 Other Application Servers

All application servers have a configuration file where class loading related options are configured. In general, the key is to identify the configuration file and tags that are required to enable a specific class loader to load a set of classes.

  1. Locate the configuration file for the application server.

  2. Use the application class loader to prevent classes from being loaded by the parent class loader, even if they are specified in the CLASSPATH.

  3. Change the default class loading behavior so the parent class loader is called only if the current class loader fails to load the class.

  4. Alternately, as in WebLogic Server, there may be a method that enables loading of classes using the designated class loader.

  5. In some application servers, you may need to define a separate domain for your application, for a parent domain, and set class loading behavior to load the parent last.

2.8.4 Tuning for High Load Environment

In a high load, high stress environment, the 11g Access SDK configuration must be tuned as follows:

  • Configure poolTimeout as a user defined parameter. You must increase the number of clients for poolTimeout.

  • Tune the maximum (max) number of connections. For high performance, the max number of connections of primary server should be in the agent profile.