Dashboard > CAS User Manual > Navigation > Advanced Features > Second-Level CAS Server
Log In   View a printable version of the current page.
Second-Level CAS Server
Added by Adam Rybicki , last edited by Adam Rybicki on Apr 09, 2008  (view change)
Labels: 
(None)


Feature Under Consideration

The Second-Level CAS Server feature was created based on the requirements of the University of California, Berkeley. The University wants to contribute this feature to JA-SIG. The documentation that follows has been copied from the original documentation that accompanied the solution as developed for UC Berkeley by Unicon, Inc. Once this proposed feature is vetted by the community and adopted as a supported feature, this documentation will be updated as well.

Please note that the custom authentication handler developed for UC Berkeley and documented within is not required for Second-level CAS server to operate correctly. In other words, institutions are welcome to use one of the standard CAS authentication handlers in their implementations of Second-level CAS.

Overview

UC Berkeley uses JA-SIG CAS for its Single Sign-On (SSO) solution. Not all Web applications at UC Berkeley have been CAS-enabled. For some of the remaining applications, it is a matter of time and priority. Others, however, are considered "high value" or more security-sensitive. UC Berkeley has decided that for those applications a second-level CAS server is desired. Second-level here means that in order to authenticate to the desired secure application the users have to first authenticate to the existing CAS server (first-level), then to the second-level server before the authorized user is allowed access to the high-security Web application.

Requirements

In order to make primary CAS the first authentication source, the second-level CAS server is itself CAS-enabled. That is, in order to log in to second-level CAS, the user must successfully authenticate to the primary CAS server. It is only from primary CAS that second-level CAS can obtain the NetID, or CalNet ID, as it is known at UC Berkeley. CalNet ID is not prompted for by the second-level CAS. The only prompt issued by the second-level CAS is for CalNetKey.

For added security, CalNetKey may only be entered by clicking the mouse on a numeric keypad. This is to prevent any keystroke logging application that may have been installed on a publicly-accessible computer from logging, and potentially compromising, CalNetKey. Since CalNet ID is not exchanged over the network between the browser and second-level CAS, even in case of a compromise, an attacker would not have enough information to steal a full set of credentials required for login to high-security applications.

While the first-level CAS uses Kerberos for authentication, the second-level CAS server uses a Personal Identification Number (PIN), known at UC Berkeley as CalNetKey. CalNetKey is stored as a custom attribute in LDAP. For security reasons CalNetKey is not stored in LDAP in clear text. Instead, it is combined with a "salt" value and one-way-hash encoded into a random-looking string of alphanumeric characters. Only persons with the privilege to use the high-security Web applications have CalNetKey attributes in their LDAP records.

Primary CAS server supports the CAS Single Sign-Out feature. This means that this solution must expect and process sign-out notifications from the primary CAS server and invalidate the corresponding Single Sign-On sessions on the second-level CAS server.

UC Berkeley uses server clustering to assure high availability of its CAS servers. The solution that Unicon delivers must support clustering.

UC Berkeley wishes to explore the possibility of contributing the results of this effort to the JA-SIG open source community and beyond. Unicon is requested to evaluate the feasibility and method of making such a contribution. It is also because of this requirement that Unicon should consider this solution to be flexible enough for other institutions to adopt.

Design

General

Although UC Berkeley requirements do not explicitly specify it, Unicon desires to implement second-level CAS with the fewest modifications to the original CAS. This should make upgrading to new releases of CAS server easier for UC Berkeley after Unicon has delivered the finished product. Since CAS, and UC Berkeley's second-level CAS especially, are security applications, it will be important for UC Berkeley to quickly and with little effort incorporate new releases of CAS. This will be especially important when security-related CAS releases become available.

Integration with the Primary CAS Server

Naturally, the primary CAS server at UCB requires no modifications in this design. In order to assure primary authentication, the Second-level CAS server is CAS-enabled using the JA-SIG Java CAS client. Unicon initially chose the Yale CAS client because of its simplicity and the fact that it is bundled with CAS server. The Yale CAS client, however, does not have support for Single Sign-Out, which is required in this project.

