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

Previous
Previous
Next
Next
 

9 Developing Applications for Single Sign-On

This chapter explains how to develop applications to work with mod_osso. The chapter contains the following topics:

9.1 What Is mod_osso?

In OracleAS release 10.1.2, you use mod_osso, an authentication module on the Oracle HTTP Server, to enable applications for single sign-on. mod_osso is a simple alternative to the single sign-on SDK, used in earlier releases to integrate partner applications. mod_osso simplifies the authentication process by serving as the sole partner application to the single sign-on server. By doing so, it renders authentication transparent for OracleAS applications.

After authenticating users, mod_osso transmits the simple header values that applications need to validate them. These include the following:

Table 9-1 lists all of the user attributes that mod_osso passes to applications. The table also recommends attributes to use as keys, or handles, to retrieve additional user attributes from Oracle Internet Directory.

Table 9-1 User Attributes Passed to Partner Applications

HTTP Header Name Description Source Use as Key or Handle?
Osso-User-Guid

Single sign-on user's globally unique user ID (GUID).

Single sign-on user's globally unique user ID (GUID).

Recommended.

Osso-Subscriber-Guid

Realm GUID.

Realm entry in Oracle Internet Directory.

Recommended.

Remote-User

User nickname as entered by user on the login page.

Single sign-on login page.

Recommended for pre-9.0.4 applications only.

Osso-Subscriber

User-friendly name for a realm.

Realm entry in Oracle Internet Directory.

Not recommended. Use GUID headers to perform user searches in Oracle Internet Directory.

Accept-Language

Language and territory in ISO format.

Single sign-on server.

Not applicable.


mod_osso interoperates only with the Oracle HTTP listener. You can use OracleAS SSO Plug-in to protect applications that work with third-party listeners such as Sun One and IIS. To learn how to use OracleAS SSO Plug-in, see the appendix about this tool in Oracle HTTP Server Administrator's Guide.

9.2 Protecting Applications Using mod_osso: Two Methods

mod_osso redirects the user to the single sign-on server only if the URL you request is configured to be protected. You can secure URLs in one of two ways: statically or dynamically. Static directives simply protect the application, ceding control over user interaction to mod_osso. Dynamic directives not only protect the application, they also enable it to regulate user access.

This section contains the following topics:

9.2.1 Protecting URLs Statically

You can statically protect URLs with mod_osso by applying directives to the mod_osso.conf file. This file is found at $ORACLE_HOME/Apache/Apache/conf. In the example that follows, a directory named /private, located just below the Oracle HTTP Server document root, is protected by this directive:

<IfModule mod_osso.c>

  <Location /private>
    AuthType Basic
    require valid-user
  </Location>

</IfModule>

After making the entry, restart the Oracle HTTP Server:

$ORACLE_HOME/opmn/bin/opmnctl restartproc type=ohs

Finally, populate the directory with pages and then test them. For example:

http://host:port/private/helloworld.html

9.2.2 Protecting URLs with Dynamic Directives

Dynamic directives are HTTP response headers that have special error codes that enable an application to request granular functionality from the single sign-on system without having to implement the intricacies of the single sign-on protocol. Upon receiving a directive as part of a simple HTTP response from the application, mod_osso creates the appropriate single sign-on protocol message and communicates it to the single sign-on server.

OracleAS supports dynamic directives for Java servlets and JSPs. The product does not currently support dynamic directives for PL/SQL applications.

Table 9-2 lists commonly requested dynamic directives.

Table 9-2 Commonly Requested Dynamic Directives

Directive Status Code Headers

Request Authentication

401, 499

-

Request Forced Authentication

499

Osso-Paranoid: true

Single Sign-Off

470

Osso-Return-URL

This is the URL to return to after single sign-off is complete


9.3 Developing Applications Using mod_osso

This section explains how to write and enable applications using mod_osso. The section contains the following topics:

9.3.1 Developing Statically Protected PL/SQL Applications

What follows is an example of a simple mod_osso-protected application. This application logs the user in to the single sign-on server, displays user information, and then logs the user out of both the application and the single sign-on server.

