Best Practice - Setting Up CAS Locally using the Maven WAR Overlay Method

New CAS documentation site

CAS documentation has moved over to apereo.github.io/cas, starting with CAS version 4.x. The wiki will no longer be maintained. For the most recent version of the documentation, please refer to the aforementioned link.

This document is designed to walk a new CAS user through our recommended development/build process. It does not require you to explicitly download any version of CAS, but it does require particular development tools to be available. We've detailed those requirements and our recommendations as part of this process. Experienced users may be able to ignore that, and other parts. At the end of the document, we've listed publicly available examples of our recommended process. This document will continue to evolve.

Software

Required Software

  • A Servlet 2.4 Container - We've had good luck with Tomcat and this exercise will use that.
  • Maven3- If you're interested in using the Maven2 WAR Overlay method, you must download the Maven software.  These instructions assume you are using a Maven 3 version which is the same level used to build all CAS modules.
  • Java 5 or higher - We'll assume you've installed a JDK. While Java 5 will work, it has reached its end-of-life, so you should install Java 6 or higher.

Recommended Software

  • An IDE - This exercise won't actually utilize an IDE, but we recommend you use the one you're most comfortable with in your daily work. We've had great luck with IntelliJ IDEA, Eclipse and the SpringSource Tool Suite
  • A Version Control system - Again, this exercise won't actually use a version control system, but you should ultimately be using one such as Subversion or Git.

Setting up the Software

Java

You should download the Java SDK from the link above and follow its installation prompts. The installation methods will vary per operating system so they won't be described here.

Tomcat

Tomcat is relatively simple to set up, especially for CAS. At the time of this writing, the most recent version was Tomcat 7.0.22, so that's the version we'll work with. You can download it from the Tomcat web site. We recommend downloading the core zip or tar.gz. You should use your favorite program to unzip the file to a location. For the purpose of this exercise, we'll install Tomcat 7.0.22 to the following location:

/opt/apache-tomcat-7.0.22/

You can install it wherever you want, though we recommend you don't utilize a directory with spaces. To make life easier, from this point forward, we'll refer to the Tomcat home, as $TOMCAT_HOME in case you use a different directory.

From this point forward, the documentation will refer to the location of your Tomcat home directory as $TOMCAT_HOME

We can run our examples without SSL enabled, but you should never really do that. Therefore, we'll step through setting up Tomcat's keystore file with a self-signed certificate. Self-signed certificates should NEVER be used for anything beyond development. Your test environment's certificate SHOULD mirror that of your production environment.

Note, these instructions assume you've never set up the keystore before. If you have, you will need to delete any key with the alias "tomcat". These instructions also assume the Java executables are in your path.

Create the Certificate.

  1. Open a Command-line or Terminal window and make sure you're in your home directory.
  2. Execute the following command:

    keytool -genkey -alias tomcat -keyalg RSA -validity 365

NOTE, the validity parameter allows you to specify, in the number of days, how long the certificate should be valid for. The longer the time period, the less likely you are to need to recreate it. To recreate it, you'd need to delete the old one and then follow these instructions again.

The response will look something like this:

Enter keystore password:  
Re-enter new password: 
What is your first and last name?
  [Unknown]:  $REPLACE_WITH_FULL_MACHINE_NAME
What is the name of your organizational unit?
  [Unknown]:  Test
What is the name of your organization?
  [Unknown]:  Test
What is the name of your City or Locality?
  [Unknown]:  Test
What is the name of your State or Province?
  [Unknown]:  Test
What is the two-letter country code for this unit?
  [Unknown]:  US
Is CN=$FULL_MACHINE_NAME, OU=Test, O=Test, L=Test, ST=Test, C=US correct?
  [no]:  yes

For the keystore password you should enter "changeit" without the quotation marks. When prompted for the first and last name, you should enter your machine name during development. The rest of the data does not matter. Then obviously answer "yes" to the question of whether it's correct.

  • CAS protocol requires HTTPS and for that to work, the value of the "first and last name" field above must be set to a fully qualified domain name.
    • On Windows, users can retrieve the fully qualified machine name by pressing WinKey+Pause and noting the value for "Full computer name".
    • On Linux, users can retrienve the FQN with `hostname -f`.
  • From this point forward, the documentation will refer to the machine name as $FULL_MACHINE_NAME.

