Sun Java Solaris Communities My SDN Account Join SDN

Article

Integrating Applications With OpenSSO

 
By Tatsuo Kudo, with contributions from Aravindan Ranganathan and Marina Sum, August 26, 2008  

OpenSSO, Sun's open Web access management project, is based on the code base of Sun Java System Access Manager, a core identity-infrastructure software product. This article starts with a description of the four ways in which you can integrate Web applications with OpenSSO. You then learn how to secure the login process with OpenSSO's identity-service interfaces in a Ruby on Rails (henceforth, Rails) sample application.

Contents
 
Architecture
Authentication With Identity Services
Demonstration
Conclusion
References
 
Architecture

In an OpenSSO deployment, you manage Web access and single sign-on (SSO) with a string named token, which travels through the Web browser, the related Web applications, and the OpenSSO instance. See Figure 1.

Figure 1: Login Process in OpenSSO
 

token is a handle that contains the information of the login session in the OpenSSO instance. When a user attempts to log in through the browser, this process takes place:

  1. OpenSSO sends token as a cookie to the browser.

  2. The browser presents token as the value of a cookie to the application.

  3. The application extracts and sends token along with a query to OpenSSO for the user's authentication or authorization status, the user attributes, and so forth. OpenSSO responds to the application with that information—for example, the authentication scheme, the resources the user can access, and the user's ID and full name. The application in turn sends that information to the browser.

  4. The browser again presents token as the value of a cookie to the application.

  5. The application allows user access, taking into account the specifics relayed by OpenSSO in step 3.

The application can process token in one of four ways: through the Policy Agent, the reverse proxy, the client SDK, or identity services. Read on for the details.

Policy Agent
The Policy Agent offers a basic scheme for managing Web access in OpenSSO. As a first step, you install the Policy Agent in the application's runtime environment, such as a Web server or an application server. Figure 2 illustrates the process flow.

Figure 2: Process Flow of Web Access Management Through the Policy Agent
 

When a browser attempts to connect to the application, the Policy Agent checks whether the request contains token. Either of these scenarios then follows:

  • If the answer is yes, the Policy Agent queries OpenSSO for the information on authentication, authorization, and so forth, and then allows or denies the user access.

  • If the answer is no, the Policy Agent redirects the browser to an OpenSSO login page for the user to log in.

Although Policy Agents are available for specific Web servers and application servers, those agents require no additional programming for token handling and access control. If no Policy Agents are available for the application's runtime environment, you can integrate the application into OpenSSO by means of identity services instead. More details later in this article.

Reverse Proxy
For a reverse proxy, install the Policy Agent on a reverse proxy server and place the Policy Agent in front of the Web server or application server in which the application is deployed. Figure 3 illustrates the process flow.

Figure 3: Process Flow of Web Access Management Through the Reverse Proxy
 

Since the reverse proxy server must relay all the browser requests to the application, a bottleneck—throughput degradation—might result in the case of a large number of requests. Nonetheless, an advantage of the reverse-proxy scheme is that you need not install any Policy Agents on a Web server or application server.

Client SDK
You can explicitly control communications between the application and OpenSSO through OpenSSO's client SDK (openssoclientsdk.jar) in the application. Figure 4 illustrates the process flow.

Figure 4: Process Flow of Web Access Management Through the Java Client SDK
 

Even though the client SDK is available on the Java platform only, you can build more sophisticated access control for your applications through the SDK than through the Policy Agent or the reverse proxy.

Identity Services
Recall that OpenSSO's identity services are simple Web interfaces that enable applications to take advantage of many of the OpenSSO capabilities, such as authentication and authorization. Even though integrating identity services into applications requires programming, you save many steps in not having to tackle any other components, such as the Policy Agent, the reverse proxy, and the client SDK. Figure 5 illustrates the process flow.

Figure 5: Process Flow of Web Access Management Through Identity Services
 

Through an example, the next section describes how to authenticate users for a Web application with identity services.

Authentication With Identity Services

Authenticating users with identity services involves three basic tasks.

Resolution of Cookie Name for token
An identity-service operation retrieves the name of the cookie that contains the string token. The URL in question is http://hostname:portnumber/opensso/identity/getCookieNameForToken. The following example shows the OpenSSO response with iPlanetDirectoryPro, the configurable default name of the cookie.

Note: The boldfaced lines in the code examples that follow denote your input.

$ telnet opensolaris.example.com 8080
Trying 127.0.0.1...
Connected to opensolaris.
Escape character is '^]'.
POST /opensso/identity/getCookieNameForToken HTTP/1.1
Host: opensolaris.example.com
Content-Length: 0
Content-Type: application/x-www-form-urlencoded [Press Enter twice.]

