IBM Skip to main content
Search for:   within 
      Search help  
     IBM home  |  Products & services  |  Support & downloads   |  My account

developerWorks > Web architecture | Java technology
developerWorks
Build and implement a single sign-on solution
83 KBe-mail it!
Contents:
Why choose single sign-on?
SSO open source projects
A brief overview of CAS
Getting started with CAS
Active Directory Server authentication
Single sign-off
Resources
About the author
Rate this article
Related content:
Using Web services for e-Commerce single sign-in
Simplify enterprise Java authentication with single sign-on
Subscriptions:
dW newsletters
dW Subscription
(CDs and downloads)
Integrate an open source, Java-based authentication component into a Web portal

Level: Introductory

Chris Dunne (mailto:chris.dunne@bigpicturesoft.com?cc=&subject=Build and implement a single sign-on solution)
Technical Director, Big Picture Software
30 September 2003

It is particularly difficult to bolt a single sign-on solution -- SSO, the ability to log in once and be authenticated to all your network resources -- onto existing applications, but every developer faces this problem when building sophisticated portals. Because portals need to integrate with back-end resources, each with its own authentication needs, the portal often has to provide the appearance of single sign-on to the user. In this article, Chris Dunne provides a step-by-step description of his experience with building a single sign-on solution for a Web portal. He shows you how to set up an open source solution, the Central Authentication Service from Yale University, and how to extend it to authenticate to a Microsoft Active Directory infrastructure.

Through my own work I have seen the growth in demand for a variety of portal applications. Portals are becoming more and more sophisticated, with complex technical and functional requirements. Even though the tools are available to build simple portals, the issues of integrating them with remote or legacy data sources are not trivial. One such issue is authentication.

Authentication is a complex problem. Portals need to authenticate users to back-end data sources and applications, yet these applications may each have different underlying security infrastructures. And the ideal and most efficient authentication solution is a single sign-on one, or SSO, in which the user only has to log in once and is authenticated to all of the network resources.

Recently, when I was asked to build an educational portal that required SSO, I researched a number of commercial and open source SSO solutions. In this article, I'll walk through a step-by-step process for implementing a simple SSO system using a freely available implementation called CAS from Yale University.

Why choose single sign-on?
How many of you have had to implement your own authentication mechanism -- usually some simple database lookup? How often have you stopped to think about the workflow needed for creating and managing user accounts? This is a common task in any development project. If you are lucky, your organization already possesses some common classes or libraries you can use. But it is often a task that is overlooked -- seen as trivial, something that occurs only in the background.

In general, a coherent authentication strategy or a solid authentication framework is missing. Over time this leads to a proliferation of applications, each of which comes with their own authentication needs and user repositories. At one time or another, everyone needs to remember multiple usernames and passwords to access different applications on a network. This poses a huge cost for the administration and support departments -- accounts must be set up in each application for each employee, users forget their passwords, and so on.

Authentication is a horizontal requirement across multiple applications, platforms, and infrastructures. In general, there's no reason why user Mary should need multiple usernames. Ideally she should only need to identify herself once and then be provided with access to all authorized network resources.

The objective of SSO is to allow users access to all applications from one logon. It provides a unified mechanism to manage the authentication of users and implement business rules determining user access to applications and data.

Before I get into the technical details of single sign-on, take a quick look at some of the benefits and some of the risks. Benefits include the following:

  • Improved user productivity. Users are no longer bogged down by multiple logins and they are not required to remember multiple IDs and passwords. Also, support personnel answer fewer requests to reset forgotten passwords.

  • Improved developer productivity. SSO provides developers with a common authentication framework. In fact, if the SSO mechanism is independent, then developers don't have to worry about authentication at all. They can assume that once a request for an application is accompanied by a username, then authentication has already taken place.

  • Simplified administration. When applications participate in a single sign-on protocol, the administration burden of managing user accounts is simplified. The degree of simplification depends on the applications since SSO only deals with authentication. So, applications may still require user-specific attributes (such as access privileges) to be set up.

