Enterprise Single Sign-On for All

Overview

CAS can be integrated with the Shibboleth federated SSO platform by a couple different strategies. It is possible to designate CAS to serve as the authentication provider for the Shibboleth IdP. With such a setup, when user is routed to the IdP, the following may take place:

  • If the user has already authenticated to CAS and has a valid CAS SSO session, the IdP will transparently perform the requested action, e.g. attribute release.
  • If the user does not have a valid CAS SSO session, the user will be redirected to CAS and must authenticate before the IDP proceeds with the requested action.

SSO for Shibboleth IdP (External)

This is a Shibboleth IdP external authentication plugin that delegates the authentication to CAS. The advantage of using this component over the plain RemoteUser solution is the ability to utilize a full range of native CAS protocol features such as renew and gateway.

The plugin is available for both Shibboleth Identity Provider v2 and v3.

SSO for Shibboleth IdP (RemoteUser)

Configuration

Note that the below instructions apply only to Shibboleth IdP v2.x.

Include CAS Client Libraries in IdP Deployable

Download the latest Java CAS Client Release and modify the IdP war deployable such that the following jars are included in the ./lib installer folder, then redeploy the Idp with these files:

1
cas-client-$VERSION/modules/cas-client-core-$VERSION.jar

Modify $SHIB_HOME/conf/handler.xml

Define the RemoteUser authentication method to be used with CAS authentication.

1
2
3
4
5
6
7
8
9
<!-- Remote User handler for CAS support -->
<LoginHandler xsi:type="RemoteUser">
  <AuthenticationMethod>
    urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified
  </AuthenticationMethod>
  <AuthenticationMethod>
    urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
  </AuthenticationMethod>
</LoginHandler>

Modify IdP Deployable web.xml

Add the following XML blocks to the web.xml file for the IdP war deployable.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<!-- For CAS client support -->
<context-param>
  <param-name>serverName</param-name>
  <param-value>${idp.hostname}</param-value>
</context-param>
CAS Filters
<!-- CAS client 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>${cas.server.url}login</param-value>
  </init-param>
</filter>

<filter-mapping>
  <filter-name>CAS Authentication Filter</filter-name>
  <url-pattern>/Authn/RemoteUser</url-pattern>
</filter-mapping>

<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>${cas.server.url}</param-value>
  </init-param>
  <init-param>
    <param-name>redirectAfterValidation</param-name>
    <param-value>true</param-value>
  </init-param>
</filter>

<filter-mapping>
  <filter-name>CAS Validation Filter</filter-name>
  <url-pattern>/Authn/RemoteUser</url-pattern>
</filter-mapping>

<filter>
  <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
  <filter-class>
    org.jasig.cas.client.util.HttpServletRequestWrapperFilter
  </filter-class>
</filter>

<filter-mapping>
  <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
  <url-pattern>/Authn/RemoteUser</url-pattern>
</filter-mapping>

Enable RemoteUserHandler in Idp Deployable web.xml

Ensure the following is defined:

1
2
3
4
5
6
7
8
9
10
<!-- Servlet protected by container user for RemoteUser authentication -->
<servlet>
  <servlet-name>RemoteUserAuthHandler</servlet-name>
  <servlet-class>edu.internet2.middleware.shibboleth.idp.authn.provider.RemoteUserAuthServlet</servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>RemoteUserAuthHandler</servlet-name>
  <url-pattern>/Authn/RemoteUser</url-pattern>
</servlet-mapping>

Relying Party EntityId

The authentication plugin is able to pass the relying party’s entity ID over to the CAS server upon authentication requests. The entity ID is passed in form of a url parameter to the CAS server as such:

1
https://sso.example.org/cas/login?service=<authentication-plugin-url>&entityId=<relying-party-entity-id>

Displaying SAML MDUI

The CAS server is able to recognize the entityId parameter and display SAML MDUI on the login page, that is provided by the metadata associated with the relying party. This means that CAS will also need to know about metadata sources that the identity provider uses.

Configuration

Support is enabled by including the following dependency in the Maven WAR overlay:

1
2
3
4
5
<dependency>
  <groupId>org.jasig.cas</groupId>
  <artifactId>cas-server-support-saml-mdui</artifactId>
  <version>${cas.version}</version>
</dependency>

Then, adjust deployerConfigContext.xml with the following:

1
2
3
4
<bean id="samlMetadataUIParserAction"
  class="org.jasig.cas.support.saml.web.flow.mdui.SamlMetadataUIParserAction"
  c:entityIdParameterName="entityId"
  c:metadataAdapter-ref="metadataAdapter"/>

