SAML2 Authentication

CAS can act as a SAML2 identity provider accepting authentication requests and producing SAML assertions.

If you intend to allow CAS to delegate authentication to an external SAML2 identity provider, you need to review this guide.

SAML Specification

This document solely focuses on what one might do to turn on SAML2 support inside CAS. It is not to describe/explain the numerous characteristics of the SAML2 protocol itself. If you are unsure about the concepts referred to on this page, please start with reviewing the SAML2 Specification.

Federation Interop Evaluation

The CAS project strives to conform to the SAML V2.0 Implementation Profile for Federation Interoperability. An evaluation of the requirements against the current CAS release is available here. It is recommended that you view, evaluate and comment on functionality that is currently either absent or marked questionable where verification is needed.

SAML Endpoints

The following CAS endpoints respond to supported SAML2 profiles:

  • /idp/profile/SAML2/Redirect/SSO
  • /idp/profile/SAML2/POST/SSO
  • /idp/profile/SAML2/POST-SimpleSign/SSO
  • /idp/profile/SAML2/POST/SLO
  • /idp/profile/SAML2/Redirect/SLO
  • /idp/profile/SAML2/Unsolicited/SSO
  • /idp/profile/SAML2/SOAP/ECP
  • /idp/profile/SAML2/SOAP/AttributeQuery
  • /idp/profile/SAML1/SOAP/ArtifactResolution

Unsolicited SSO

SAML2 IdP Unsolicited/SSO profile supports the following parameters:

Parameter Description
providerId Required. Entity ID of the service provider.
shire Optional. Response location (ACS URL) of the service provider.
target Optional. Relay state.
time Optional. Skew the authentication request.

Attribute Queries

In order to allow CAS to support and respond to attribute queries, you need to make sure the generated metadata has the AttributeAuthorityDescriptor element enabled, with protocol support enabled for urn:oasis:names:tc:SAML:2.0:protocol and relevant binding that corresponds to the CAS endpoint(s). You also must ensure the AttributeAuthorityDescriptor tag lists all KeyDescriptor elements and certificates that are used for signing as well as authentication, specially if the SOAP client of the service provider needs to cross-compare the certificate behind the CAS endpoint with what is defined for the AttributeAuthorityDescriptor. CAS by default will always use its own signing certificate for signing of the responses generated as a result of an attribute query.

Also note that support for attribute queries need to be explicitly enabled and the behavior is off by default, given it imposes a burden on CAS and the underlying ticket registry to keep track of attributes and responses as tickets and have them be later used and looked up.

To see the relevant list of CAS properties, please review this guide.

IdP Metadata

The following CAS endpoints handle the generation of SAML2 metadata:

  • /idp/metadata

This endpoint will display the CAS IdP SAML2 metadata upon receiving a GET request. If metadata is already available and generated, it will be displayed. If metadata is absent, one will be generated automatically. CAS configuration below dictates where metadata files/keys will be generated and stored.

Here is a generated metadata file as an example:

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
<?xml version="1.0" encoding="UTF-8"?>
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
                xmlns:shibmd="urn:mace:shibboleth:metadata:1.0" xmlns:xml="http://www.w3.org/XML/1998/namespace"
                xmlns:mdui="urn:oasis:names:tc:SAML:metadata:ui" entityID="ENTITY_ID">
    <IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
        <Extensions>
            <shibmd:Scope regexp="false">SCOPE</shibmd:Scope>
        </Extensions>
        <KeyDescriptor use="signing">
            <ds:KeyInfo>
              <ds:X509Data>
                  <ds:X509Certificate>...</ds:X509Certificate>
              </ds:X509Data>
            </ds:KeyInfo>
        </KeyDescriptor>
        <KeyDescriptor use="encryption">
            <ds:KeyInfo>
              <ds:X509Data>
                  <ds:X509Certificate>...</ds:X509Certificate>
              </ds:X509Data>
            </ds:KeyInfo>
        </KeyDescriptor>

        <NameIDFormat>urn:mace:shibboleth:1.0:nameIdentifier</NameIDFormat>
        <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>

        <SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
                             Location="https://HOST_NAME/cas/idp/profile/SAML2/POST/SLO"/>
        <SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
                             Location="https://HOST_NAME/cas/idp/profile/SAML2/POST/SSO"/>
        <SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
                             Location="https://HOST_NAME/cas/idp/profile/SAML2/Redirect/SSO"/>
    </IDPSSODescriptor>
</EntityDescriptor>

Server Configuration

Server Configuration