Some of the more frequently mentioned problems with single sign-on include the following:

  • Difficult to retrofit. An SSO solution can be difficult, time-consuming, and expensive to retrofit to existing applications.

  • Unattended desktop. Implementing SSO reduces some security risks, but increases others. For example, a malicious user could gain access to a user's resources if the user walks away from his machine and leaves it logged in. Although this is a problem with security in general, it is worse with SSO because all authorized resources are compromised. At least with multiple logons, the user may only be logged into one system at the time and so only one resource is compromised.

  • Single point of attack. With single sign-on, a single, central authentication service is used by all applications. This is an attractive target for hackers who may decide to carry out a denial of service attack.

So, SSO is not without its disadvantages, but I believe the advantages from a viewpoint of users, administrators, and developers can outweigh those disadvantages.

SSO open source projects
As I mentioned in the introduction, I am currently building a Web portal for an educational institution. This portal will provide an online learning environment for students enrolled in distance-education courses.

The building blocks of the portal are already in place. The site exists, course content has been developed, a virtual learning environment is in place, and productivity applications (such as diaries, calendars, email, and notebooks) have been built or acquired. All of these components are already in use by full-time students and each application runs on its own server.

The client now wants to enable remote access to these applications through a Web browser, so a portal is being built to provide a single point of entry to the applications and it is intended to provide users with single sign-on. Once the user logs into the portal, his login is authenticated and then he is given access to all other authorized resources available in the portal.

I decided to search for information on how to implement a SSO scheme, looking for useful white papers, products, and open source initiatives. I used the following criteria to narrow my search:

  • Java implementation. The portal application infrastructure is a Java-based one. I needed a compatible implementation based on a language we could work with.
  • Easy to implement. Easy in the sense that it would not require extensive modification to the infrastructure or existing applications.
  • A proven track record. It should be currently in use in large organizations as well as being actively developed.
  • LDAP-compatible. Our customer uses Microsoft Active Directory Server, so I needed a system that could easily authenticate a user against ADS.

I was pleasantly surprised to find several well-established open source initiatives. (See Resources for a list.)

I began to develop a prototype using the CAS, or Central Authentication Service, system from Yale University because it fit all of my criteria. It is Java-based and the source code is available. It can be implemented in Java application environments with relative ease through the use of JSP tags and servlet filters. It is in use at Yale University, so that indicates a sufficient level of quality and testing to satisfy my criteria. It is also built in such a way that the actual authentication mechanism, whether it is a lookup of a username and password in a database or LDAP server, can be easily changed or extended.

A brief overview of CAS
Note that in the CAS protocol, your application never sees the user's password. The CAS server performs the authentication and only it sees the user's password. This increases overall security since the username and password are not passed across the network to other applications.

The following figure demonstrates the authentication flow path of a system that has a CAS server integrated.

Figure 1. How the CAS protocol performs authentication
How the CAS protocol performs authentication

The following are the main steps in the authentication protocol.

  1. The user attempts to access an application using its URL. The user is redirected to the CAS login URL over an HTTPS connection, passing the name of the requested service as a parameter. The user is presented with a username/password dialog box.
  2. The user enters ID and password details and CAS attempts to authenticate the user. If authentication fails, the target application never hears about it -- the user remains at the CAS server.
  3. If authentication succeeds, then CAS redirects the user back to the target application, appending a parameter called a ticket to the URL. CAS then attempts to create an in-memory cookie called a ticket-granting cookie. This is done to allow for automatic re-authentication later -- if present, then it indicates that the user has already successfully logged in and the user avoids having to re-enter his username and password.
  4. The application then validates that this is a correct ticket and represents a valid user by calling the CAS serviceValidate URL by opening an HTTPS connection and passing the ticket and service name as parameters. CAS checks that the supplied ticket is valid and is associated with the requested service. If validation is successful, CAS returns the username to the application.

If you are programming to the Servlet 2.3 specification, you don't even have to do any of these steps. A servlet filter handles the entire protocol. All you have to do is to configure the filter parameters in the web.xml file. That's the approach I will take -- it means less changes to the application code in the portal.