JA-SIG Java CAS client operates as a standard JEE Web filter. Actually, it is a collection of filters that operate in unison. One assures that an authenticated session exists, another is used to validate service tickets, and another handles Single Sign-Out. All of the configuration for the JA-SIG Java CAS client resides in the web.xml file for the Web application being CAS-enabled, in this case the Second-level CAS server. To simplify how the Second-level CAS obtains the CalNet ID from the CAS filter, the filter is configured to "wrap" access to the HttpServletRequest. This allows Secondary CAS server to get the CalNet ID by simply making a getRemoteUser() call.

The Primary CAS Server supports service registry, and the Second-level CAS has been added to its list of services authorized to request authentication. Additionally, Primary CAS support the CAS Single Sign-Out feature, which notifies Second-level CAS when the user has logged out of Primary CAS.

A detailed configuration example for the JA-SIG Java CAS client is available below in the section Files Modified.

New User Interface

UC Berkeley developed a prototype UI for the collection of CalNetKey. This prototype was successfully incorporated into CAS 3.1. JavaScript used to implement collection of the PIN from the button clicks to the input field was incorporated and modified to refer to the input form's names as they are known to the standard CAS server.

Credentials Interface Implementation

Since Second-level CAS collects the credentials from the JA-SIG Java CAS filter and the Web form, a new Java class, CalNetKeyCredentials, was added. To keep this implementation as simple as possible, it extends the standard UsernamePasswordCredentials implementation.

To properly extract the credentials from the CAS filter and from the new UI, a new class, CalNetKeyCredentialsBinder, was added that implements the required CredentialsBinder interface. It is this binder that actually calls getRemoteUser(), which, in turn, calls the JA-SIG Java CAS filter, to obtain the CalNet ID that came from Primary CAS authentication. In order to configure CAS to make use of this CalNetKeyCredentialsBinder, the authenticationViaFormAction bean, as defined in cas-servlet.xml, got a new property, a reference to a new bean, calNetKeyCredentialsBinder, also defined in the same file. calNetKeyCredentialsBinder bean is an instance of CalNetKeyCredentialsBinder class. authenticationViaFormAction bean also received another property, formObjectClass, which tell the bean which class to use to store credentials in. The default class was UsernamePasswordCredentials, and the newly configured class is CalNetKeyCredentials. This approach allows to keep using the CAS server-supplied AuthenticationViaFormAction class, which would be complicated to replace.

Because of the different class implementing Credentials, a new class that can resolve a principal from the new Credentials implementation was added. Its name is CalNetKeyCredentialsToPrincipalResolver, and it is configured as one of the credentialsToPrincipalResolvers properties of the authenticationManager bean in deployerConfigContext.xml. authenticationManager also is configured to use a new authentication handler in its authenticationHandlers list.

Single Sign-Out Processing

In order to process Single Sign-Out (SSOut) messages from the primary CAS server, the SSOut filter from JA-SIG CAS Client is used. This assures that the successful Primary CAS authentication artifact is removed from the filter's session and that on subsequent requests to the second-level CAS Primary CAS authentication will be enforced.

However, the core functionality of that filter was insufficient. It was also necessary to keep track of the relationships between Primary CAS service tickets (ST) and second-level CAS ticket granting tickets (TGT). Additional Web filter was designed to use an approach similar to that in the JA-SIG CAS Client's SSOut filter. This approach uses a mapping between those tickets. The mapping can retrieve ST given TGT and vice versa.

This two-way mapping is necessary because second-level CAS needs to remove the mapping if its TGT becomes invalidated because of time-out or explicit user logout.

The implementation of this mapping must function in clustered environment. Unicon has developed a simple, memory-based mapping class based on the Java Map interface. After testing based on this simpler implementation was successful, a cluster-friendly version, based on JBoss Cache, was added. The simple, memory-based implementation is available and because it comes without networking overhead, its performance should be better.

A good way to associate Primary CAS ST with second-level CAS TGT is to monitor the second-level CAS TGT creation and destruction. This is implemented in a new EventHandler registered to receive TicketEvents.

Authentication Handler