Use the following steps to write and enable a PL/SQL application using mod_osso.

  1. Create the schema where application procedure will be loaded.

    sqlplus sys/sys_password as sysdba
    create user schema_name identified by schema_password;
    grant connect,  resource to schema_name;
    
    
  2. Load the following procedure into the schema and grant the public access to the procedure:

    create or replace procedure show_user_info
     is
     begin
        begin
            htp.init;
         exception
             when others then null;
         end;
         htp.htmlOpen;
         htp.bodyOpen;
         htp.print('<h2>Welcome to Oracle Single Sign-On</h2>');
         htp.print('<pre>');
         htp.print('Remote user:'
            || owa_util.get_cgi_env('REMOTE_USER'));
         htp.print('User DN:'
            || owa_util.get_cgi_env('Osso-User-Dn'));
         htp.print('User Guid:'
            || owa_util.get_cgi_env('Osso-User-Guid'));
         htp.print('Subscriber:'
            || owa_util.get_cgi_env('Osso-Subscriber'));
         htp.print('Subscriber DN:'
            || owa_util.get_cgi_env('Osso-Subscriber-Dn'));
         htp.print('Subscriber Guid:'
            || owa_util.get_cgi_env('Osso-Subscriber-Guid'));
         htp.print('</pre>');
         htp.print('<a href=/osso_logout?'
            ||'p_done_url=http://my.oracle.com>Logout</a>');
    
         htp.bodyClose;
         htp.htmlClose;
    end show_user_info;
    /
    show errors;
    
    grant execute on show_user_info to public;
    
    
  3. Create a database access descriptor (DAD) for the application in the dads.conf file, located at $ORACLE_HOME/Apache/modplsql/conf:

    <Location /pls/DAD_name>
           SetHandler pls_handler
           Order deny,allow
           AllowOverride None
           PlsqlDatabaseConnectString    hostname:port:SID
           PlsqlDatabasePassword         schema_password
           PlsqlDatabaseUsername         schema_name
           PlsqlDefaultPage              schema_name.show_user_info
           PlsqlDocumentTablename        schema_name.wwdoc_document
           PlsqlDocumentPath             docs
           PlsqlDocumentProcedure        schema_name.wwdoc_process.process_
                                         download
           PlsqlAuthenticationMode       Basic
           PlsqlPathAlias                url
           PlsqlPathAliasProcedure       schema_name.wwpth_api_alias.process_
                                         download
           PlsqlSessionCookieName        schema_name
           PlsqlCGIEnvironmentList       OSSO-USER-DN
           PlsqlCGIEnvironmentList       OSSO-USER-GUID
           PlsqlCGIEnvironmentList       OSSO-SUBSCRIBER
           PlsqlCGIEnvironmentList       OSSO-SUBSCRIBER-DN
           PlsqlCGIEnvironmentList       OSSO-SUBSCRIBER-GUID
    </Location>
    
    
  4. Protect the application DAD by entering the following lines in the mod_osso.conf file:

    <Location /pls/DAD_name>
      require valid-user
      authType Basic
    </Location>
    

    Note:

    The assumption here is that mod_osso is already configured for single sign-on. This step is performed when OracleAS is installed.

  5. Restart the Oracle HTTP Server:

    http://host:port/private/helloworld.html
    
    
  6. To test whether the newly created functions and procedures are protected by mod_osso, try to access them from a browser:

    http://host:port/pls/DAD/schema_name.show_user_info
    
    

    Selecting the URL should invoke the single sign-on login page if mod_osso.conf has been configured properly and mod_osso is registered with the single sign-on server.

9.3.2 Developing Statically Protected Java Applications