Metadata sources in the CAS server can be configured via the following ways:

Static

In this case, metadata sources are statically provided via classpath, file or url resources.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<bean id="metadataAdapter"
      class="org.jasig.cas.support.saml.web.flow.mdui.StaticMetadataResolverAdapter"
      c:metadataResources-ref="metadataResources"
      p:refreshIntervalInMinutes="300"
      p:requireValidMetadata="true" />

<util:map id="metadataResources">
    <entry key="classpath:/sample-metadata.xml">
        <bean class="org.opensaml.saml.metadata.resolver.filter.impl.MetadataFilterChain">
            <property name="filters">
                <list />
            </property>
        </bean>
    </entry>
</util:map>

Dynamic

In this case, metadata sources are provided via the Metadata Query Protocol, which is a REST-like API for requesting and receiving arbitrary metadata. CAS will contact the metadata server to query for the metadata based on the entityId provided.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<bean id="metadataAdapter"
      class="org.jasig.cas.support.saml.web.flow.mdui.DynamicMetadataResolverAdapter"
      c:metadataResources-ref="metadataResources"
      p:refreshIntervalInMinutes="300"
      p:requireValidMetadata="true" />

<util:map id="metadataResources">
  <entry key="http://<metadata.queryserver.org>/entities/">
    <bean class="org.opensaml.saml.metadata.resolver.filter.impl.MetadataFilterChain">
        <property name="filters">
            <list />
        </property>
    </bean>
  </entry>
</util:map>

Configure Metadata Filters

Metadata filters can be configured to validate and verify the received metadata in both scenarios. Filters typically check for validity of signaures, whether validUntil exists, etc. The following example attempts to validate the signature on the metadata via a pre-configured public key:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<bean id="metadataFilters"
    class="org.opensaml.saml.metadata.resolver.filter.impl.MetadataFilterChain">
    <property name="filters">
        <list>
            <!--
            <bean class="org.opensaml.saml.metadata.resolver.filter.impl.RequiredValidUntilFilter"
                  c:maxValidity="0"  />
            -->
            <bean class="org.opensaml.saml.metadata.resolver.filter.impl.SignatureValidationFilter"
                  c:engine-ref="trustEngine" p:requireSignature="false"  />
        </list>
    </property>
</bean>

<bean id="trustEngine"
    class="org.opensaml.xmlsec.signature.support.impl.ExplicitKeySignatureTrustEngine"
        c:keyInfoResolver-ref="keyInfoResolver"
        c:resolver-ref="credentialResolver" />

<bean id="keyInfoResolver"
  class="org.opensaml.xmlsec.keyinfo.impl.BasicProviderKeyInfoCredentialResolver">
    <constructor-arg name="keyInfoProviders">
        <list>
            <bean class="org.opensaml.xmlsec.keyinfo.impl.provider.RSAKeyValueProvider" />
            <bean class="org.opensaml.xmlsec.keyinfo.impl.provider.DSAKeyValueProvider" />
            <bean class="org.opensaml.xmlsec.keyinfo.impl.provider.DEREncodedKeyValueProvider" />
            <bean class="org.opensaml.xmlsec.keyinfo.impl.provider.InlineX509DataProvider" />
        </list>
    </constructor-arg>
</bean>

<bean id="credentialResolver"
  class="org.opensaml.security.credential.impl.StaticCredentialResolver"
      c:credential-ref="credentialFactoryBean" />

<bean id="credentialFactoryBean"
      class="net.shibboleth.idp.profile.spring.relyingparty.security.credential.BasicResourceCredentialFactoryBean"
      p:publicKeyInfo="classpath:inc-md-pub.pem" >
</bean>

You will need to modify your metadata retrieval process, whether static or dynamic, to adjust for the appropriate metadata filter if need be.

Display MDUI

Modify the login-webflow.xml to execute the SamlMetadataUIParserAction action when the login form is rendered:

1
2
3
4
5
6
7
8
9
<view-state id="viewLoginForm" ...>
    ...
    <on-entry>
        ...
        <evaluate expression="samlMetadataUIParserAction" />
        ...
    </on-entry>
    ...
</view-state>

A sample screenshot of the above configuration in action:

capture

Shibboleth Service Provider Proxy

The CASShib project “Shibbolizes” the CAS server and enables end applications to get authentication information from CAS rather than the Shibboleth Service Provider. CASShib is designed as an alternative to deploying the Shibboleth service provider for each application in order to:

  • Leverage Shibboleth’s sophisticated attribute release policy functionality to enable attribute releasing to services in the local environment.
  • Offer the chance for local applications to easily become federated services.