Thursday, January 3, 2013

Authenticating OIM APIs without end user's password

A common requirement in an OIM implementation is to not expose OIM user interface to all types of end users. To address this requirement, usually a custom application using OIM APIs is developed and deployed. Such application will expose specific OIM functionalities to end users. In most of the cases, customers want the custom application/OIM APIs to act as the end user, and not as a service account; this approach leverages OIM security model, and the actions will be correctly audited in OIM. Usually this custom application will be protected by a SSO solution, and asking the end user to provide his/her password is not an option. So the big question is: how to authenticate the OIM APIs against OIM server and make them act as the end user?

This is another post in the OIM Academy series. To view the entire OIM 11g Academy series click here

In OIM 9.x, the APIs provide two different ways of authentication: through OIM user's credentials (username and password) and through the so called digital signature authentication. The digital signature authentication process allows authentication without a password, and because of that it is a largely used approach in custom OIM APIs based applications.

With the introduction of OIM 11g, the digital signature APIs are being deprecated. They will still work when correctly configured, but they may be discontinued in future OIM releases.

In R2 there is an easier way of using OIM APIs without the need of end's user password. This post shows how this can be done.

OIM uses standard J2EE/JAAS based authentication. Such authentication, in WebLogic world, is provided by the domain-level authentication providers. In an environment where OAM is providing SSO, such authenticators are integrated with OAM.

In a situation where the user has already been authenticated and a valid Subject (along with the correct Principals) is set in the J2EE session, the OIM APIs can be used without further authentication. Of course the authenticated Subject must be a valid one for OIM.

Some technical details:
  • This application runs in a separate WebLogic managed server created in the OIM domain
  • In this example OIM is protected by and integrated with OAM
  • The custom application is also protected by OAM
  • Both OIM and the custom application are accessed through OHS with a WebGate deployed on it
  • The custom application is a Java Servlet that uses the OIM APIs to get user's detailed information based on the logged in user
The detailed configuration steps are:

1. Managed server creation and configuration

The custom application will be deployed to a managed server created in the OIM WebLogic domain. In this example, the server is called 'myapp_server1'. The managed server was created by using the WebLogic administration console.

There are two details that must be observed:

  • Configure the new server as a target for the 'opss-DBDS' JDBC data source. This will prevent the server from failing at start up time
  • Make sure that the server is configured to listen in a free port. In this example the port 9001 was used.

2. OHS server configuration

Create a custom file called 'myCustomApp.conf' in the $ORACLE_INSTANCE/config/OHS/ohs1/moduleconf folder.

The file contents:

<Location /myCustomOIMApp>
    SetHandler weblogic-handler
    WebLogicHost [WL_HOST]

    WebLogicPort [WL_PORT]
    WLLogFile "${ORACLE_INSTANCE}/diagnostics/logs/mod_wl/oim_component.log"
</Location>


 [WL_HOST]  and [WL_PORT] must be replaced by their respective values.

3. OAM resource creation

The custom application must be protected by OAM. This will guarantee that when the browser request hits the application, it has already been authenticated and the J2EE Subject information is already set.

In this example, the OAM resource is created under the 'IAM Suite' application domain.

The custom application URI is '/myCustomOIMApp'.

A new resource of type 'HTTP' is created, the resource URL is set to '/myCustomOIMApp/**', and the resource is configured with 'Protect' protection level, 'Protected HigerLevel Policy' as authentication policy and 'Protected Resource Policy' as authorization policy.

The images below shows the configured resource:





4. Custom application details and deployment

The custom application is a simple Java Servlet that leverage OIM APIs to get detailed user information and print such information to the Servlet output. It also prints the available HTTP headers.It is deployed to the managed server created in step '1' as an application.

In order to this application be accessible through the OHS/WebGate, the application URI must match the URI configured in steps 2 and 3:  '/myCustomOIMApp'. In this example this is defined in the 'weblogic.xml' descriptor.