A new authentication handler, implemented by a class called CalNetKeyAuthenticationHandler, is where the actual CalNetKey authentication is performed. The handler performs a search for the LDAP entry where uid equals CalNet ID. CalNet ID is what the Primary CAS authentication provides. Only two attributes are asked for in this LDAP query: berkeleyEduCalNetKey, and berkeleyEduCalNetKeySalt. Names of these attributes are configurable as properties of the authentication handler bean configured in deployerConfigContext.xml. Here is a more complete list of properties of this bean:

Property Description Example Value
filter LDAP search filter uid=%u
searchBase LDAP search base ou=people,dc=berkeley,dc=edu
scope This is from the JNDI API used for LDAP searching. SearchControls.OBJECT_SCOPE=0, SearchControls.ONELEVEL_SCOPE=1, SearchControls.SUBTREE_SCOPE=2 1
allowMultipleAccounts Are multiple LDAP results permitted for this search? In the context of this project multiple results from this search would create ambiguity, so it is not anticipated that this would ever be a valid situation. false
pinAttribute Name of the LDAP attribute storing the encoded CalNetKey berkeleyEduCalNetKey
saltAttribute Name of the LDAP attribute storing the CalNetKey salt value used to one-way-hash encode the CalNetKey berkeleyEduCalNetKeySalt
contextSource A reference to a bean that provides LDAP access at runtime. This is an instance of the CAS server-supplied AuthenticatedLdapContextSource defined in the same file. contextSource

Based on the above properties, the handler performs the LDAP search. If successful, the search returns one or more instance of CalNetKey, an inner class containing the LDAP attributes queried for. A standard Java MessageDigest class provides the implementation of the SHA-256 hash, which is given the CalNetKey (the PIN entered by the user on the Second-level CAS authentication screen) and the salt (obtained from LDAP) to create a hash. This hash is then converted to a string to hexadecimal characters and finally compared to the encoded LDAP attribute. When they are equal, second-level authentication succeeds.

Files Added

This section lists files added to a standard distribution of JA-SIG CAS Server 3.1.x to implement it as Second-level CAS at UCB.

