|
|
|
Contents: |
|
|
|
Related content: |
|
|
|
Subscriptions: |
|
|
| Integrate an open source, Java-based authentication
component into a Web portal
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
The following are the main steps in the authentication protocol.
- 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.
- 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.
- 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.
- 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):
- 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;
};
|
- 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());
|
- 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
- Download the CAS server and client
libraries used in this article.
- Download the Tomcat web.xml for CAS
used in this article, including instructions for setting up SSL.
- Download the
KerberosAuthHandler
and CASCallBackHandler code used in this
article.
- Learn about "Using CAS at Yale: A Quick
Introduction." This article details the components of CAS, explains
when to use it, and shows the easiest way to use it to authenticate
users.
- Check out "CAS 2.0: Proxiable
Credentials" for the reasons for the upgrade plus the new and
improved features of the system.
- Read "Using Web services for
e-Commerce single sign-in" (developerWorks,
January 2002) for more on how to integrate an electronic Customer
Relationship Management (eCRM) application into an existing e-Commerce
marketplace application to provide a single-sign-in experience for the
user.
- Discover how to implement SSO on the Java platform using GSS-API and
Kerberos standards to handle the security issues in the article, "Simplify enterprise Java
authentication with single sign-on" (developerWorks,
September 2003).
- Get the details on Lightweight Third Party Authentication (LTPA), a
way for servers to delegate single sign-on authentication to a common
third-party service, from "WebSphere and Domino
single sign-on" (developerWorks,
January 2001).
- Take the "Java security, Part 2:
Authentication and authorization" tutorial (developerWorks, July
2002) for an introduction to the basic concepts of authentication and
authorization and an architectural overview of JAAS.
- Visit the ITS Central Authentication
Service site for an explanation of the thought that went into the
design and implementation of CAS 1.0.
- Check out Tips for LDAP Users
site for how to use different security authentication mechanisms and SSL
(Secure Socket Layer) to access the LDAP service.
- Visit the Security Guide, Kerberos
chapter for information on understanding the secure remote commands,
authenticating to AIX using Kerberos, and a Q&A on troubleshooting
Kerberos.
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. |
|
|