CAS+: Single Sign-On with Jifty (Part 1)

Single sign-on (SSO) means that one user ID and one password are entered one time to allow passage from one system to another without interruption. [1] In the realm of web development, this means you can log in on one site and then use the same credentials while moving from one domain to the next. This gets interesting because neither cookies nor JavaScript are allowed to directly share such information across domains. This means that the web applications must perform a little extra footwork to get this communication done. You also need to be concerned that you aren't giving too much information away too easily, so it's also important to allow the user to have a say in the matter during these transactions.

My employer, Boomer Consulting, is building a number of web-based tools to be used by our clients. These tools are being built on different platforms. For example, our main web site, two client service sites, and a support site will be running separate installations of Drupal. Meanwhile, we're also building some custom tools to aid our consultants and clients in Jifty. We also use other tools such as Best PracticalRT for issue tracking and client correspondence. Eventually, as our services expand, we will want to integrate our e-commerce platform and possibly even support third-party applications with business partners. All of these require some amount of authentication. We don't want our clients (or our own staff) to log in every time they move from one site to the next. Login is tedious, and remembering multiple passwords is not an efficient use of our brains. By implementing SSO, we can use a single login page to grant access to every affiliated site. That way, our clients don't really need to be aware that they are moving from one platform to another. It makes for a more seamless user experience.

Once you know the general technique, it's actually pretty easy to implement a client-server single sign-on architecture. However, there are several existing SSO solutions out there for web development. One of the most popular such protocols is the Central Authentication Service (CAS), developed by Yale. I've chosen to use this protocol because I can take advantage of existing connectors that are compatible with the various platforms we're using for our web projects. It also provides a common protocol that our partners will be able to implement more easily, using already canned connectors.

This article will outline the CAS server I've developed using Jifty. Learning how CAS works was a tedious process because there's a lot of specialized knowledge involved. Here, I attempt to discuss a CAS server implementation in terms that will be more readily accessible to someone already familiar with Perl. Hopefully, you'll be able to take the principles here to develop your own CAS integration, servers, or clients; or even to roll your own SSO service more easily in Perl.

Central Authentication Service

The CAS protocol is an especially nice SSO interface because it addresses many of the potential security pitfalls. For example, it prevents login replay attacks; it prevents a user from being able to log in as another if the original user inadvertently passes a login token in a pasted link; and it provides advanced features like proxy authentication.

The basic process of logging in to a CAS server is as follows:

Go to a restricted page on a client web service. The first time you visit a restricted page prior to logging in, the web service owning the page will redirect you to the login page. The login page is located on the CAS server. That is, the service will send an HTTP redirect response rather than the page itself (since it currently doesn't know if you should be able to see it). The redirect will contain a special parameter, named "service," which should contain the URL of the original page you are trying to view.

The browser will connect the client to the CAS server. Here, the user is presented with a login screen. The user fills in a username and password (or other login credentials if you use client-side certificates or something else) and clicks the Login button, which contacts the CAS server again with these credentials.

The CAS server will attempt to verify the credentials. If the given username and password are not valid, the user is returned to the login screen again. If they are valid, CAS sends back an HTTP redirect response. This returns the browser to the original restricted page that was passed to the CAS server originally in the "service" parameter. In addition, it will attach a parameter to the redirect, called "ticket," that contains a unique identifier, called the Service Ticket.

The browser will return to the original restricted page. The client web service that owns the original page receives the request for that page again, but this time with a Service Ticket attached in the "ticket" parameter. The service initiates its own HTTP connection (this time not through the user's browser) to contact the CAS server directly. It asks the CAS server if the given Service Ticket matches the service URL it originally sent. If CAS agrees, then it replies with the username of the person logging in. The web service can then determine if the owner of that username may access the page, and will return it if so.

That's the CAS protocol in a nutshell. The remainder of this article concerns the specifics of the implementation, which will reveal more about how this actually works.

CAS+

I've dubbed my implementation of the CAS protocol, CAS+ (or CASPlus for the actual Perl module name). The original CAS server implementation (and the only significant implementation that I'm aware of) is written in Java using the Spring Framework and served using a J2EE application server. I decided to implement my own CAS server using the CAS Protocol Specification on the CAS web site for a few reasons:

I do not like Java very much and I like J2EE servers even less. If you like Java and J2EE, I don't mean any offense. It's just not my preference (for both logical and purely emotional reasons).

I cannot host Java web applications on my web host, and I like my web host too much to change.

I like Perl a lot and have come to like Jifty very much as well.

I can host Perl, and all the tools I need for my own CAS customizations are available to me on CPAN.

CAS+ is a Jifty test application I'm writing in conjunction with work I am contributing back to Jifty.

Whenever possible, I like to multipurpose a project so that I get benefits on several levels out of the effort. This is the case with CAS+.

Jifty platform

I chose Jifty as my platform because I am now very familiar with it, I like it, and I am contributing to the project. Implementing the code took less than a weekend for the main components and a little more than a weekend to test and debug. This is, I believe, both a testament to the excellence of the Jifty platform and the simplicity of the CAS protocol.

Jifty is the brainchild of Best Practical Solutions, which hosts Hiveminder as both a pretty nice to-do list builder and the platform's main demo. I've built CAS+ using a development branch of Jifty, the virtual-models branch. It may not be entirely compatible with the release version of Jifty available from CPAN. Jesse Vincent, the chief monkey wrangler on Jifty, is working to bring this branch into the trunk, so I hope this won't be the case for long. However, the core functionality may work with the CPAN release. At least most tests passed when I last built against the CPAN release, but some of the advanced features (those not directly related to the CAS protocol) will certainly not work.

As of this writing, my implementation's main deviation from the standard regards support for SSL. I believe it should work with SSL for the most part, but I have not yet fully tested any of it, so I cannot confirm it. Also, the implementation does not necessarily require SSL in places where it is supposed to (according to the protocol definition) either, which is a potential security flaw in the current implementation. This is an area that I will be improving when I can get to it.

Getting CAS+

If you would like to, fetch and work with CAS+ to try it out. You'll first need to install Jifty. If you want to work with the experimental branch that CAS+ is made for, you may run something like the following on Linux or in the Mac OS X terminal:

Jifty has a large number of CPAN dependencies. Most, if not all, of these dependencies should install automatically. If you have trouble, see the Jifty web site on how to get help with the installation. If you do not have SQLite installed, you will probably want to do so for easy testing of Jifty and CAS+.

Next, you need to install CAS+. To do so, you will need to run these additional commands:

If everything has gone as planned and SQLite is installed, you can now run:

bin/jifty schema --setup
bin/jifty server

The first command builds the database and the second starts the test web server. Next, you should be able to contact the CAS+ server on your local machine at http://localhost:8889/. Of course, you can't log in yet because there are no users entered. At this time, the administration interface provided by Jifty may or may not allow you to add users due to recent bugs in CAS+ (this is still not a mature service), but if you entered the usernames and passwords directly into the users table of the CASPlus database using the command-line interface of SQLite, you can test login as well.

I don't recommend you use this service for production purposes at this time, but I would welcome additional contributors if you are interested in it.