Use the following steps to write and enable a servlet or JSP application using mod_osso:

  1. Write the JSP or servlet. Like the PL/SQL application example immediately preceding, the simple servlet that follows logs the user in, displays user information, and then logs the user out.

    import java.io.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    
    /**
     * Example servlet showing how to get the SSO User information
     */
    
    public class SSOProtected extends HttpServlet
    {
      
        public void service(HttpServletRequest request,
             HttpServletResponse response)
            throws IOException, ServletException
        {
            response.setContentType("text/html");
    
            // Show authenticated user informationsingle sign-on
            PrintWriter out = response.getWriter();
            out.println("<h2>Welcome to Oracle Single Sign-On</h2>");
            out.println("<pre>");
            out.println("Remote user: "
                + request.getRemoteUser());
            out.println("Osso-User-Dn: "
                +  request.getHeader("Osso-User-Dn"));
            out.println("Osso-User-Guid: "
                +  request.getHeader("Osso-User-Guid"));
            out.println("Osso-Subscriber: "
                +  request.getHeader("Osso-Subscriber"));
            out.println("Osso-User-Dn: "
                +  request.getHeader("Osso-User-Dn"));
            out.println("Osso-Subscriber-Dn: "
                +  request.getHeader("Osso-Subscriber-Dn"));
            out.println("Osso-Subscriber-Guid: "
                +  request.getHeader("Osso-Subscriber-Guid"));
            out.println("Lang/Territory: "
                + request.getHeader("Accept-Language"));
            out.println("</pre>");
            out.println("<a href=/osso_logout?"
                +"p_done_url=http://my.oracle.com>Logout</a>");
    
    
  2. Protect the servlet by entering the following lines in the mod_osso.conf file:

    <Location /servlet>
       require valid-user
       authType Basic
    </Location>
    
    
  3. Deploy the servlet. If you need help, see the overview chapter in Oracle Application Server Containers for J2EE Servlet Developer's Guide. This chapter provides an example of a servlet and shows how to deploy it.

  4. Restart the Oracle HTTP Server and OC4J:

    $ORACLE_HOME/opmn/bin/opmnctl restartproc type=ohs
    $ORACLE_HOME/opmn/bin/opmnctl stopproc type=oc4j
    $ORACLE_HOME/opmn/bin/opmnctl startproc type=oc4j
    
    
  5. Test the servlet by trying to access it from the browser. Selecting the URL should invoke the login page.

    The process is this: when you try to access the servlet from the browser, you are redirected to the single sign-on server for authentication. Next you are redirected back to the servlet, which displays user information. You may then select the logout link to log out of the application as well as the single sign-on server.

9.3.3 Developing Java Applications That Use Dynamic Directives

Applications that use dynamic directives require no entry in mod_osso.conf because mod_osso protection is written directly into the application as one or more dynamic directives. The servlets that follow show how such directives are incorporated. Like their "static" counterparts, these sample "dynamic" applications generate user information.

This section covers the following topics:

  • Java Example #1: Simple Authentication

  • Java Example #2: Single Sign-Off

  • Java Example #3: Forced Authentication

9.3.3.1 Java Example #1: Simple Authentication

This servlet uses the request.getRemoteUser()method to check the mod_osso cookie for the user name. If the user name is absent, the servlet issues dynamic directive 499, a request for simple authentication. The key lines are in boldface.

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

/**
 * Example servlet showing how to use
 * Dynamic Directive for login
 */

public class SSODynLogin extends HttpServlet
{

    public void service(HttpServletRequest request,
         HttpServletResponse response)
        throws IOException, ServletException
    {
        String l_user     = null;

        // Try to get the authenticate user name
        try
        {
            l_user = request.getRemoteUser();
        }
        catch(Exception e)
        {
            l_user = null;
        }

        // If user is not authenticated then generate
        // dynamic directive for authentication
        if((l_user == null) || (l_user.length() <= 0) )
        {
           response.sendError(499, "Oracle SSO");
        }
        else
        {
            // Show authenticated user information
            response.setContentType("text/html");
            PrintWriter out = response.getWriter();
            out.println("<h2>Welcome to Oracle Single Sign-On</h2>");
            out.println("<pre>");
            out.println("Remote user: "
                + request.getRemoteUser());
            out.println("Osso-User-Dn: "
                +  request.getHeader("Osso-User-Dn"));
            out.println("Osso-User-Guid: "
                +  request.getHeader("Osso-User-Guid"));
            out.println("Osso-Subscriber: "
                +  request.getHeader("Osso-Subscriber"));
            out.println("Osso-User-Dn: "
                +  request.getHeader("Osso-User-Dn"));
            out.println("Osso-Subscriber-Dn: "
                +  request.getHeader("Osso-Subscriber-Dn"));
            out.println("Osso-Subscriber-Guid: "
                +  request.getHeader("Osso-Subscriber-Guid"));
            out.println("Lang/Territory: "
                + request.getHeader("Accept-Language"));
            out.println("</pre>");
        }
    }

Note:

If Oracle JAAS Provider is used, the directive code 401 may be substituted for 499.

9.3.3.2 Java Example #2: Single Sign-Off

This servlet is invoked when users select the login link within an application. The application sets the URL to return to when sign-off is complete; then it issues a directive that sends users to the single sign-off page. The key lines are in boldface.

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

/**
 * Example servlet showing how to use
 * Dynamic Directive for logout
 */

public class SSODynLogout extends HttpServlet
{
    public void service (HttpServletRequest request,
         HttpServletResponse response)
        throws ServletException, IOException
    {
        // Set the return URL
        response.setHeader("Osso-Return-Url",
               "http://my.oracle.com" );
        // Send Dynamic Directive for logout
        response.sendError(470, "Oracle SSO");
    }
}

Note:

Alternatively, you can redirect to the osso_logout URL on that computer.

9.3.3.3 Java Example #3: Forced Authentication

If logged-in users have exceeded a timeout, an application can force them to reauthenticate. The directive for reauthentication is written into the servlet that follows. The key lines are in boldface.

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

/**
 * Example servlet showing how to use
 * Dynamic Directive for forced login
 */

public class SSODynForcedLogin extends HttpServlet
{

    public void service(HttpServletRequest request,
         HttpServletResponse response)
        throws IOException, ServletException
    {
        String l_user = null;
        // Try to get the authenticate user name
        try
        {
            l_user = request.getRemoteUser();
        }
        catch(Exception e)
        {
            l_user = null;
        }

        // If the user is authenticated then show
        // user information; otherwise generate Dynamic
        // Directive for forced login
        if(l_user != null)
        {
            // Show authenticated user information
            PrintWriter out = response.getWriter();
            response.setContentType("text/html");
            out.println("<h2>Welcome to Oracle Single Sign-On.</h2>");
            out.println("<pre>");
            out.println("Remote user: "
                + request.getRemoteUser());
            out.println("Osso-User-Dn: "
                +  request.getHeader("Osso-User-Dn"));
            out.println("Osso-User-Guid: "
                +  request.getHeader("Osso-User-Guid"));
            out.println("Osso-Subscriber: "
                +  request.getHeader("Osso-Subscriber"));
            out.println("Osso-User-Dn: "
                +  request.getHeader("Osso-User-Dn"));
            out.println("Osso-Subscriber-Dn: "
                +  request.getHeader("Osso-Subscriber-Dn"));
            out.println("Osso-Subscriber-Guid: "
                +  request.getHeader("Osso-Subscriber-Guid"));
            out.println("Lang/Territory: "
                + request.getHeader("Accept-Language"));
            out.println("</pre>");
        }
        else
        {
            response.setHeader( "Osso-Paranoid", "true" );
            response.sendError(499, "Oracle SSO");
       }
    }
}

9.3.4 A Word About Non-GET Authentication

The first page of a mod_osso-protected application must be a URL that uses the GET authentication method. If the POST method is used, the data that the user provides when logging in is lost during redirection to the single sign-on server. When deciding whether to enable the global user inactivity timeout, please note that users are redirected after timing out and logging in again.

9.3.5 Global Inactivity Timeout and Dynamic Directives

If you are using Global Inactivity Timeout and Dynamic Directive for enabling Single Sign-On for your applications, then you can use the Osso-Idle-Timeout-Exceeded HTTP header in your application to determine the timeout status. This header value is set to true if timeout has occurred, otherwise it is set to false.

The following example shows how you can use the Osso-Idle-Timeout-Exceeded HTTP header:

// Get the timeout status
String timeoutStatus = request.getHeader("Osso-Idle-Timeout-Exceeded")
// Check if user has timedout
if ( (timeoutStatus != null) && timeoutStatus.equalsIgnoreCase("true") )
{
   response.setHeader( "Osso-Paranoid", "true" );
   response.sendError(499, "Oracle SSO");
}
else
{
  // Display page content here
}

9.4 Security Issues

This section describes security considerations when developing applications for OracleAS Single Sign-On. It contains these topics:

9.4.1 Single Sign-Off and Application Logout

If you build custom applications using OracleAS, note the following: when global logout, or single sign-off, is invoked, only the single sign-on and mod_osso cookies are cleared. This means that an OracleAS application must be coded to store single sign-on user and realm names in either the OC4J session or in the application session. The application must then compare these values to those passed by mod_osso. If a match occurs, the application must show personalized content. If no match occurs, which means that the mod_osso cookie is absent, the application must clear the application session and force the user to log in.

This section covers the following topics:

9.4.1.1 Application Login: Code Examples

The first two code examples in this section do not incorporate the logic prescribed in the section immediately preceding. The third example does incorporate this logic. Although these are Java examples, they could be examples written in other languages such as Perl, PL/SQL, and CGI.

Bad Code Example #1

// Get user name from application session. This session was
// established by the application cookie or OC4J session cookie
String username = request.getSession().getAttribute('USER_NAME');

// Get subscriber name from application session. This session was
// established by the application cookie or OC4J session cookie.
String subscriber = request.getSession().getAttribute('SUBSCRIBER_NAME');

// Get user security information from application session. This session was established  by the application cookie or OC4J session cookie
String user_sec_info = request.getSession().getAttribute('USER_APP_SEC');

if((username != null) && (subscriber!= null))
{
  // Show personalized user content
  show_personalized_page(username, subscriber, user_sec_info);
}
else
{
  // Send Dynamic Directive for login
  response.sendError( 499, "Oracle SSO" );

Bad Code Example #2

// Get SSO username from http header
String username = request.getRemoteUser();

// Get subscriber name from SSO http header
String subscriber = request.getHeader('OSSO-SUBSCRIBER');

// Get user security information from application session. 
// This session was established by the application or OC4J session.
String user_sec_info =request.getSession().getAttribute('USER_APP_SEC');

if((ssousername != null)&&(subscriber!= null))
{
  // Show personalized user content
show_personalized_page(username, subscriber, user_sec_info);
}
else
{
  // Send Dynamic Directive for login
response.sendError( 499, "Oracle SSO" );
}

Recommended Code

// Get user name from application session. This session was
// established by the application or OC4J session
String username = request.getSession().getAttribute('USER_NAME');

// Get subscriber name from application session. This session was
// established by the application or OC4J session
String subscriber = request.getSession().getAttribute('SUBSCRIBER_NAME');

// Get user security information from application session.
 // This session was established by the application or OC4J session.
String user_sec_info = request.getSession().getAttribute('USER_APP_SEC');

// Get username and subscriber name from JAZN API */
JAZNUserAdaptor jaznuser  = (JAZNUserAdaptor)requset.getUserPrincipal();
     String ssousername   = jaznuser.getName();
     String ssosubscriber = jaznuser.getRealm().getName();

// If you are not using JAZN api then you can also get the username and
// subscriber name from mod_osso headers
String ssousername   = request.getRemoteUser();
String ssosubscriber = request.getHeader('OSSO-SUBSCRIBER');

// Check for application session. Create it if necessary.
if((username == null) || (subscriber == null) )
  {
   ...Code to create application session. Get the user information from 
   JAZN api (or mod_osso headers if you are not using JAZN api) and populate the
   application session with user, subscriber, and user security info.
  }

if((username != null)&&(subscriber != null)
  &&(ssousername != null)&&(ssosubscriber != null)
  &&(username.equalsIgnoreCase(ssousername) == 0 )
  &&(subscriber.equalsIgnoreCase(ssosubscriber) == 0))
{
  // Show personalized user content
show_personalized_page(username, subscriber, user_sec_info);
}
else
{
     ...Code to Wipe-out application session, followed by...

// Send Dynamic Directive for login
// If you are using JAZN then you should use following code
// response.sendError( 401);

// If you are not using JAZN api then you should use following code
// response.sendError( 499, "Oracle SSO" );
}

9.4.1.2 Application Logout: Recommended Code

Most applications that authenticate users have a logout link. In a single-sign-on-enabled application, the user invokes the dynamic directive for logout in addition to other code in the logout handler of the application. Invoking the logout directive initiates single sign-off, or global logout. The example that follows shows what single sign-off code should look like in Java:

// Clear application session, if any
String l_return_url := return url to your application
response.setHeader( "Osso-Return-Url", l_return_url);
response.sendError( 470, "Oracle SSO" );

9.4.2 Secure Transmission of mod_osso Cookies

You can add the OssoSecureCookies directive to set the Secure flag on all cookies created by mod_osso. This tells the browser to only transmit those cookies on connections secured by HTTPS.

An example of this directive, in the mod_osso configuration file located in $ORACLE_HOME/Apache/Apache/conf/mod_osso.conf, is as follows:

<IfModule mod_osso.c>
    OssoIpCheck off
    OssoIdleTimeout off
    OssoSecureCookies on
    OssoConfigFile osso/osso.conf  
    
    <Location /j2ee/webapp>
        require valid-user
        AuthType Basic
    </Location>
 
</IfModule>