This page describe how to use credentials other than [UsernamePasswordCredentials] with CAS 3.
Use case
Suppose that your Apache environment or a JAAS realm or a Java Servlet Filter set the REMOTE_USER with the authenticated user before the request even gets to CAS.
How would we configure CAS 3 to consume that remote user field?
Implementation
Java code
Credentials
We need some Credentials that bear an already resolved Principal:
package org.jasig.cas.adaptors.generic; import org.jasig.cas.authentication.principal.Credentials; import org.jasig.cas.authentication.principal.Principal; /** * Credentials that bear the fully resolved and authenticated Principal. * * These Credentials are a mechanism to pass into CAS information about an * authentication and Principal resolution that has already happened in layers * in front of CAS, e.g. by means of a Java Servlet Filter. * * DO NOT accept these Credentials from arbitrary web-servicy calls to CAS. * Rather, the code constructing these Credentials must be trusted. */ public class PrincipalBearingCredentials implements Credentials { private Principal principal; public Principal getPrincipal(){ return this.principal; } public void setPrincipal(Principal principal) { this.principal = principal; } }
Extracting the REMOTE_USER into the Credentials
We need a [CredentialsBinder] to extract the remote user into a [Principal] that we can store into our [Credentials].
/** * Extracts the remote user from the request into the PrincipalBearingCredentials. * @version $Revision:$ $Date:$ */ public class RemoteUserCredentialsBinder implements CredentialsBinder { public void bind(HttpServletRequest request, Credentials credentials) { String remoteUser = request.getRemoteUser(); SimplePrincipal principal = new SimplePrincipal(remoteUser); ((PrincipalBearingCredentials) credentials).setPrincipal(principal); } public boolean supports(Class clazz) { return PrincipalBearingCredentials.class.equals(clazz); } }
AuthenticationHandler
We need an AuthenticationHandler that will approve authentication of our dummy credentials
/** * AuthenticationHandler which authenticates Principal-bearing credentials. * Authentication must have occured at the time the Principal-bearing credentials * were created, so we perform no further authentication. * */ public class PrincipalBearingCredentialsAuthnHandler implements AuthenticationHandler { public boolean authenticate(Credentials credentials) throws AuthenticationException { // we're assuming supports() was called and we supported the // credentials, so they must be PrincipalBearingCredentials. return true; } public boolean supports(Credentials credentials) { return credentials instanceof PrincipalBearingCredentials; } }
CredentialsToPrincipalResolver
We need a CredentialsToPrincipalResolver to extract the Principal out of the Credentials.
package org.jasig.cas.adaptors.generic; import org.jasig.cas.authentication.principal.Credentials; import org.jasig.cas.authentication.principal.CredentialsToPrincipalResolver; import org.jasig.cas.authentication.principal.Principal; /** * Extracts the Principal out of PrincipalBearingCredentials. */ public class PrincipalBearingCredentialsToPrincipalResolver implements CredentialsToPrincipalResolver { public Principal resolvePrincipal(Credentials credentials) { return ((PrincipalBearingCredentials) credentials).getPrincipal(); } public boolean supports(Credentials credentials) { return credentials instanceof PrincipalBearingCredentials; } }
Wiring
Now that we have the necessary Java class implementations, we need to wire them in.
deployerConfigContext.xml
Declare the authentication handler:
<property name="authenticationHandlers"> <list> <bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler" /> <bean class="org.jasig.cas.adaptors.generic.PrincipalBearingCredentialsAuthnHandler" /> </list> </property>
And declare our CredentialsToPrincipalResolver:
<property name="credentialsToPrincipalResolvers"> <list> <bean class="org.jasig.cas.authentication.principal.PrincipalBearingCredentialsToPrincipalResolver" /> <bean class="org.jasig.cas.authentication.principal.HttpBasedServiceCredentialsToPrincipalResolver" /> </list> </property>
cas-servlet.xml
Declare our Credentials class and our CredentialsBinder in configuring the Login Form Action in cas-servlet.xml
<bean
id="loginFormAction"
class="org.jasig.cas.web.flow.LoginFormAction">
<property
name="centralAuthenticationService"
ref="centralAuthenticationService" />
<property
name="credentialsBinder">
<bean
class="org.jasig.cas.adaptors.generic.RemoteUserCredentialsBinder"/>
</property>
<property
name="formObjectClass"
value="org.jasig.cas.adaptors.generic.PrincipalBearingCredentials" />
</bean>
Demonstrating
One way to set the REMOTE_USER is to use the CASFilter. We can front our CAS 3 instance with our existing CAS 2 instance.
Declaring the CASFilter
<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://secure.its.yale.edu/cas/login</param-value> </init-param> <init-param> <param-name>edu.yale.its.tp.cas.client.filter.validateUrl</param-name> <param-value>https://secure.its.yale.edu/cas/serviceValidate</param-value> </init-param> <init-param> <param-name>edu.yale.its.tp.cas.client.filter.serverName</param-name> <param-value>hkg2.cis.yale.edu:8080</param-value> </init-param> <init-param> <param-name>edu.yale.its.tp.cas.client.filter.wrapRequest</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CAS Validate Filter</filter-name> <url-pattern>/login</url-pattern> </filter-mapping>
Removing the username and password fields from the UI
And we need an alternative login.jsp without the username and password fields:
<%@ page session="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<!-- $Id: casLoginView.jsp,v 1.10 2005/05/24 18:57:18 sbattaglia Exp $ -->
<!-- DOCUMENT TITLE: CHANGE TO NEW TITLE -->
<title>JA-SIG Central Authentication Service (CAS)</title>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<!-- KEYWORDS AND DESCRIPTIONS GO INTO THIS SECTION -->
<meta name="keywords" content="Central Authentication Service,JA-SIG,CAS" />
<meta name="description" content="The login page for the JA-SIG Central Authentication Service" />
<meta name="author" content="Bart Grebowiec, Scott Battaglia" />
<!-- THIS CODE PROVIDES THE FORMATTING FOR THE TEXT - PLEASE LEAVE INTACT -->
<link rel="stylesheet" href="<spring:theme code="css" />" type="text/css" media="all" />
<script src="js/common.js" type="text/javascript"></script>
</head>
<body onload="init();">
<!-- HEADER -->
<div id="header">
<a id="top">Java Architecture Special Interest Group</a>
<h1>JA-SIG Central Authentication Service</h1>
</div>
<!-- END HEADER -->
<!-- CONTENT -->
<div id="content">
<div class="dataset clear" style="position: relative;">
<h2 style="margin-bottom:0;">Please Log In</h2>
<p style="margin-top:-.5em;border:1px solid #ccc;background-color:#ffc;color:#000;padding:5px;">
Congratulations on bringing CAS online!
We've fronted this CAS 3 instance with authentication to CAS 2. <br />
</p>
<form method="post" action="">
<p><input style="width:1.5em;border:0;padding:0;margin:0;"
type="checkbox" id="warn" name="warn" value="true" tabindex="3" />
<label for="warn" accesskey="w">
<span class="accesskey">W</span>arn me before logging me into other sites.</label></p>
<input type="hidden" name="lt" value="${flowExecutionId}" />
<input type="hidden" name="_currentStateId" value="${currentStateId}" />
<input type="hidden" name="_eventId" value="submit" />
<p><input type="submit"
class="button" accesskey="l" value="LOGIN" tabindex="4" /></p>
</div>
</div>
</fieldset>
</form>
</div>
</div><!-- END CONTENT -->
<!-- FOOTER -->
<div id="footer">
<hr />
<p style="margin-top:1em;">
Copyright © 2005 JA-SIG. All rights reserved.
</p>
</div>
<!-- END FOOTER -->
</body>
</html>
Trying it out
Visit the CAS server explicitly specifying the /login on the path. You will CAS (2) authenticate and then be able to submit the CAS 3 login form. Specify a service and you'll get a ST which validates to authenticate your CAS 2 NetID.