HTTP/1.1 200 OK
X-Powered-By: Servlet/2.5
Server: Sun Java System Application Server 9.1_02
Content-Type: text/plain;charset=ISO-8859-1
Content-Length: 27
Date: Mon, 09 Jun 2008 11:31:33 GMT

string=iPlanetDirectoryPro
Connection to opensolaris closed by foreign host.
$
 

Validation of token
Another identity-service operation validates token. The URL in question is http://hostname:portnumber/opensso/identity/isTokenValid. If the return value is true, token is valid; if the return value is false, token is invalid.

The following example shows an OpenSSO response of true in reply to an application request.

$ telnet opensolaris.example.com 8080
Trying 127.0.0.1...
Connected to opensolaris.
Escape character is '^]'.
POST /opensso/identity/isTokenValid HTTP/1.1
Host: opensolaris.example.com
Content-Length: 0
Content-Type: application/x-www-form-urlencoded
Cookie: iPlanetDirectoryPro=AQIC5wM2LY4Sfcw/i16QyLit+Ttax4/HXZEB6eCtRHppz0M=@AAJTSQACMDE=# [Press Enter twice.]

HTTP/1.1 200 OK
X-Powered-By: Servlet/2.5
Server: Sun Java System Application Server 9.1_02
Content-Type: text/plain;charset=ISO-8859-1
Content-Length: 13
Date: Mon, 09 Jun 2008 11:38:20 GMT

boolean=true
Connection to opensolaris closed by foreign host.
$
 

Retrieval of User Attributes
Yet another identity-service operation retrieves the attributes of the user, as represented by token. The URL in question is http://hostname:portnumber/opensso/identity/attributes. An attribute name is the value of userdetails.attribute.name, which can have zero or multiple values, as reflected in userdetails.attribute.value.

The following example shows an OpenSSO response, again in reply to an application request that contains token as a cookie. This response contains a user's attributes: a name called uid with a value of demo.

$ telnet opensolaris.example.com 8080
Trying 127.0.0.1...
Connected to opensolaris.
Escape character is '^]'.
POST /opensso/identity/attributes HTTP/1.1
Host: opensolaris.example.com
Content-Length: 0
Content-Type: application/x-www-form-urlencoded
Cookie: iPlanetDirectoryPro=AQIC5wM2LY4Sfcw/i16QyLit+Ttax4/HXZEB6eCtRHppz0M=@AAJTSQACMDE=# [Press Enter twice.]

HTTP/1.1 200 OK
X-Powered-By: Servlet/2.5
Server: Sun Java System Application Server 9.1_02
Content-Type: text/plain;charset=ISO-8859-1
Content-Length: 972
Date: Mon, 09 Jun 2008 11:46:10 GMT

userdetails.token.id=AQIC5wM2LY4Sfcw/i16QyLit+Ttax4/HXZEB6eCtRHppz0M=@AAJTSQACMDE=#
userdetails.attribute.name=uid
userdetails.attribute.value=demo
userdetails.attribute.name=sn
userdetails.attribute.value=demo
userdetails.attribute.name=userpassword
userdetails.attribute.value={SSHA}an+ilaB+RX0HIZkebtapdJS1alUEGY11uHSrXg==
userdetails.attribute.name=cn
userdetails.attribute.value=demo
userdetails.attribute.name=inetuserstatus
userdetails.attribute.value=Active
userdetails.attribute.name=objectclass
userdetails.attribute.value=organizationalPerson
userdetails.attribute.value=person
userdetails.attribute.value=sunIdentityServerLibertyPPService
userdetails.attribute.value=inetorgperson
userdetails.attribute.value=sunFederationManagerDataStore
userdetails.attribute.value=iPlanetPreferences
userdetails.attribute.value=iplanet-am-user-service
userdetails.attribute.value=sunFMSAML2NameIdentifier
userdetails.attribute.value=inetuser
userdetails.attribute.value=top
Connection to opensolaris closed by foreign host.
$
 

Process Scenario
Figure 6 illustrates the preceding three operations in a Web application.

Figure 6: User Authentication in Applications With Identity Services
 

The process flow is as follows:

  1. The application calls getCookieNameForToken for the name of the cookie that will retrieve token from the browser's request later.

  2. The application accepts the browser request and attempts to connect to a protected resource, for example, a Web page or business logic.

  3. The application attempts to extract token from the browser request.

    • If token exists, the application proceeds to step 4.

    • If token does not exist, the application redirects the browser to OpenSSO's login page for the user to log in. Once login is successful, OpenSSO sends a valid token to the browser and redirects the user to the application.

  4. The application calls isTokenValid to check the validity of token.

    • If token is valid, the application retrieves the user attributes through the attributes service and allows the user access.

    • If token is invalid, the application denies access or redirects the browser to OpenSSO's login page for the user to log in.