An in-depth discussion of CAS is not within the scope of this article, so I encourage you to look in Resources for the articles from Yale University to determine if this is an authentication scheme that might suit your own purposes.

Getting started with CAS
Setting up the CAS software is straightforward, but before beginning you should be aware of some software parameters that I'm using. I have only tested CAS with Tomcat 4.1, the Java Development Kit 1.4, and Ant 1.5. (You can download the files and client libraries mentioned from Resources.)

First, download the CAS server and client libraries. Client libraries have been developed for a number of languages and environments, including Java, ASP, Perl, PHP, and PL/SQL.

CAS uses HTTPS, so you must enable this in Tomcat. I found this to be a bit tricky, but if you follow the set of downloadable instructions (the readme_tomcat_ssl.txt file) I've provided, it should work fine.

Expand the CAS server ZIP file and then build the CAS server software using the supplied Ant build script. Deploy the WAR file (Web Archives) to the /webapps directory in Tomcat. When you start Tomcat, explode your WAR file to create a CAS directory within Tomcat/webapps.

Download the CAS client libraries. Expand the ZIP file and you will see a number of directories. The Java client library is the one to use. Again, an Ant build script is provided. Run the build script. A JAR file called casclient.jar is produced. Copy this file to common/lib directory under the Tomcat root.

You now need to configure your application to use CAS. For the purposes of this experiment, the application is the tried and trusted "HelloWorld" sample servlet provided with Tomcat. This should already be in your Tomcat installation under the /webapps/examples directory. Change the web.xml file to configure the servlet filter.

The web.xml file for the HelloWorld JSP contains the following servlet filter configuration. This uses localhost and port 8443 for HTTPS. You can change these to suit your own configuration. An example web.xml file is included in the zip file I've provided.

Listing 1. Default servlet filter configuration for HelloWorld JSP

<filter>
    <filter-name>CAS Filter</filter-name>
    <filter-class>edu.yale.its.tp.cas.client.filter.CASFilter</filter-class>
    <init-param>
      <param-name>edu.yale.its.tp.cas.client.filter.loginUrl</param-name>
      <param-value>https://localhost:8443/cas/login</param-value>
    </init-param>
    <init-param>
      <param-name>edu.yale.its.tp.cas.client.filter.validateUrl</param-name>
      <param-value>https://localhost:8443/cas/proxyValidate</param-value>
    </init-param>
    <init-param>
      <param-name>edu.yale.its.tp.cas.client.filter.serverName</param-name>
      <param-value>localhost</param-value>
    </init-param>
  </filter>

  <filter-mapping>
    <filter-name>CAS Filter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

Start Tomcat. Then enter the URL http://localhost/examples/servlet/HelloWorldExample. You are redirected to the CAS login screen. The default authenticator simply requires you to enter the same string for both the username and password, for example demo in both fields. You are then redirected to the HelloWorld page.

This is a simple demonstration of CAS, but it does show how easy it can be to adapt existing Java servlet applications to use CAS by using this powerful servlet filter. You can also use the available set of JSP tags instead of the servlet filter -- this may suit other applications or application servers which cannot use servlet filters.

Active Directory Server authentication
In my educational portal project, the applications can be easily modified because the source code is available. I have used the servlet filter for each of these applications. In this case, CAS will perform the authentication when the user first visits the portal and requests a restricted application or data source. Once authentication is successful, the CAS servlet filter can validate the ticket and pass the username as a parameter to the requested application. I have modified the existing application login screens to accept the username parameter from CAS after a successful authentication. The applications can then use this parameter to authorize users and provide an audit trail of user activity.

Unfortunately, CAS does not come with any truly useful authenticators. The default authenticator simply verifies that the username and password are identical. In the educational portal project I use Microsoft's Active Directory Server to store the user profiles. So I needed to extend the CAS server to authenticate the username and password against the Active Directory Server.