If you have deployed CAS in an external application server/servlet container (i.e. Apache Tomcat) you will need to make sure that the server is adjusted to handle large-enough HttpHeaderSize and HttpPostSize values (i.e. 2097152). The embedded container that ships with CAS handles this automatically.

Mapping Endpoints

Note that CAS metadata endpoints for various bindings are typically available under /cas/idp/.... If you mean you use an existing metadata file whose binding endpoints begin with /idp/..., you may need to deploy CAS at the root context path so it’s able to respond to those requests. (i.e. https://sso.example.org/cas/login becomes https://sso.example.org/login). Alternatively, you may try to use URL-rewriting route requests from /idp/ to /cas/idp/,etc.

SP Metadata

If the SP you wish to integrate with does not produce SAML metadata, you may be able to use this service to create the metadata, save it in an XML file and then reference and register it with CAS for the SP.

Configuration

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

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

You may also need to declare the following Maven repository in your CAS overlay to be able to resolve dependencies:

1
2
3
4
5
6
7
8
<repositories>
    ...
    <repository>
        <id>shibboleth-releases</id>
        <url>https://build.shibboleth.net/nexus/content/repositories/releases</url>
    </repository>
    ...
</repositories>

To see the relevant list of CAS properties, please review this guide.

SAML Services

SAML relying parties and services must be registered within the CAS service registry similar to the following example:

1
2
3
4
5
6
7
8
{
  "@class" : "org.apereo.cas.support.saml.services.SamlRegisteredService",
  "serviceId" : "the-entity-id-of-the-sp",
  "name" : "SAMLService",
  "id" : 10000003,
  "evaluationOrder" : 10,
  "metadataLocation" : "http://www.testshib.org/metadata/testshib-providers.xml"
}

The following fields are available for SAML services:

Field Description
metadataLocation Location of service metadata defined from system files, classpath, directories or URL resources.
metadataSignatureLocation Location of the metadata signing certificate/public key to validate the metadata which must be defined from system files or classpath. If defined, will enforce the SignatureValidationFilter validation filter on metadata.
metadataExpirationDuration If defined, will expire metadata in the cache after the indicated duration which will force CAS to retrieve and resolve the metadata again.
signAssertions Whether assertions should be signed. Default is false.
signResponses Whether responses should be signed. Default is true.
encryptAssertions Whether assertions should be encrypted. Default is false.
requiredAuthenticationContextClass If defined, will specify the SAML authentication context class in the final response. If undefined, the authentication class will either be urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified or urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport depending on the SAML authentication request.
requiredNameIdFormat If defined, will force the indicated Name ID format in the final SAML response.
metadataCriteriaPattern If defined, will force an entity id filter on the metadata aggregate based on the PredicateFilter to include/exclude specific entity ids based on a valid regex pattern.
metadataCriteriaDirection If defined, will force an entity id filter on the metadata aggregate based on PredicateFilter. Allowed values are INCLUDE,EXCLUDE.
metadataCriteriaRoles If defined, will whitelist the defined metadata roles (i.e. SPSSODescriptor, IDPSSODescriptor). Default is SPSSODescriptor.
metadataCriteriaRemoveEmptyEntitiesDescriptors Controls whether to keep entities descriptors that contain no entity descriptors. Default is true.
metadataCriteriaRemoveRolelessEntityDescriptors Controls whether to keep entity descriptors that contain no roles. Default is true.
attributeNameFormats Map that defines attribute name formats for a given attribute name to be encoded in the SAML response.
nameIdQualifier If defined, will overwrite the NameQualifier attribute of the produced subject’s name id.
serviceProviderNameIdQualifier If defined, will overwrite the SPNameQualifier attribute of the produced subject’s name id.
skipGeneratingAssertionNameId Whether generation of a name identifer should be skipped for assertions. Default is false.
skipGeneratingSubjectConfirmationInResponseTo Whether generation of the InResponseTo element should be skipped for subject confirmations. Default is false.
skipGeneratingSubjectConfirmationNotOnOrAfter Whether generation of the NotOnOrBefore element should be skipped for subject confirmations. Default is false.
skipGeneratingSubjectConfirmationRecipient Whether generation of the Recipient element should be skipped for subject confirmations. Default is false.
skipGeneratingSubjectConfirmationNotBefore Whether generation of the NotBefore element should be skipped for subject confirmations. Default is true.
signingCredentialType Acceptable values are BASIC and X509. This setting controls the type of the signature block produced in the final SAML response for this application. The latter, being the default, encodes the signature in PEM format inside a X509Data block while the former encodes the signature based on the resolved public key under a DEREncodedKeyValue block.
Keep What You Need!

You are encouraged to only keep and maintain properties and settings needed for a particular integration. It is UNNECESSARY to grab a copy of all service fields and try to configure them yet again based on their default. While you may wish to keep a copy as a reference, this strategy would ultimately lead to poor upgrades increasing chances of breaking changes and a messy deployment at that.

Metadata Aggregates

CAS services are fundamentally recognized and loaded by service identifiers taught to CAS typically via regular expressions. This allows for common groupings of applications and services by url patterns (i.e. “Everything that belongs to example.org is registered with CAS). With aggregated metadata, CAS essentially does double authorization checks because it will first attempt to find the entity id in its collection of resolved metadata components and then it looks to see if that entity id is authorized via the pattern that is assigned to that service definition. This means you can do one of several things:

  1. Open up the pattern to allow everything that is authorized in the metadata.
  2. Restrict the pattern to only a select few entity ids found in the metadata. This is essentially the same thing as defining metadata criteria to filter down the list of resolved relying parties and entity ids except that its done after the fact once the metadata is fully loaded and parsed.
  3. You can also instruct CAS to filter metadata entities by a defined criteria at resolution time when it reads the metadata itself. This is essentially the same thing as forcing the pattern to match entity ids, except that it’s done while CAS is reading the metadata and thus load times are improved.

Metadata Resolution

Service provider metadata is fetched and loaded on demand for every service and then cached in a global cache for a configurable duration. Subsequent requests for service metadata will always consult the cache first and if missed, will resort to actually resolving the metadata by loading or contacting the configured resource. Each service provider definition that is registered with CAS may optionally also specifically an expiration period of metadata resolution to override the default global value.

Attribute Name Formats

Attribute name formats can be specified per relying party in the service registry.

1
2
3
4
5
6
7
8
9
10
{
  "@class": "org.apereo.cas.support.saml.services.SamlRegisteredService",
  "serviceId" : "the-entity-id-of-the-sp",
  "name": "SAML Service",
  "id": 100001,
  "attributeNameFormats": {
    "@class": "java.util.HashMap",
    "attributeName": "basic|uri|unspecified|custom-format-etc"
  }
}

You may also have the option to define attributes and their relevant name format globally via CAS properties. To see the relevant list of CAS properties, please review this guide.

Attribute Release

Attribute filtering and release policies are defined per SAML service. See this guide for more info.

A few additional policies specific to SAML services are also provided below.

InCommon Research and Scholarship

A specific attribute release policy is available to release the attribute bundles needed for InCommon’s Research and Scholarship service providers:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
  "@class": "org.apereo.cas.support.saml.services.SamlRegisteredService",
  "serviceId": "entity-ids-allowed-via-regex",
  "name": "SAML",
  "id": 10,
  "metadataLocation": "path/to/incommon/metadata.xml",
  "attributeReleasePolicy": {
    "@class": "org.apereo.cas.services.ChainingAttributeReleasePolicy",
    "policies": [ "java.util.ArrayList",
      [
         {"@class": "org.apereo.cas.support.saml.services.InCommonRSAttributeReleasePolicy"}
      ]
    ]
  }
}