Demonstration

As an example, this section shows you how to secure the login process of a Rails application with identity services. Note that this example is a proof of concept only. Other customizations might be necessary for other applications.

Environment
Our sample application, which was developed with Ruby on Rails 2.1, Ruby 1.8.6, and the MySQL 5.0.45 database, runs on the Firefox 3.0 RC 2 browser on the OpenSolaris 2008.05 OS. The related OpenSSO build is 20080531.1, which supports the GlassFish V2 UR2 Multilingual and JDK 6, Update 4 releases. The latest OpenSSO build, V1 Build 5, also works.

Figure 7 illustrates the environment.

Figure 7: Environment of Sample Application
 

Integration With OpenSSO
Figure 8 illustrates the application's integration with OpenSSO.

Figure 8: Integration of Sample Application With OpenSSO
 

Here is the process flow:

  1. The user connects to the application's front page at http://opensolaris.example.com:3000/products. To register a new product, the user clicks "New product," which points to http://opensolaris.example.com:3000/products/new.

  2. The application redirects the browser—along with the user behind it—to OpenSSO's login page.

  3. The user types the credentials—demo in the User Name text field and changeit in the Password text field—and clicks Login. Afterwards, OpenSSO redirects the browser and the user to the registration page for new products.

Customization
You perform two tasks to customize the application.

Specifying the Protected Operations
First, specify the operations that are to be protected by adding a before_filter statement to the ProductsController class, as follows:

1 class ProductsController < ApplicationController
2   before_filter :check_authentication, :only => [ :new ]
...
26   # GET /products/new
27   # GET /products/new.xml
28   def new
29     @product = Product.new
30
31     respond_to do |format|
32       format.html # new.html.erb
33       format.xml { render :xml => @product }
34     end
35   end
 

Subsequently, when the browser attempts to connect to http://opensolaris.example.com:3000/products/new, which is a protected page, the application invokes the check_authentication method.

Defining the Methods for Collaboration With OpenSSO
Next, to take advantage of OpenSSO's identity services, add a few code segments to ApplicationController, the parent class of ProductsController in the application.

check_authentication (Lines 20-39)
The application invokes check_authentication after calling new, the protected method.

20 def check_authentication
21   @opensso_uri = URI.parse(opensso_location)
22   @http = Net::HTTP.new(@opensso_uri.host, @opensso_uri.port)
23
24   token_cookie_name = get_cookie_name_for_token
25   token_cookie = get_token_cookie(token_cookie_name)
26
27   redirect_to_opensso and return unless validate_token(token_cookie)
28
29   opensso_user = get_opensso_user(token_cookie)
30
31   opensso_user.keys.each do |n|
32     p ' key: ' + n
33     opensso_user[n].each do |m|
34     p ' value: ' + m
35   end
36 end
37
38     p 'User ID is: ' + opensso_user['uid'].at(0) if opensso_user.has_key?('uid')
39 end
 

The preceding code segment performs four tasks:

  1. Sets up the connection to OpenSSO (lines 21-22).

  2. Resolves the cookie name for token (line 24).

  3. Validates the status of token. In case of an invalid status, redirects the user to OpenSSO (line 27).

  4. Retrieves the user attributes (line 29).

get_cookie_name_for_token (Lines 42-47)
get_cookie_name_for_token queries OpenSSO's getCookieNameForToken service and then retrieves and returns the cookie name for token.

42 def get_cookie_name_for_token
43   req = Net::HTTP::Post.new(@opensso_uri.path +
44     '/identity/getCookieNameForToken')
45   res = @http.request(req, '')
46   res.body.split('=').at(1).chomp
47 end
 

get_token_cookie (Lines 49-54)
get_token_cookie extracts and returns token from the cookie in the browser request, with the token_cookie_name parameter specifying the cookie name. If token does not exist, get_token_cookie returns nil.

49 def get_token_cookie(token_cookie_name)
50   token_cookie =
51   CGI.unescape(request.cookies.fetch(token_cookie_name, nil).
52     to_s.gsub('+', '%2B'))
53       token_cookie != '' ? token_cookie : nil
54 end
 

validate_token (Lines 56-64)
validate_token queries OpenSSO's isTokenValid service with token as a cookie. If OpenSSO responds that token is valid, validate_token returns true.

56 def validate_token(token_cookie)
57   return unless token_cookie != nil
58
59   req = Net::HTTP::Post.new(@opensso_uri.path +
60     '/identity/isTokenValid')
61   req['Cookie'] = token_cookie
62   res = @http.request(req, '')
63   res.body.split('=').at(1).chomp == 'true'
64 end
 