The creators of CAS at Yale University have developed a pluggable authenticator architecture. By extending the PasswordHandler interface, a developer can create a class to implement the password-checking logic.

Listing 2. CAS's pluggable authenticator architecture

/** Interface for password-based authentication handlers. */
public interface PasswordHandler extends AuthHandler {

  /**
   * Authenticates the given username/password pair, returning true
   * on success and false on failure.
   */
  boolean authenticate(javax.servlet.ServletRequest request,
                       String username,
                       String password);

}

All I had to do was find out how to check the username and password using Active Directory Server, create a class to extend this interface, and add the code to perform the authentication.

ADS is an LDAP3-compliant directory server. It supports a number of different authentication methods, the principal ones being anonymous, simple, and SASL (Simple Authentication and Security Layer). Anonymous authentication is of no use in this instance; simple authentication sends the password as cleartext, again not suitable for these needs. So SASL is the option I will use.

SASL supports pluggable authentication. This means that you can configure the LDAP client and server to negotiate and use any of a range of mechanisms. The following are some of the currently defined SASL mechanisms:

  • Anonymous
  • CRAM-MD5
  • Digest-MD5
  • External
  • Kerberos V4
  • Kerberos V5
  • SecurID
  • Secure Remote Password
  • S/Key
  • X.509

Of these mechanisms, popular LDAP servers (such as those from Sun, OpenLDAP, and Microsoft) support External, Digest-MD5, and Kerberos V5.

CAS itself is Kerberos-like, sharing many of the same concepts such as tickets, ticket-granting tickets (actually called ticket-granting cookies in CAS), and a similar protocol. So choosing this mechanism felt like a natural fit. Also adding support for Kerberos authentication will enable CAS, in a future development, to act as a Web-based Kerberos agent on behalf of the user, allowing CAS to manage all aspects of Kerberos tickets for its users. This would mean that the same Kerberos authentication mechanisms used to access local and network resources could also be used by remote users.

The Kerberos protocol is already built into ADS and Windows 2000/XP. The Java Authentication and Authorization Service (JAAS) provides an implementation of a Kerberos Login Module (see Resources for the tutorial that provides detail on how to get a sample application running). To be precise, it is GSS-API SASL mechanism that you will use, but this only supports Kerberos v5 authentication to LDAP3 servers.

Kerberos authentication is a straightforward process (assuming you follow the instructions carefully):

  1. Configure the Login Module for your application class in your JAAS configuration file.
    
    edu.yale.its.tp.cas.auth.provider.KerberosAuthHandler  
    {
    com.sun.security.auth.module.Krb5LoginModule required client=TRUE;
    };
    
  2. Create a LoginContext, passing the name of the class doing the authentication, and a CallBackHandler object.
    
    LoginContext lc = new LoginContext(CASApp.class.getName(), 
                        new CASCallbackHandler());
    
  3. Call the login() method to perform the authentication. If this executes without exceptions, then authentication is successful. If an exception is thrown, then the exception indicates the cause of the failure.

