Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Warning
titleNew 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.

Tip

Since CAS version 4.0, in addition to this server support, a new OpenID client support is available in the CAS server through the cas-server-support-pac4j module. It means that the CAS authentication can be delegated to www.myopenid.com.

 

OpenID is an open, decentralized, free framework for user-centric digital identity. Users represent themselves using URIs. For more information see the http://www.openid.net. As of CAS 3.15, CAS supports both the "dumb" and "smart" mode modes of the OpenID protocol. Dumb mode acts in a similar fashion to the existing CAS protocol. The smart mode differs in that it establishes an association between the client and the openId provider (OP) at the begining. Thanks to that association and the key exchange done during association, information exchanged between the client and the provider are signed and verified using this key. There is no need for the final request (which is equivalent in CAS protocol to the ticket validation).

Enabling OpenID Support in the Build

To enable OpenID in your build, edit the pom.xml in the cas-server-webapp module. Add the following entry:

...

A demo of the OpenId support in CAS server is available at : https://github.com/leleuj/cas-openid-demo.

Giving your users URIs

Configuring your users to have URIs.

OpenId identifiers are URIs. The default mechanism in CAS support is an uri ending with the actual user login (ie. http://my.cas.server/openid/fesnault where the actual user login is fesnault). This is not recommended and you should think of a more elaborated way of providing URIs to your users.

Add OpenId support module to CAS server

The first thing, with a CAS server webapp, is to add the OpenId support module dependency. This is done by adding this in the cas server webapp pom.xml.

Code Block
languagehtml/xml
<dependency>
    <groupId>org.jasig.cas</groupId>
    	<artifactId>cas-server-support-openid</artifactId>
	    <version>${project.version}</version>
</dependency>

Giving your users URIs

Configuring your users to have URIs.

You'll need to set up a local mechanism for generating URIs for your users based on their username (i.e. http://openid.rutgers.edu/battags).

The endpoint pages look something like this:

...


<html>
	<head>
		<link rel="openid.server" href="https://localhost/cas/login" />
	</head>
</html>

Enabling OpenID in CAS

Note: We're assuming you are using the Default AuthenticationManager.

Modifying the deployerConfigContext.xml

Open your deployerConfigContext.xml and add the following entries:

Add a new AuthenticationHandler to your AuthenticationManager

Code Block
xmlxml

Warning
titleBe Careful

You must change the server prefix property of the cas server to an https url. Otherwise SSO will not work. Find the cas.properties file and edit the server.prefix url to something like this : https://localhost:443/cas.

Now let's dive into CAS configuration itself.

Declare the OpenID endpoint (since CAS 4.0)

Since CAS 4.0, the OpenID endpoint for discovery is no more enabled by default in the CAS server (in fact, it is no more available in the cas-server-support-webapp module : it has been moved to the cas-server-support-openid module).

The OpenID discovery endpoint should be enabled during the configuration process. In the web.xml file, the following mapping must be added :

Code Block
languagehtml/xml
titleweb.xml
  <servlet-mapping>
    <servlet-name>cas</servlet-name>
    <url-pattern>/openid/*</url-pattern>
  </servlet-mapping>

In the cas-servlet.xml file, the following mapping and bean must be added :

Code Block
languagehtml/xml
titlecas-servlet.xml
  <bean id="handlerMappingC" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
      <props>
        <prop key="/logout">logoutController</prop>
        ...
        <prop key="/openid/*">openIdProviderController</prop>
        ...


 
  <bean
      id="openIdProviderController"
      class="org.jasig.cas.support.openid.web.OpenIdProviderController"
      p:loginUrl="${server.prefix}/login"/>

Add the OpenID entry in the unique id generator map (since CAS 4.0)

Since CAS 4.0, the OpenID entry in the unique id generator map is no more defined by default in the CAS server.

The OpenID entry should be added to the uniqueIdGenerators.xml file :

Code Block
languagehtml/xml
titleweb.xml
<util:map id="uniqueIdGeneratorsMap">
  ...
  <entry
    key="org.jasig.cas.support.openid.authentication.principal.OpenIdService"
    value-ref="serviceTicketUniqueIdGenerator" />
</util:map>

Update webflow

CAS uses a spring webflow to describe the the authentication process. We need to change it a little bit to allow CAS to switch to OpenId authentication if it recognizes one. This is done in the login-webflow.xml fie. After the on-start element just add these two blocks :

Code Block
languagehtml/xml
  <!-- If the request contains a parameter called openid.mode and is not an association request, switch to openId. Otherwise, continue normal webflow. -->
  <decision-state id="selectFirstAction">
      <if
         test="externalContext.requestParameterMap['openid.mode'] neq ''
          &amp;&amp; externalContext.requestParameterMap['openid.mode'] neq null
          &amp;&amp; externalContext.requestParameterMap['openid.mode'] neq 'associate'"
         then="openIdSingleSignOnAction" else="ticketGrantingTicketExistsCheck" />
  </decision-state>
		
  <!-- The OpenID authentication action. If authentication is successful, send the ticket granting ticker. Otherwise, redirect to the login form. -->
  <action-state id="openIdSingleSignOnAction">
      <evaluate expression="openIdSingleSignOnAction" />
      <transition on="success" to="sendTicketGrantingTicket" />
      <transition on="error" to="viewLoginForm" />
      <transition on="warn" to="warn" />
  </action-state>

 

Enable OpenId in the AuthenticationManager

The authentication manager is the place where authentication takes place. We must provide it two elements needed for a successful OpenId authentication. The first thing to do is to detect the user name from the OpenId identifier. When your CAS server will work as an OP, users will authenticate with an OpenId identifier, looking like this : http://localhost:8080/cas/openid/fesnault. Actually, in your users database, this users login is probably fesnault. We must provide the CAS server with a way to extract the user principal from the credentials he provides us. This is the first thing we'll do in this section : add an OpenIdCredentialsToPrincipalResolver to the authentication manager. The next thing to give CAS is a specialized authentication handler.

Open the deployerConfigContext.xml file, and locate the authenticationManager bean definition. It has two properties containing beans. The credentials to principal property, add this bean definition :

Code Block
languagehtml/xml
     <!-- The openid credentials to principal resolver -->
     <bean class="org.jasig.cas.support.openid.authentication.handlerprincipal.support.OpenIdCredentialsAuthenticationHandlerOpenIdCredentialsToPrincipalResolver"    p:ticketRegistry-ref="ticketRegistry" />

...

Then, in the authentication handler property, add this bean definition :

Code Block
xml
languagehtml/xml
     <!-- The open id authentication handler -->
     <bean class="org.jasig.cas.support.openid.authentication.principalhandler.support.OpenIdCredentialsAuthenticationHandler" p:ticketRegistry-ref="ticketRegistry" />

 

...

Adapt the

...

Add the Url Mapping Handler

Add the following entry to your cas-servlet.xml (it can go anywhere):

...

Spring CAS servlet configuration

We now have to make CAS handle nicely the OpenId request he will be presented with. First, we'll add a handler for the /login url, when called to validate a ticket (CAS is implementing the dumb OpenId mode, which means it does not create an association at the beginning of the authentication process. It must then check the received authentication success notification, which is done by one extra HTTP request at the end of the process). Anywhere in the cas-servlet.xml file, add this bean definition :

 

Code Block
languagehtml/xml
    <bean id="handlerMappingA" handlerMappingOpendId"
          class="org.jasig.cas.support.openid.web.support.OpenIdPostUrlHandlerMapping">
	<property
		        <!-- Notice we set the order value to 2, which is the order of the flow handler mapping. We'll fix that just next.
        The OpenIDPostUrlHandlerMapping MUST be called before the login webflow action is called, otherwise we will never be able to validate the authentication success. -->
        <property name="order" value="2"/>
        <property name="mappings">
		<props>
			<prop
				
            <props>
                <prop key="/login">openIdValidateController<>delegatingController</prop>
		
            </props>
	
        </property>
    </bean>

As we gave the order of 2 to the OpenIdPostUrlHandlerMapping, we must modify the FlowHandlerMapping order to give it the order of 3. Find the FlowHandlerMapping bean declaration and change the p:order="2"' to p:order="3".

Code Block
languagehtml/xml
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping" p:flowRegistry-ref="flowRegistry"
  

This will direct validation requests to the correct controller.

OpenId Validation Controller

Add the following to enable validation of an OpenID request:

Code Block
xmlxml

	 p:order="3">

 

In the handlerMappingOpenId, we referenced a bean called delegatingController. this bean is a special controller, using the Delegate pattern, which delegates the processing of a request to the first controller of its delegates which says it can handle it. So now we'll provide two delegate controllers. The first one is handling the Smart OpenId association, and the second process the authentication and ticket validation. Add this two beans in the file.

The Smart OpenId controller :

Code Block
languagehtml/xml
   <bean id="smartOpenIdAssociationController" class="org.jasig.cas.support.openid.web.mvc.SmartOpenIdController"
        p:serverManager-ref="serverManager"
        p:successView="casOpenIdAssociationSuccessView" p:failureView="casOpenIdAssociationFailureView" />

The OpenId validation controller :

Code Block
languagehtml/xml
   <bean id="openIdValidateController" class="org.jasig.cas.web.ServiceValidateController"
		
          p:validationSpecificationClass="org.jasig.cas.validation.Cas20WithoutProxyingValidationSpecification"
		
          p:centralAuthenticationService-ref="centralAuthenticationService"
		          p:proxyHandler-ref="proxy20Handler" 		p:argumentExtractor-ref="openIdArgumentExtractor"
		          p:successView="casOpenIdServiceSuccessView" 		p:failureView="casOpenIdServiceFailureView" />

ArgumentExtractor

Next, we need to add the ArgumentExtractor that can actually detect the OpenID request:

Code Block
xmlxml

<bean
	id="openIdArgumentExtractor"
	

We are done with the delegates. Now we must create the Delegating controller itself, and give it a list of delegates referencing the two delegates we just defined. So add this definition :

 

Code Block
languagehtml/xml
   <bean id="delegatingController" class="org.jasig.cas.support.openid.web.support.OpenIdArgumentExtractorDelegatingController"
  />

Then, locate the <util:list> entry in the cas-servlet.xml and add a:

...


<ref bean="openIdArgumentExtractor" />

It should look something like this (it will vary depending on what is enabled):

Code Block
xmlxml

<util  p:delegates-ref="delegateControllers"/>
  
   <util:list id="argumentExtractorsdelegateControllers">
	
        <ref bean="casArgumentExtractorsmartOpenIdAssociationController" />
  	<ref bean="samlArgumentExtractor" />
	      <ref bean="openIdArgumentExtractoropenIdValidateController" />
    </util:list>

Add the Action for the Web Flow

...

Also, add the indicated lines to the <beans> definition at the top of the file, if they're not already there:

Code Block
xml
languagehtml/xml
<beans xmlns="http://www.springframework.org/schema/beans"
       ...
     <bean  idxmlns:util="openIdSingleSignOnAction" class="org.jasig.cas.support.openid.web.flow.OpenIdSingleSignOnAction"
    	p:centralAuthenticationService-ref="centralAuthenticationService" />
Note
titleBe Careful
The OpenIdSingleSignOnAction has an additional parameter not configured here. Its the "extractor" property which accepts a
http://www.springframework.org/schema/util"
       xsi:schemaLocation="...
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
       ...">

 

Next, we'll give CAS a handler for the OpenIdSingleSignOnAction we added in the spring webflow definition file. So add this bean definition anywhere :

Code Block
languagehtml/xml
Code Block
xml
     <!-- Be Careful
         The OpenIdSingleSignOnAction has an additional parameter not configured here.
         Its the "extractor" property which accepts a "org.jasig.cas.support.openid.web.support.OpenIdUserNameExtractor".
         The default one merely accepts the value after the last "/".
         A more robust implementation should check the entire URL. Note, that means the default one SHOULD NOT be used in production.

login-webflow.xml

Add the following action to your login-webflow.xml


     -->
 
    <bean id="openIdSingleSignOnAction" class="org.jasig.cas.support.openid.web.flow.OpenIdSingleSignOnAction"
          p:centralAuthenticationService-ref="centralAuthenticationService"/>

Add an argument extractor

Finally, we must tell cas how to extract the OpenId from the authentication request (openid.mode, openid.sig, openid.assoc_handle...). This is done in the argumentExtractorsConfiguration.xml file, located in the spring-configuration directory. Add this bean into the file :

Code Block
     <bean id="openIdArgumentExtractor" class="org.jasig.cas.support.openid.web.support.OpenIdArgumentExtractor" />

 

Then add a reference to this bean into the arguments extractors list, just below in the file :

Code Block
languagehtml/xml
     <action-state<util:list id="openIdSingleSignOnActionargumentExtractors">
    	<action    <ref bean="openIdSingleSignOnActioncasArgumentExtractor" />
        <!-- The 	<transition on="success" to="sendTicketGrantingTicket" />OpenId arguments extractor -->
      	<transition on="error" to  <ref bean="ticketGrantingTicketExistsCheckopenIdArgumentExtractor" />
       	<transition on="warn" to <ref bean="warnsamlArgumentExtractor" />
     </action-state>

You'll want to modify your InitialFlowAction's "success" event to go to "openIdSingleSignOnAction"

Modify the login view

Instead of the normal NetId login field, any CAS instance that accepts OpenID credentials needs to be able to not accept a Username (as its provided by the OpenID protocol). This can be accomplished with the following snippit of code on the login JSP page:

Code Block
xmlxml

<c:if test="${not empty sessionScope.openIdLocalId}">
	<strong>${sessionScope.openIdLocalId}</strong>
	<input type="hidden" id="username" name="username" value="${sessionScope.openIdLocalId}" />
</c:if>
					
<c:if test="${empty sessionScope.openIdLocalId}">
	<input class="required" id="username" name="username" size="32" tabindex="1" accesskey="<spring:message code="screen.welcome.label.netid.accesskey" />" />
</c:if>
util:list>

 

Next we must provide a ServerManager, which is a class from the openid4java library, which allows us to handle the Diffie-Hellman algorithm used by the association process. In the spring-configuration/applicationContext.xml file, add this bean definition :

Code Block
languagehtml/xml
<bean id="serverManager" class="org.openid4java.server.ServerManager"
          p:oPEndpointUrl="${cas.securityContext.casProcessingFilterEntryPoint.loginUrl}"
          p:enforceRpId="false"  />

And finally, we need an applicationContext provider , so add this bean into spring-configuration/applicationContext.xml :

Code Block
languagehtml/xml
<bean id="applicationContextProvider" class="org.jasig.cas.util.ApplicationContextProvider" />

You're done ! CAS is now configured to work as an OpenId Provider.