Name Location Purpose
cas-client-core-3.1.1.jar cas-server-webapp/target/cas-server-webapp-3.1.2/WEB-INF/lib* JA-SIG CAS Client
CalNetKeyAuthenticationHandler.java cas-server-support-ldap/src/main/java/edu/berkeley/cas/adaptors/ldap CalNetKey CAS authentication handler
CalNetKeyCredentials.java cas-server-support-ldap/src/main/java/edu/berkeley/cas/authentication/principal A CAS Credentials interface implementation to store CalNetKey credentials. This class extends the UsernamePasswordCredentials class.
CalNetKeyCredentialsToPrincipalResolver.java cas-server-support-ldap/src/main/java/edu/berkeley/cas/authentication/principal A CAS CredentialsToPrincipalResolver interface implementation to retrieve a Principal from CalNetKeyCredentials. This class extends the AbstractPersonDirectoryCredentialsToPrincipalResolver class.
CalNetKeyCredentialsBinder.java cas-server-support-ldap/src/main/java/edu/berkeley/cas/web/bind A CAS CredentialsBinder interface implementation to store the CalNetKey credentials in a CalNetKeyCredentials class.
TicketHandler.java cas-server-support-ldap/src/main/java/edu/berkeley/cas/events/handler A CAS EventHandler implementation that tracks TGT creation and destruction
PrimaryCASSingleSignOutFilter.java
FilterUtils.java
HashMapBackedTicketMappingStorage.java
JBossCacheBackedTicketMappingStorage.java
TicketMappingStorage.java
XmlUtils.java
cas-server-support-ldap/src/main/java/edu/berkeley/cas/web/filter Primary CAS Single Sign-Out Web filter and related utilities
pinpad_styles.css cas-server-webapp/src/main/webapp/css CSS styles definition for PinPad from UCB.
bg_button_a.gif cas-server-webapp/src/main/webapp/images Image from UCB to paint PinPad buttons.
bg_button_span.gif cas-server-webapp/src/main/webapp/images Image from UCB to paint PinPad buttons.
pinpad.js cas-server-webapp/src/main/webapp/js JavaScript source from UCB to implement the PinPad functionality.
build.bat   Script to perform a Maven 2 build (this script should work fine on any platform as it doesn't use platform-specific constructs).

*This location is dynamically determined by Maven because JA-SIG Java CAS client is added as a Maven dependency.

Files Modified

Name Location Purpose Modification
casLoginView.jsp cas-server-webapp/src/main/webapp/WEB-INF/view/jsp/default/ui CAS login prompt Added the PinPad buttons from UCB
casLogoutView.jsp cas-server-webapp/src/main/webapp/WEB-INF/view/jsp/default/ui CAS logout confirmation Invalidated the HttpSession. CAS does not rely on the session, but the JA-SIG Java CAS filter does. Invalidating the session will force the filter to request primary CAS authentication.
top.jsp cas-server-webapp/src/main/webapp/WEB-INF/view/jsp/default/ui Common JSP headers Changed the title.
cas-servlet.xml cas-server-webapp/src/main/webapp/WEB-INF Spring bean configuration file that configures the business logic processing HTTP requests. Added properties to the authenticationViaFormAction bean.
deployerConfigContext.xml cas-server-webapp/src/main/webapp/WEB-INF Deployment-specific CAS server configuration file Replaced the default authentication handler with CalNetKeyAuthenticationHandler and its options. Added a bean with LDAP server configuration. See the example below.
auditTrailContext.xml cas-server-webapp/src/main/webapp/WEB-INF Spring Beans configuration file Added an EventHandler to process the TGT creation and destruction events
web.xml cas-server-webapp/src/main/webapp/WEB-INF Web application deployment descriptor Added the JA-SIG Java CAS client filters and their options as illustrated in the example below.
pom.xml cas-server-webapp Maven 2 configuration file Added dependencies on the CAS LDAP module (internal), JBoss Cache module (internal), and JA-SIG Java CAS Client (external)
pom.xml cas-server-support-ldap Maven 2 configuration file Added dependency on the JBoss Cache module (internal)
log4j.properties cas-server-webapp/src/main/webapp/WEB-INF/classes Log4j configuration file Configured a fully-qualified path to cas.log file and added a new log file for UCB-specific logging

web.xml addition

<!-- JA-SIG CAS client for Java -->
<!-- First, the single sign-on filters -->
<filter>
  <filter-name>CAS Authentication Filter</filter-name>
  <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
  <init-param>
    <param-name>casServerLoginUrl</param-name>
    <param-value>https://auth-test.berkeley.edu/cas/login</param-value>
  </init-param>
  <init-param>
    <param-name>serverName</param-name>
    <param-value>https://aws-dev.berkeley.edu</param-value>
  </init-param>
</filter>
<filter>
  <filter-name>CAS Validation Filter</filter-name>
  <filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
  <init-param>
    <param-name>casServerUrlPrefix</param-name>
    <param-value>https://auth-test.berkeley.edu/cas</param-value>
  </init-param>
  <init-param>
    <param-name>redirectAfterValidation</param-name>
    <param-value>true</param-value>
  </init-param>
  <init-param>
    <param-name>serverName</param-name>
    <param-value>https://aws-dev.berkeley.edu</param-value>
  </init-param>
</filter>
<filter>
  <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
  <filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
</filter>
<filter>
  <filter-name>CAS Assertion Thread Local Filter</filter-name>
  <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
</filter>

<!-- And now, the single sign-out filters -->
<filter>
  <filter-name>CAS Single Sign Out Filter</filter-name>
  <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
</filter>

<filter>
  <filter-name>Primary CAS Single Sign Out Filter</filter-name>
  <filter-class>edu.berkeley.cas.web.filter.PrimaryCASSingleSignOutFilter</filter-class>
</filter>

<!-- Filter mappings in the correct order -->
<filter-mapping>
  <filter-name>Primary CAS Single Sign Out Filter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
  <filter-name>CAS Single Sign Out Filter</filter-name>
  <url-pattern>/login/*</url-pattern>
</filter-mapping>
 <filter-mapping>
  <filter-name>CAS Authentication Filter</filter-name>
  <url-pattern>/login/*</url-pattern>
</filter-mapping>
 <filter-mapping>
  <filter-name>CAS Validation Filter</filter-name>
  <url-pattern>/login/*</url-pattern>
</filter-mapping>
 <filter-mapping>
  <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
  <url-pattern>/login/*</url-pattern>
</filter-mapping>
 <filter-mapping>
  <filter-name>CAS Assertion Thread Local Filter</filter-name>
  <url-pattern>/login/*</url-pattern>
</filter-mapping>
 <listener>
  <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>

deployerConfigContext.xml additions

First is the new bean added to the authenticationHandlers property of the authenticationManager bean:

<bean class="edu.berkeley.cas.adaptors.ldap.CalNetKeyAuthenticationHandler">
  <property name="filter" value="uid=%u" />
  <property name="searchBase" value="ou=people,dc=berkeley,dc=edu" />
  <!-- SearchControls.OBJECT_SCOPE=0, SearchControls.ONELEVEL_SCOPE=1, SearchControls.SUBTREE_SCOPE=2 -->
  <property name="scope" value="1" />
  <property name="allowMultipleAccounts" value="false" />
  <property name="pinAttribute" value="berkeleyEduCalNetKey" />
  <property name="saltAttribute" value="berkeleyEduCalNetKeySalt" />
  <property name="contextSource" ref="contextSource" />
</bean>

Second is the addition of the contextSource bean describing the LDAP server:

<bean id="contextSource" class="org.jasig.cas.adaptors.ldap.util.AuthenticatedLdapContextSource">
  <property name="anonymousReadOnly" value="false" />
  <property name="userName" value="uid=ist-is-ias-cas-unicon,ou=applications,dc=berkeley,dc=edu" />
  <property name="password" value="[removed]" />
  <property name="pooled" value="true" />
  <property name="urls">
    <list>
      <value>ldaps://ldap-test.berkeley.edu/</value>
    </list>
  </property>
  <property name="baseEnvironmentProperties">
    <map>
      <entry>
        <key><value>java.naming.security.authentication</value></key>
        <value>simple</value>
      </entry>
    </map>
  </property>
</bean>

Source Code Repository

UC Berkeley uses Subversion (SVN) as its version control system. The entire second-level CAS project has been allocated space under svn+ssh://svn.berkeley.edu/cas. Unicon created the customary "vendor," "branches," "tags," and "trunk" subdirectories in there. As is customary, the "trunk" directory will not have subdirectories, and it will reflect the most current development version of the project.

To populate this repository Unicon started by importing an unmodified release of CAS 3.1.1 into the vendor branch tagged as "current." This version was also tagged as "3.1.1." The contents of vendor branch "current" was copied into "trunk" and the development of the second-level CAS server proceeded from there. All development commits were made into "trunk."

When release 3.1.2 of CAS became available, it was imported into vendor branch using the SVN script svn_load_dirs.pl. This script automates file/directory moves, renames, and deletions with minimum risk of losing historical revisions. After the script was finished, the vendor branch "current" tas also tagged as "3.1.2." The next step was to merge the differences between 3.1.1 and 3.1.2 into the development area under trunk. The only files that were flagged as merge conflicts were GIF images that were accidentally corrupted when the release 3.1.2 of CAS was produced. The corrupted files were discarded, and the merged work area was committed to trunk.

Future releases of CAS server should follow the same pattern as described in the paragraph above.

Steps Required to Install on Another Server

CAS server is packaged as a self-contained Web application archive (war file). Maven 2 is used to package this war file. For convenience, build.bat can be used to build the war file. The war file contains all the CAS configuration files, including two that will need to be changed when deploying second-level CAS to a different application server: web.xml and deployerConfigContext.xml. Example fragments of these files are included above. web.xml will need to be changed to point to the correct primary CAS server and to correctly identify the location of the second-level CAS. deployerConfigContext.xml will need to be updated with correct LDAP server address and credentials to perform LDAP searches.

Powered by a free Atlassian Confluence Open Source Project License granted to Java Architectures Special Interest Group. Evaluate Confluence today.
Powered by Atlassian Confluence 2.7.3, the Enterprise Wiki. Bug/feature request - Atlassian news - Contact administrators