Next, open up $TOMCAT_HOME/conf/server.xml and locate the block that looks like this:

   <!-- 
    <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS" />
  --> 

Remove the <!-- and the --> to enable the SSL connection. Then save the file. If you have Tomcat started, you'll need to restart it to enable the additional connector. You should then able able to access Tomcat over:

https://$FULL_MACHINE_NAME:8443/

Any application that wishes to securely connect to this Tomcat instance would need to import the certificate. You can export the certificate that's compatible with other JVM keystores by executing the following command:

keytool -export -alias tomcat -file server.crt

You'll get output that looks similar to this:

Enter keystore password:  
Certificate stored in file <server.crt>

You can then import the server.crt into other JVM keystore's by executing a command similar to this:

keytool -import -file server.crt -keystore $JAVA_HOME/jre/lib/security/cacerts -alias tomcat

Windows Users

  • Paths may require the "\" instead of "/" and reference variables with "%", i.e. %JAVA_HOME%. You may also have to put double quotes around the keystore path specially if %JAVA_HOME% contains spaces.
  • Make sure the command-prompt has sufficient administrator privileges before you do the import.You can achieve this by right-clicking on the command-prompt executable and selecting "Run as Administrator" from the context menu.

Mac Users

Your JVM cacerts file is located in an obscure location. We believe it's /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home/lib/security but you should confirm that.

It's recommended that you add it to the JVM keystore of your local development machine to facilitate testing.

Maven

Maven is another Apache project, and it's also easy to install. Similar to Tomcat, you should download Maven from its web site and unzip it. For purposes of this tutorial, we'll assume you've installed the latest Maven 2 version to:

/opt/apache-maven-2.2.1

For sanity's sake, we'll refer to the location of the Maven2 installation as $MAVEN_HOME in case you use a different location.

From this point forward, the documentation will refer to the location of your Maven2 home directory as $MAVEN_HOME.

Macintosh Users: You've already got a version of Maven installed by default. If you're interested in upgrading your version of Maven, check out these instructions.

Windows

  1. Add the M2_HOME environment variable by opening up the system properties (WinKey + Pause), selecting the "Advanced" tab, and the "Environment Variables" button, then adding the M2_HOME variable in the user variables with the value $MAVEN_HOME. Be sure to omit any quotation marks around the path even if it contains spaces. Note: For Maven < 2.0.9, also be sure that the M2_HOME doesn't have a '\' as last character.
  2. In the same dialog, add the M2 environment variable in the user variables with the value %M2_HOME%\bin.
  3. Optional: In the same dialog, add the MAVEN_OPTS environment variable in the user variables to specify JVM properties, e.g. the value -Xms256m -Xmx512m. This environment variable can be used to supply extra options to Maven.
  4. In the same dialog, update/create the Path environment variable in the user variables and prepend the value %M2% to add Maven available in the command line.
  5. In the same dialog, make sure that JAVA_HOME exists in your user variables or in the system variables and it is set to the location of your JDK, e.g. C:\Program Files\Java\jdk1.5.0_02 and that %JAVA_HOME%\bin is in your Path environment variable.
  6. Open a new command prompt (Winkey + R then type cmd) and run mvn --version to verify that it is correctly installed.

Unix-based Operating Systems

  1. In a command terminal, add the M2_HOME environment variable, e.g. export M2_HOME=$MAVEN_HOME.
  2. Add the M2 environment variable, e.g. export M2=$M2_HOME/bin.
  3. Optional: Add the MAVEN_OPTS environment variable to specify JVM properties, e.g. export MAVEN_OPTS="-Xms256m -Xmx512m". This environment variable can be used to supply extra options to Maven.
  4. Add M2 environment variable to your path, e.g. export PATH=$M2:$PATH.
  5. Make sure that JAVA_HOME is set to the location of your JDK, e.g. export JAVA_HOME=/usr/java/jdk1.5.0_02 and that $JAVA_HOME/bin is in your PATH environment variable.
  6. Run mvn --version to verify that it is correctly installed.