redirect_to_opensso (Lines 66-69)
redirect_to_opensso redirects the browser to OpenSSO's login page with a goto parameter that specifies the URL to which the browser attempted to connect before. If login is successful, OpenSSO sets up token as a cookie for and redirects the browser to the URL specified by goto.

66 def redirect_to_opensso
67   redirect_to opensso_location + '/UI/Login?goto=' +
68     url_for({:only_path => false})
69 end
 

get_opensso_user (Lines 71-95)
get_opensso_user queries OpenSSO's attributes service with token as a cookie. If token is valid, OpenSSO returns the user attributes, which get_opensso_user then stores into a hash of arrays and returns.

71 def get_opensso_user(token_cookie)
72   return unless token_cookie != nil
73
74   opensso_user = Hash[]
75   attribute_name = ''
76
77   req = Net::HTTP::Post.new(@opensso_uri.path +
78     '/identity/attributes')
79   req['Cookie'] = token_cookie
80   res = @http.request(req, '')
81
82   lines = res.body.split(/\n/)
83
84   lines.each do |line|
85     if line.match(/^userdetails.attribute.name=/)
86       attribute_name = line.gsub(/^userdetails.attribute.name=/, '')
87       opensso_user[attribute_name] = Array.new
88     elsif line.match(/^userdetails.attribute.value=/)
89       opensso_user[attribute_name] << line.gsub(/^userdetails.attribute.value=/, '')
90     end
91   end
92
93   return opensso_user
94   end
95 end
 

Access to a Protected Page
Finally, go to the application's front page at http://opensolaris.example.com:3000/products and click "New product." On the page that's displayed are the user attributes, including the user ID, from the Web server WEBrick's log output, as follows.

" key: cn"
"   value: demo"
" key: objectclass"
"   value: organizationalPerson"
"   value: person"
"   value: sunIdentityServerLibertyPPService"
"   value: inetorgperson"
"   value: sunFederationManagerDataStore"
"   value: iPlanetPreferences"
"   value: iplanet-am-user-service"
"   value: sunFMSAML2NameIdentifier"
"   value: inetuser"
"   value: top"
" key: sn"
"   value: demo"
" key: uid"
"   value: demo"
" key: inetuserstatus"
"   value: Active"
" key: userpassword"
"   value: {SSHA}an+ilaB+RX0HIZkebtapdJS1alUEGY11uHSrXg=="
"User ID is: demo"
 

Lines 31-18 in the code segment in the section "check_authentication (Lines 20-39)" generated the preceding information.

Conclusion

OpenSSO offers a host of scalable and flexible access management and SSO capabilities, including log management, policy management, Security Assertion Markup Language (SAML) service provider, multifactor authentication, all ready for integration into applications. In particular, integration with OpenSSO's identity services works well in the broader application runtime environment—independent of Policy Agents, the reverse proxy, and non-Java applications that are developed with scripting languages like Rails, Perl, and PHP. Do consider OpenSSO as a viable and robust solution for securing your applications.

Sun recently announced commercial support for OpenSSO. For details, see the announcement and read a related interview.

References that pertain to identity services are in the Liferay-OpenSSO wiki, which points to many valuable resources. In addition, the two source files for OpenSSOFilter.java and OpenSSOUtil.java are well worth a glance.

References
Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
Your email address (no reply is possible without an address):
Sun Privacy Policy

Note: We are not able to respond to all submitted comments.
Tatsuo KudoTatsuo Kudo, a solutions architect at Sun Japan, has been in a business-development role for identity management since 2006. Before assuming that position, he was a systems engineer who specialized in Sun middleware—identity management, PKI, XML messaging, Web server, application server—for eight years. Tatsuo blogs in Japanese on identity management and publishes extensively both in magazines and on the Web on topics that range from internal control to OpenID. He's also a frequent guest speaker at seminars and conferences, such as those held by ISACA's Tokyo Chapter and The Liberty Alliance's Japan SIG.
 
Aravindan RanganathanAravindan Ranganathan, a software architect at Sun, is currently designing identity services for SOA. Previously, he developed solutions for securing Web-service communications and for implementing SSO within and across enterprises. Aravindan has also actively participated in standards bodies, such as the Liberty Alliance Project in defining the Identity Federation Framework (ID-FF); and OASIS Technical Committees in developing SAML, XACML, and SPML specifications.
 
Marina SumMarina Sum is a staff writer for Sun Developer Network. She has been writing for Sun since 1989, mostly in the technical arena. Marina blogs on Sun's products, technologies, events, publications, and unsung heroes.