Groovy Script

This policy allows a Groovy script to calculate the collection of released attributes.

1
2
3
4
5
6
7
8
9
10
11
{
  "@class": "org.apereo.cas.support.saml.services.SamlRegisteredService",
  "serviceId": "entity-ids-allowed-via-regex",
  "name": "SAML",
  "id": 10,
  "metadataLocation": "path/to/incommon/metadata.xml",
  "attributeReleasePolicy": {
    "@class": "org.apereo.cas.support.saml.services.GroovySamlRegisteredServiceAttributeReleasePolicy",
    "groovyScript": "file:/etc/cas/config/script.groovy"
  }
}

The outline of the script may be designed as:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.util.*
import org.apereo.cas.support.saml.services.*
import org.apereo.cas.support.saml.*

def Map<String, Object> run(final Object... args) {
    def attributes = args[0]
    def service = args[1]
    def resolver = args[2]
    def facade = args[3]
    def entityDescriptor = args[4]
    def applicationContext = args[5]
    def logger = args[6]
    ...
    return null;
}

The following parameters are passed to the script:

Parameter Description
attributes Map of current attributes resolved and available for release.
service The SAML service definition matched in the service registry.
resolver The metadata resolver instance of this service provider.
facade A wrapper on top of the metadata resolver that allows access to utility functions.
entityDescriptor The EntityDescriptor object matched and linked to this service provider’s metadata.
applicationContext CAS application context allowing direct access to beans, etc.
logger The object responsible for issuing log messages such as logger.info(...).

