Using the REMOTE_USER
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.