Thursday, December 13, 2012

Configuring CAS Externally using Spring Import

Over the past few months, my team has been working on integrating the Jasig CAS (Central Authentication Service) framework with our application. CAS is a feature rich enterprise Single Sign On (SSO) service. Most importantly, it's very flexible. We need this flexibility because we have several customers, each with different authentication requirements:. Some with and without Active Directory, and others needing PKI (X.509) authentication. Beyond that, we also need to support light weight options for local development. So the problem we had to solve was how to configure CAS externally so we could dynamically change authentication mechanisms without having to rebuild CAS.

Let me first explain that the recommended way to extend CAS is using maven overlays. It's real simple to modify the default behavior in CAS by copying the files from the CAS WAR into your own WAR directory. For example, most of the authentication configuration exists in /WEB-INF/deployerConfigContext.xml. To change the default authentication behavior, you copy this file to your WARs /WEB-INF directory and modify it to fit your requirements. This is the file that defines all the authentication handlers for things like LDAP (BindLdapAuthenticationHandler), X.509 (X509CredentialsAuthenticationHandler), and my personal favorite the simple username equals password (SimpleTestUsernamePasswordAuthenticationHandler) authentication handler.

So the real problem became how can we enable the SimpleTestUsernamePassword authentication handler for local development and test servers, while disabling it for production systems? We wanted to avoid creating multiple CAS WARs containing configuration for their specific purpose: cas-ldap, cas-x509, cas-simple. Also, we wanted to avoid having a single CAS WAR that contained all methods of authentication. Ironically the solution was really simple and is actually used in other places in CAS.

Spring Import
The solution was spring imports (section This was a feature I was not previously familiar with, but now think is one of the coolest features in spring because it lets you change the behavior of the system without having to rebuild. Spring lets you load in other bean xml files via the spring import tag. And since CAS uses spring, it was easy to modify CAS to be configured externally.

Configuring CAS Externally
First, I assume you have already setup your maven project that is performing the maven overlay. Once you have built your project do the following:

  • copy
  • You'll also need to copy this same file to your application servers classpath for your application. For us this would be under the jboss conf directory: /jboss/server/default/conf. I also renamed this file to custom-deployerConfigContext.xml to avoid confusion.
  • Open the file /cas/src/main/webapp/WEB-INF/deployerConfigContext.xml
  • Remove all the bean tags in between the beans tag. This leaves you with nothing but the beans tag with nothing in between.
  • Paste in the following spring import tag:
    <import resource="classpath:custom-deployerConfigContext.xml"/>
  • Save your changes, rebuild and redeploy your CAS WAR
That's it. Now you can edit the custom-deployerConfigContext.xml and add/remove the SimpleTestUsernamePasswordAuthenticationHandler, or any other authentication handlers, without having to rebuild your CAS WAR.

Final Thoughts
Hopefully, you learned a little about how to configure CAS externally and a way to use springs import ability. For the most part this works great, but it isn't 100% fool proof. There are several CAS configuration files, so for the more complex authentication scenarios, you might have to modify the cas-servlet.xml or login-webflow.xml files. For example, if you want to do X.509 authentication, you have to include a bean in the cas-servlet.xml file and modify the login-webflow.xml file. But you could apply the same concepts to these files as well as cas-servlet.xml is just another spring file and login-webflow.xml is a spring webflow file that supports the bean-import tag.