For a more in-depth look at Kerberos authentication, I suggest you use the resources at the end of the article. (I've also provided a download of my implementation and configuration files, KerberosAuthHandler and CASCallBackHandler.)

You need to create a new PasswordHandler implementation, the KerberosAuthHandler, which uses the above methods to authenticate against the Active Directory Server using Kerberos v5.

Listing 3. Creating the new PasswordHandler implementation

public class KerberosAuthHandler implements PasswordHandler {

  public boolean authenticate(javax.servlet.ServletRequest request,
                                String username,
                                String password) 
  {

    LoginContext lc = null;
  
    try 
    {
  /* Set up the Callback handler, and initialise */
 /* the userid and password fields */

     CASCallbackHandler ch = new CASCallbackHandler();
     ch.setUserId(username);
       ch.setPassword(password);
    
     /* Initialise the login context - LoginModule configured */
     /* in cas_jaas.conf and */
              /* set to use Krb5LoginModule. */
     lc = new LoginContext(KerberosAuthHandler.class.getName(), ch);

     /* Perform the authentication */
     lc.login();

    } 
    catch (LoginException le) 
    {
     System.err.println("Authentication attempt failed" + le);
     return false;
    }
    return true;

  }
}

When the LoginContext is created, I pass the classname and the CASCallbackHandler object. The JAAS configuration file specifies the login module to use for this class.

When the login() method is called, the login module knows what information it needs from the user/application in order to authenticate them. In the case of Kerberos, it needs a username and password, so it constructs an array of two callback objects (NameCallback and PasswordCallback) and then calls the CallbackHandler object, which decides how it should perform these callbacks and retrieve the username and password.

I have taken the simplest and most expedient route and explicitly set the user ID and password using setter methods on the CallbackHandler. Then the CallbackHandler simply passes these on to the NameCallback and PasswordCallback objects.

Listing 4. Setting ID and password with setName (CASUserId) and setPassword (CASPassword)

public class CASCallbackHandler implements CallbackHandler 
{

    private String CASUserId;
    private char [] CASPassword;

    public void handle(Callback[] callbacks) 
  throws java.io.IOException, UnsupportedCallbackException {
      for (int i = 0; i < callbacks.length; i++) {
    if (callbacks[i] instanceof NameCallback) {
        NameCallback cb = (NameCallback)callbacks[i];
        cb.setName(CASUserId);

    } else if (callbacks[i] instanceof PasswordCallback) {
        PasswordCallback cb = (PasswordCallback)callbacks[i];
        cb.setPassword(CASPassword);

    } else {
        throw new UnsupportedCallbackException(callbacks[i]);
    }
      }
    }

    public void setUserId(String userid)
    {
  CASUserId = userid;
    }

    public void setPassword(String password)
    {
  CASPassword = new char[password.length()];
  password.getChars(0, CASPassword.length, CASPassword, 0);
    }

The next thing to do is tell CAS to use the new authentication handler. Do this by setting the following in the web.xml file for the CAS server in webapps/cas:

Listing 5. Telling CAS to use the new authentication handler

<!-- Authentication handler -->
    <context-param>
        <param-name>edu.yale.its.tp.cas.authHandler</param-name>
        <param-value>
             edu.yale.its.tp.cas.auth.provider.KerberosAuthHandler
        </param-value>
    </context-param>

An example web.xml is included in the ZIP file (KerberosAuthSrc.zip in Resources).

You'll have to restart Tomcat, but this time you'll also need to set some Java runtime properties . Expand the ZIP file (KerberosAuthSrc.zip) and copy the files cas_jaas.conf, krb5.conf, and setkerberosjvmoptions.bat to the TOMCAT_HOME directory. Run the setkerberosjvmoptions.bat and then start Tomcat.

Now you are ready to repeat the HelloWorld experiment. This time you can use a valid Kerberos username and password pair as defined in your Active Directory Server.

Single sign-off
Without a unified strategy, developers re-implement custom security for each network application. This can result in a variety of scalability and maintenance problems. Single sign-on solutions can be that unified framework for security and authentication, alleviating much of the burden on users, administrators, and developers.

The concept of single sign-on, the technologies, and the implications for users and administrators are complex, so I have only scratched the surface in this article. But I have provided you with some practical ways to implement a single sign-on scheme using the proven CAS application from Yale University, and have also detailed a method to extend this technology so you can use it to authenticate users to a LDAP server (specifically, to an Active Directory Server using the Kerberos protocol).

Resources

About the author
Chris Dunne lives and works in Dublin, Ireland. He was co-founder of Kadius, a company which developed J2EE content-management technology, and is now a technical director of Big Picture Software where he is involved in the development portals, content management, and e-marketing products. He graduated from Dublin City University with a MSc in Computer Applications and has been an active developer for 10 years.


83 KBe-mail it!

What do you think of this document?
Killer! (5) Good stuff (4) So-so; not bad (3) Needs work (2) Lame! (1)

Comments?



developerWorks > Web architecture | Java technology
developerWorks
  About IBM  |  Privacy  |  Terms of use  |  Contact