Setting Up Your Local CAS Project

At this point, you should have all the necessary software installed.

Working with a Maven2-based project may be different from when you worked with an Ant-based project. For many people, Ant-based projects included things like manually managing dependencies, building source for external projects that you were integrating with, keeping binary JAR files in your version control system, and manually crafting Ant build files. Maven2 is a different way of thinking. The libraries or projects you're working with maintain the list of required dependencies, Maven2 attempts to resolve them and any conflicts, downloads them and keeps them in a local cache. It also uses standard "goals" (which were often called tasks in Ant). Recent versions of Ant have included some of these features with add-ons such as Ivy 2.0. At this point, there is no expectation that you understand completely how Maven2 works. We'll explain the important concepts as we go along.

In particular for CAS, we'll be working with what's called a "WAR Overlay." Essentially, we've already built and made available the standard CAS distribution. What you're interested in doing is merely ADDING to our standard distribution, possibly by adding new files or configuration, new dependencies, or replacing a few of our standard files. This WAR Overlay process supports them all. We always recommend this process because if keeps you out of the business of downloading the CAS source, building it, making your customizations, rebuilding it, etc. and maintaining a copy of our source code locally. With the WAR overlay, you're only keeping the files you care about locally.

How do we get started?

The first step is to create your "workspace." We'll assume, for arguments sake, that we're not using an IDE since it makes this tutorial easier, and we're not working with many files. We'll assume you're keeping a copy of your work here:

/opt/work

In case you're not, we'll refer to your work area as $WORKSPACE.

In case you're keeping your local work elsewhere, we'll refer to your workspace as $WORKSPACE

This means that if you're creating your local organization's CAS project, you might put the files here:

$WORKSPACE/local-cas

We'll refer to this as $PROJECT_HOME to make it easier.

We'll refer to your local project's directory as $PROJECT_HOME

Create the pom.xml

The second step is to create the pom.xml for your local institution's CAS. This should go in the $PROJECT_HOME directory. We recommend you create a version like the one below:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd ">
	<modelVersion>4.0.0</modelVersion>
	<groupId>edu.university.cas</groupId>
	<artifactId>local-cas</artifactId>
	<packaging>war</packaging>
	<version>1.0-SNAPSHOT</version>

	<build>
		<plugins>
			<plugin>
			     <artifactId>maven-war-plugin</artifactId>
                             <configuration>
                                 <warName>cas</warName>
                             </configuration>
                        </plugin>
		</plugins>
	</build>

	<dependencies>
		<dependency>
			<groupId>org.jasig.cas</groupId>
			<artifactId>cas-server-webapp</artifactId>
			<version>${cas.version}</version>
			<type>war</type>
			<scope>runtime</scope>
		</dependency>
	</dependencies>

	<properties>
		<cas.version>3.5.2</cas.version>
	</properties>

        <repositories>
             <repository>
                  <id>ja-sig</id>
                  <url>http://oss.sonatype.org/content/repositories/releases/ </url>
             </repository>
        </repositories>
</project>

Let's walk through this step by step:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
</project>

This is the standard POM root xml element. Suffice to say, we must have it for this to be useful! The Maven Team maintains a relatively robust POM reference if you're interested in learning more about the POM.

The next set of elements are:

<modelVersion>4.0.0</modelVersion>
	<groupId>edu.university.cas</groupId>
	<artifactId>local-cas</artifactId>
	<packaging>war</packaging>
	<version>1.0-SNAPSHOT</version>

The modelVersion MUST be set to 4.0.0. The groupId should be set to something that refers to your local organization. The artifactId should reflect that it's a local instance of CAS (i.e. local-cas, local-cas-webapp, myU-cas-webapp, etc.). Since we ultimately want to build a WAR file to deploy, our packaging should be set to war. Finally, the version should reflect your local organization's versioning system for local CAS releases.