The Java Servlet method below is the one that connects to OIM and gets the logged in user information:

public void printMyOIMInfo(PrintWriter out) throws IOException, ServletException {

  try {
    Hashtable hm = new Hashtable();
    hm.put(OIMClient.JAVA_NAMING_PROVIDER_URL, "t3://<oim_server_address>:14000");

    OIMClient client = new OIMClient(hm); 
    AuthenticatedSelfService selfsvc = client.getService(AuthenticatedSelfService.class);

    Set retAttr = new HashSet();
    retAttr.add(AttributeName.USER_LOGIN.getId());
    retAttr.add(AttributeName.FIRSTNAME.getId());
    retAttr.add(AttributeName.LASTNAME.getId());

    User user = selfsvc.getProfileDetails(retAttr);
    Set attrNames = user.getAttributeNames();
    Iterator iter = attrNames.iterator();

    out.println("<TABLE ALIGN=CENTER BORDER=1>");
    out.println("<tr><th> Attribute Name </th><th> Attribute Value </th>");

    while (iter.hasNext()) {

      String attrName = (String)iter.next();
      out.println("<tr><td align=center><b>" + attrName + "</td>");
      out.println("<td align=center>" + user.getAttribute(attrName).toString()+ "</td></tr>");
    }

    out.println("</TABLE><>");

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

Note how the OIMClient instance is acquired: all the information needed is the OIM t3 location (t3://<oim_server_address>:14000). There is no need to provide credentials because the session is already authenticated by the container. This approach provides a very simple way of acquiring OIM API instances from an external application.

It is important to mention that the oimclient.jar library must be deployed in the application. In this example, it was deployed under WEB-INF/lib folder in the WAR file.

The XML below is the J2EE web.xml descriptor:
<?xml version = '1.0' encoding = 'windows-1252'?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5" xmlns="http://java.sun.com/xml/ns/javaee">
  <servlet>
    <servlet-name>MyCustomOIMServlet</servlet-name>
    <servlet-class>com.oracle.demo.iam.MyCustomOIMServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>MyCustomOIMServlet</servlet-name>
    <url-pattern>/myInfo</url-pattern>
  </servlet-mapping>
  <login-config>
    <auth-method>CLIENT-CERT</auth-method>
  </login-config>
</web-app> 

It is important to notice the 'login-config' section and the 'CLIENT-CERT' authentication method. This method tells WebLogic to trigger the container based authentication. Since the application is protected by OAM and the OAM authenticator is deployed to WebLogic, the J2EE Subject will be created based on the username that got externally authenticated by OAM.

The picture below shows the Servlet output for the logged in user 'bob.dylan':


The result of invoking 'request.getUserPrincipal().getName()' is highlighted in yellow .

The information retrieved from OIM by the OIM APIs is highlighted in green.

The available HTTP request headers are highlighted in red.

The JDeveloper workspace created for this post can be found here, file name is 'MyCustomOIMApp.zip'. You will need to have OIM client jar defined as a JDeveloper library in order to get the project compiled.

4 comments:

  1. Hello,

    Thanks for the post. Is there a way to point the log out url for OIM to login url for OIM? I just can't find this property. All the documentations point me to Oracle Access Manager. Unfortunately, we do not have OAM installed in the environment.

    Thanks

    ReplyDelete
    Replies
    1. Laks, I did not understand the question. Why would you want to point logout URL to login URL? What are you trying to achieve?

      Delete
    2. Is there any special configuration needed if this servlet is deployed on a remote weblogic domain which participates in the same OAM SSO realm. I am getting exception when i attempt this:
      https://forums.oracle.com/forums/thread.jspa?threadID=2531885&tstart=0

      Delete
    3. Shidart, I didn't get the whole picture. If your servlet is running in a different domain than OIM, then you have to enable cross domain trust: http://docs.oracle.com/cd/E15051_01/wls/docs103/secmanage/domain.html

      Delete

Note: Only a member of this blog may post a comment.