An example script follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.util.*
import org.apereo.cas.support.saml.services.*
import org.apereo.cas.support.saml.*

def Map<String, Object> run(final Object... args) {
    def attributes = args[0]
    def service = args[1]
    def resolver = args[2]
    def facade = args[3]
    def entityDescriptor = args[4]
    def applicationContext = args[5]
    def logger = args[6]

    if (entityDescriptor.entityId == "TestingSAMLApplication") {
      return [username:["something"], another:"attribute"]
    }
    return [:]
}

Pattern Matching Entity Ids

In the event that an aggregate is defined containing multiple entity ids, the below attribute release policy may be used to release a collection of allowed attributes to entity ids grouped together by a regular expression pattern:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
  "@class": "org.apereo.cas.support.saml.services.SamlRegisteredService",
  "serviceId": "entity-ids-allowed-via-regex",
  "name": "SAML",
  "id": 10,
  "metadataLocation": "path/to/incommon/metadata.xml",
  "attributeReleasePolicy": {
    "@class": "org.apereo.cas.support.saml.services.PatternMatchingEntityIdAttributeReleasePolicy",
    "allowedAttributes" : [ "java.util.ArrayList", [ "cn", "mail", "sn" ] ],
    "fullMatch" : "true",
    "entityIds" : "entityId1|entityId2|somewhere.+"
  }
}

Entity Attributes Filter

This attribute release policy authorizes the release of defined attributes, provided the accompanying metadata for the service provider contains attributes that match certain values.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
  "@class": "org.apereo.cas.support.saml.services.SamlRegisteredService",
  "serviceId": "entity-ids-allowed-via-regex",
  "name": "SAML",
  "id": 10,
  "metadataLocation": "path/to/metadata.xml",
  "attributeReleasePolicy": {
    "@class": "org.apereo.cas.support.saml.services.MetadataEntityAttributesAttributeReleasePolicy",
    "allowedAttributes" : [ "java.util.ArrayList", [ "cn", "mail", "sn" ] ],
    "entityAttributeValues" : [ "java.util.LinkedHashSet", [ "entity-attribute-value" ] ],
    "entityAttribute" : "http://somewhere.org/category-x",
    "entityAttributeFormat" : "urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"
  }
}

The specification of entityAttributeFormat is optional.

Requested Attributes Filter

This attribute release policy authorizes the release of defined attributes, based on the accompanying metadata for the service provider having requested attributes as part of its AttributeConsumingService element.

1
2
3
4
5
6
7
8
9
10
11
{
  "@class": "org.apereo.cas.support.saml.services.SamlRegisteredService",
  "serviceId": "entity-ids-allowed-via-regex",
  "name": "SAML",
  "id": 10,
  "metadataLocation": "path/to/metadata.xml",
  "attributeReleasePolicy": {
    "@class": "org.apereo.cas.support.saml.services.MetadataRequestedAttributesAttributeReleasePolicy",
    "useFriendlyName" : false
  }
}

The useFriendlyName allows the filter to compare the requested attribute’s friendly name with the resolved attribute.

Name ID Selection

Each service may specify a required Name ID format. If left undefined, the metadata will be consulted to find the right format. The Name ID value is always simply the authenticated user that is designed to be returned to this service. In other words, if you decide to configure CAS to return a particular attribute as the authenticated user name for this service, that value will then be used to construct the Name ID along with the right format.

Dynamic Metadata

CAS also supports the Dynamic Metadata Query Protocol which is a REST-like API for requesting and receiving arbitrary metadata. In order to configure a CAS SAML service to retrieve its metadata from a Metadata query server, the metadata location must be configured to point to the query server instance. Here is an example:

1
2
3
4
5
6
7
8
{
  "@class" : "org.apereo.cas.support.saml.services.SamlRegisteredService",
  "serviceId" : "the-entity-id-of-the-sp",
  "name" : "SAMLService",
  "id" : 10000003,
  "evaluationOrder" : 10,
  "metadataLocation" : "http://mdq.server.org/entities/{0}"
}

…where {0} serves as an entityID placeholder for which metadata is to be queried.

SP Integrations

A number of SAML2 service provider integrations are provided natively by CAS. To learn more, please review this guide.

Client Libraries

For Java-based applications, the following frameworks may be used to integrate your application with CAS acting as a SAML2 identity provider:

Troubleshooting

To enable additional logging, modify the logging configuration file to add the following:

1
2
3
4
<AsyncLogger name="org.opensaml" level="debug" additivity="false">
    <AppenderRef ref="console"/>
    <AppenderRef ref="file"/>
</AsyncLogger>