The next set of elements are:

<build>
		<plugins>
			<plugin>
			     <artifactId>maven-war-plugin</artifactId>
                             <configuration>
                                 <warName>cas</warName>
                             </configuration>
                        </plugin>
		</plugins>
	</build>

This section relates to how we want to build the project. We're saying that when we tell Maven2 to build the project, the WAR plugin should be used with the supplied configuration. In this instance, our configuration only says what to name the WAR file. For more information on the WAR Plugin, take a look at its documentation.

The next set of elements are:

<dependencies>
		<dependency>
			<groupId>org.jasig.cas</groupId>
			<artifactId>cas-server-webapp</artifactId>
			<version>${cas.version}</version>
			<type>war</type>
			<scope>runtime</scope>
		</dependency>
	</dependencies>

This section is critical. Its where you define what libraries and external projects YOUR project depends on. In this particular POM file, our only dependency is the Jasig produced WAR file for CAS. Later on, we'll see why you might need more. Notice that each dependency is referenced by an artifactId and a groupId. Maven attempts to automatically resolve dependencies from publicly available repositories AND whatever repositories you've defined in your POM. In our case, we had added this:

<repositories>
   <repository>
      <id>ja-sig</id>
      <url>http://oss.sonatype.org/content/repositories/releases/ </url>
   </repository>
</repositories>

