Oracle® Identity Management Application Developer's Guide
10g Release 2 (10.1.2) B14087-02 |
|
Previous |
Next |
This chapter explains how to develop applications to work with mod_osso. The chapter contains the following topics:
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:
User name
User GUID
Language and territory
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
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.
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:
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
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.
This section explains how to write and enable applications using mod_osso. The section contains the following topics:
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.
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;
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;
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>
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. |
Restart the Oracle HTTP Server:
http://host:port/private/helloworld.html
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.
Use the following steps to write and enable a servlet or JSP application using mod_osso:
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>");
Protect the servlet by entering the following lines in the mod_osso.conf
file:
<Location /servlet> require valid-user authType Basic </Location>
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.
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
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.
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
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 code401 may be substituted for 499 .
|
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 theosso_logout URL on that computer.
|
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"); } } }
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.
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 }
This section describes security considerations when developing applications for OracleAS Single Sign-On. It contains these topics:
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:
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" ); }
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" );
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>