This tells Maven2 to not only look in the public repositories that Maven2 knows about, but also to check in the Jasig repository (which is where you'll find the Jasig CAS Server artifacts).

The final item we have in our project is a small section where we can define custom properties. In this instance, we've defined the cas.version which is referenced in our CAS Web App dependency. This is not necessary at all, but it allows us to see quickly at a glance all the dependency version numbers.

Build It!

While this project is not yet exceptionally useful, we should make sure we can build it. As mentioned before, Maven2 defines a set of "goals" that have common meaning across projects. To build our WAR file, execute the following in the $PROJECT_HOME directory:

mvn clean package

What does this mean?

  • mvn - The standard Maven2 executable
  • clean - clean out any artifacts from the last build
  • package (looks familiar, right?) - build this project according to how it should be packaged (in our case, a WAR file).

If the build was successful, you should now see a directory called "target" in your $PROJECT_HOME. This directory should have a cas.war in it. Again, it's not a terribly useful WAR file right now. You could have just taken the standard CAS artifact from the Maven repository and renamed it and had the same thing. Baby steps! The next step is to deploy it to Tomcat. Copy the file to $TOMCAT_HOME/webapps/ Then, start Tomcat. On Unix-based systems, there should be a startup.sh in the $PROJECT_HOME/bin directory. Windows users should see a similar batch file. If you then point your browser to https://$FULL_MACHINE_NAME:8443/cas/login*, you should see the CAS login page. The default authentication is such that the username and the password are the same. Once you're done playing with it, you can stop it by using either *$PROJECT_HOME/bin/shutdown.sh or shutdown.bat.

CAS 4 Default Authentication

Starting with CAS 4, the default authentication handler has been switched to a slightly more complicated handler. Briefly, the username and password are no longer the same, but are actually changed to a hardcoded set in the configuration. The username is "casuser" in lowercase without the quotes and the password is "Mellon", without the quotes of course.

See this link for more info.

Replace the Default Authentication Method with Something Else

CAS includes a large number of authentication methods, all of which are detailed under Authentication so we won't reiterate them here. We're going to replace the default authentication method with one of them. To keep this simple, we're going to use one that doesn't require any external resources (such as an LDAP server). Not entirely realistic, but the mechanism is the same. In this case, we'll be using one of the "generic" authentication handlers. Therefore, the first step is add a dependency to the pom.xml. So if you've closed out of your pom.xml, open it back up! Add the following dependency into the <dependencies>...</dependencies> XML block:

<dependency>
			<groupId>org.jasig.cas</groupId>
			<artifactId>cas-server-support-generic</artifactId>
			<version>${cas.version}</version>
			<type>jar</type>
			<scope>runtime</scope>
		</dependency>

This says that we want to include the Generic Support from CAS at Runtime, and that it's a JAR file. Next, we'll need to configure this in! Remember when we said this was the Maven2 WAR Overlay method, and that this means that you can selectively overwrite files in the "WAR" that you're laying stuff over. Well, the WAR dependency is the one we're going to overlay stuff into. So under project home create the following directory structure:

$PROJECT_HOME/src/main/webapp/WEB-INF

which is where we'll be putting our custom configuration.

Next, grab the latest deployerConfigContext.xml for your release, e.g. version 3.5.2 Create a deployerConfigContext.xml in $PROJECT_HOME/src/main/webapp/WEB-INF/ and copy in the contents from the web. Next locate this bean:

<bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler" />

This is the simple test authentication method that always resolve to username=password for demonstration purposes. Clearly, not a good thing to have in production. Well, what we're going to replace it with isn't necessarily the greatest thing for production either, but it's a simple step up. Replace the above bean definition with:

<bean class="org.jasig.cas.adaptors.generic.AcceptUsersAuthenticationHandler">
   <property name="users">
      <map>
         <entry>
            <key>
               <value>scott</value>
            </key>
            <value>secret</value>
         </entry>
      </map>
   </property>
</bean>

This example authentication method only accepts the user "scott" if his supplied password is "secret". Clearly not useful in production either, but slightly more secure. With this change in place, save the file. Rebuild your WAR file from the $PROJECT_HOME:

mvn clean package

Copy that WAR file into the $TOMCAT_HOME/webapps/. Delete any existing "cas" directory under $TOMCAT_HOME/webapps/. Start up your container again. Navigate to the login page. When prompted for the username and password, first try entering "scott" and "scott". This should fail. Then enter "scott" and "secret". You should see the message that says you've successfully logged in. You've made a great first attempt at modifying your CAS installation.

While this is a simple case, you can configure in more complex authentication methods. As of this writing, CAS supports database, LDAP, Active Directory, SPNEGO, Delegated/Trusted, X.509 Certificates, and more. Some methods are more complex than others, and we've made attempts to document them in their appropriate pages. The above example should give you the starting point for configuring other authentication methods, but remember, they're all not that easy, but they follow the same steps: add the dependency, update the appropriate configuration files, and rebuild.

Modifying the Look and Feel

Spring Configuration Structure

Copies of the original versions of each file are located in the standard distributions or can be obtained from our Github Repository

Because we would like to encourage the usage of the Maven2 WAR Overlay method, we've made numerous attempts to make it easier to use. One of those methods includes more fine-grained Spring XML configuration files, as well as a method for auto-loading your additional custom XML files. We're going to go over this now:

Loading Additional Configuration Files and Enabling Additional Features

CAS will automatically load any XML file located in $PROJECT_HOME/src/main/webapp/WEB-INF/spring-configuration/ (after obviously, rebuilding the WAR (wink) ). So when you have your own configuration to add, or you want to enable another feature for CAS, you can drop the XML file in that directory and it will load. You can see this example with our Inspektr configuration and the ClearPass Extension.

Many of the optional CAS features are built to be enabled this way (i.e. the Inspektr library).

Explanation of Location of Files in the Standard Distribution

Messages

  • WEB-INF/classes/messages*.properties - The messages, localized.  If you don't like the default messages, you can adjust them.  Change the values for the languages you care about it.

You can add additional messages by either changing the files above, or overriding the ResourceBundleMessageSource in the cas-servlet.xml.

Views

  • WEB-INF/classes/default_views.properties - This file stores the locations of the default views (JSP pages) that CAS uses.  In general, you use should the Maven2 WAR Overlay Method to override the views rather than changing the locations.
  • WEB-INF/classes/protocol_views.properties - Similar to the default_views.properties, it stores the locations of the default locations of the protocol views.

To add additional views, one can either customize the provided properties or provide your own view resolver in a separate Spring configuration file, such as this example:

    <bean id="clearPassViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"
        p:order="1"
        p:prefix="/WEB-INF/view/jsp/custom/"
        p:suffix=".jsp"  />

The files are for the most part located under WEB-INF/view/jsp.

The default skin is under "default". The protocols are under "protocols."

Skins

Logging

  • WEB-INF/classes/log4j.xml - The log4 settings that are used by default.  You should/could override this with your own.  Some people like to change the location of where the CAS log file is stored.

Configuration Files

All configuration files are located under WEB-INF or one of its sub-directories:

  • WEB-INF/web.xml - This file should be modified if you're adding any custom exception handling (i.e. 500 error pages, etc.) or if you've added additional endpoints to CAS (i.e. /myCustomLogin).
  • WEB-INF/cas-servlet.xml
  • WEB-INF/cas.properties - this defines the URLs to configure the Services Management Tool to authenticate to your local CAS instance, as well as the Database Dialect for the Services Management Tool. You will MOST LIKELY need to override this if you haven't overridden where you load the properties from.
  • WEB-INF/deployerConfigContext.xml - This is detailed above.
  • WEB-INF/login-webflow.xml - The Spring Web Flow for the login. In most cases you WILL NOT need to override this. If you enable things like X.509 Authentication, etc. you would need to.
  • WEB-INF/restlet-servlet.xml - The configuration for the RESTful APIs.  Normally does not need to be touched.
  • WEB-INF/spring-configuration - this is where any Spring configuration that CAS loads go. CAS has a bunch in there that you can override by default.  You can also add additional ones in there as needed.
  • WEB-INF/unused-spring-configuration - these are example or complete Spring configuration files that can be copied into the spring-configuration directory to be enabled.

Configuration Files under the WEB-INF/spring-configuration directory:

  • applicationContext.xml - Contains most of the default CAS beans that don't need to be changed. Includes an Autowiring Scheduler such that if you are configuring additional Quartz Jobs, they do not have to be explicitly wired, they will be detected.
  • argumentExtractorsConfiguration.xml - Configures which protocols to use. By default CAS and SAML are enabled. You would need to change this if you wanted to add Google Apps for Education support.
  • propertyFileConfigurer.xml - Configures the location of external properties. The default points to WEB-INF/cas.properties
  • securityContext.xml - This is for the security of the Services Management Tool. Usually does not need to be changed.
  • ticketExpirationPolicies.xml - The expiration policies used to expire TicketGrantingTickets and Service Tickets. Only really need to be changed if you change the timeout.
  • ticketGrantingTicketCookieGenerator.xml - The configuration for the Spring CookieGenerator for the TicketGrantingTickets. This would only be modified if you wanted to change the length of time the cookie is valid for.
  • ticketRegistry.xml - The configuration for the default ticket generator. This should be replaced if you plan on using a different TicketRegistry.
  • uniqueIdGenerators.xml - the configuration for the unique identifier generators. Normally does not need to be modified.
  • warnCookieGenerator.xml - stores the configuration for the Spring CookieGenerator for the "WARN" cookie. Should probably not be modified.

Publicly Available Maven2 WAR Overlay Examples

  • Virginia Tech maintains a sophisticated Maven War Overlay build process for its local CAS instance. The project is publicly available for review in our Subversion Repository.

 

Services management webapp

Before CAS server 4.0.0, the services management webapp was part of the CAS server.

But with the new major version 4.0.0 of CAS, the services management webapp is in a more general and separate webapp dedicated to CAS management : the cas-management-webapp module.

As it requires equivalent configuration in the deployerConfigContext.xml file as the CAS server webapp, the CAS management webapp needs to be setup using the Maven2 WAR Overlay Method, in a similar way as the CAS server.

Example
<dependencies>
  <dependency>
    <groupId>org.jasig.cas</groupId>
   <artifactId>cas-management-webapp</artifactId>
   <version>${cas.version}</version>
   <type>war</type>
   <scope>runtime</scope>
  </dependency>
</dependencies>

An overlay demo for CAS server version 3.5.x : https://github.com/leleuj/cas-overlay-3.5.x.
An overlay demo for CAS server version 4.0.0 : https://github.com/leleuj/cas-overlay-demo.