The process of dealing with attributes in Apereo CAS is twofold. First, CAS begins to fetch and resolve attributes from configured data sources, which may or may not be the same as the authentication source, usually as part of or right after the authentication transaction. Once attributes are found, they may be conditionally released to integrated service providers and registered clients and relying parties using a variety of attribute release policies.
In this blog post, I attempt to collect a number of attribute release policy samples and snippets that demonstrate the capabilities of the CAS attribute release engine to some degree. Some are rather modest and hopefully self-explanatory, and some are more advanced tapping into the particulars of a given authentication protocol to take advantage of fancier features such as scopes, chains, etc.
In all such examples, the underlying assumptions are:
Let’s begin. Our starting position is based on:
CAS running as SAML2 identity provider, releasing the R&E bundle of attributes to service providers found in a metadata aggregate in addition to a number of other freelancing attributes.
{
"@class": "org.apereo.cas.support.saml.services.SamlRegisteredService",
"serviceId": ".+",
"name": "example",
"id": 1,
"evaluationOrder": 1,
"metadataLocation": "https://server-url/saml-metadata-aggregate.xml",
"attributeReleasePolicy": {
"@class": "org.apereo.cas.services.ChainingAttributeReleasePolicy",
"policies": [
"java.util.ArrayList",
[
{ "@class": "org.apereo.cas.support.saml.services.InCommonRSAttributeReleasePolicy" },
{ "@class": "org.apereo.cas.support.saml.services.RefedsRSAttributeReleasePolicy" },
{
"@class": "org.apereo.cas.services.ReturnAllowedAttributeReleasePolicy",
"allowedAttributes" : [ "java.util.ArrayList", [ "emplId", "department" ] ]
}
]
]
}
}
Release employeeId
as UDC_IDENTIFIER
typically done for Ellucian Banner SSO Manager.
{
"@class" : "org.apereo.cas.services.RegexRegisteredService",
"serviceId" : "https://example.banner.edu",
"name" : "banner",
"id" : 1,
"attributeReleasePolicy" : {
"@class" : "org.apereo.cas.services.ReturnMappedAttributeReleasePolicy",
"allowedAttributes" : {
"@class" : "java.util.TreeMap",
"employeeId" : "UDC_IDENTIFIER"
}
}
}
CAS running a SAML2 identity provider is set to release all attributes to the SAML2 service provider, while generating a transient name identifier.
{
"@class" : "org.apereo.cas.support.saml.services.SamlRegisteredService",
"serviceId" : "service-provider-entity-id",
"name" : "SAML",
"id" : 1,
"metadataLocation" : "/path/to/metadata.xml",
"requiredNameIdFormat": "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
"attributeReleasePolicy" : {
"@class" : "org.apereo.cas.services.ReturnAllAttributeReleasePolicy"
},
"usernameAttributeProvider" : {
"@class" : "org.apereo.cas.services.AnonymousRegisteredServiceUsernameAttributeProvider",
}
}
CAS running a SAML2 identity provider is set to release all attributes to the SAML2 service provider, while generating a persistent name identifier using a pre-defined salt.
{
"@class" : "org.apereo.cas.support.saml.services.SamlRegisteredService",
"serviceId" : "service-provider-entity-id",
"name" : "SAML",
"id" : 1,
"metadataLocation" : "/path/to/metadata.xml",
"attributeReleasePolicy" : {
"@class" : "org.apereo.cas.services.ReturnAllAttributeReleasePolicy"
},
"usernameAttributeProvider" : {
"@class" : "org.apereo.cas.services.AnonymousRegisteredServiceUsernameAttributeProvider",
"persistentIdGenerator" : {
"@class" : "org.apereo.cas.authentication.principal.ShibbolethCompatiblePersistentIdGenerator",
"salt" : "aGVsbG93b3JsZA==",
}
}
}
CAS running as OAuth identity provider, releasing a number of attributes.
{
"@class" : "org.apereo.cas.support.oauth.services.OAuthRegisteredService",
"clientId": "client",
"clientSecret": "secret",
"serviceId" : "https://app.example.org/dashboard/login",
"name" : "OAUTH",
"id" : 1,
"attributeReleasePolicy" : {
"@class" : "org.apereo.cas.services.ReturnAllowedAttributeReleasePolicy",
"allowedAttributes" : [ "java.util.ArrayList", [ "cn", "mail", "givenName" ] ]
}
}
CAS running as an OpenID Connect identity provider, releasing the dynamically-built attribute user-x
off of uid
as well as all other attributes (i.e. claims) defined by the standard email
scope.
{
"@class": "org.apereo.cas.services.OidcRegisteredService",
"clientId": "client",
"clientSecret": "secret",
"serviceId": "^https://app.example.org/.*",
"name": "OIDC",
"id": 1000,
"attributeReleasePolicy": {
"@class": "org.apereo.cas.services.ChainingAttributeReleasePolicy",
"policies": [
"java.util.ArrayList",
[
{
"@class" : "org.apereo.cas.services.ReturnAllowedAttributeReleasePolicy",
"allowedAttributes" : [ "java.util.ArrayList", [ "cn", "uid", "givenName" ] ],
"order": 0
},
{
"@class": "org.apereo.cas.services.ReturnMappedAttributeReleasePolicy",
"allowedAttributes": {
"@class": "java.util.TreeMap",
"user-x": "groovy { return attributes['uid'].get(0) + '-X' }"
},
"order": 1
},
{
"@class": "org.apereo.cas.oidc.claims.OidcEmailScopeAttributeReleasePolicy",
"order": 2
}
]
]
}
}
CAS running as a WS-FED identity provider releasing employeeNumber
off of givenName
via a custom namespace.
{
"@class" : "org.apereo.cas.ws.idp.services.WSFederationRegisteredService",
"serviceId" : "https://url.to.example/app.*",
"name" : "WSFED",
"id" : 2,
"attributeReleasePolicy" : {
"@class" : "org.apereo.cas.ws.idp.services.CustomNamespaceWSFederationClaimsReleasePolicy",
"namespace": "https://github.com/apereo/cas",
"allowedAttributes" : {
"@class" : "java.util.TreeMap",
"employeeNumber" : "givenName"
}
},
"tokenType": "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1"
}
CAS is releasing attributes cn
, mail
and sn
as well as displayName
to a client, where the user is asked to consent to the release of attributes displayName
and cn
.
{
"@class" : "org.apereo.cas.services.RegexRegisteredService",
"serviceId" : "https://example.app.org",
"name" : "ConsentChained",
"id" : 1,
"evaluationOrder" : 1,
"attributeReleasePolicy": {
"@class": "org.apereo.cas.services.ChainingAttributeReleasePolicy",
"mergingPolicy": "replace",
"policies": [ "java.util.ArrayList",
[
{
"@class" : "org.apereo.cas.services.ReturnAllowedAttributeReleasePolicy",
"allowedAttributes" : [ "java.util.ArrayList", [ "cn", "mail", "sn" ] ],
"consentPolicy": {
"@class": "org.apereo.cas.services.consent.DefaultRegisteredServiceConsentPolicy",
"includeOnlyAttributes": ["java.util.LinkedHashSet", ["cn"]],
"enabled": true
}
},
{
"@class" : "org.apereo.cas.services.ReturnAllowedAttributeReleasePolicy",
"allowedAttributes" : [ "java.util.ArrayList", [ "displayName" ] ],
"consentPolicy": {
"@class": "org.apereo.cas.services.consent.DefaultRegisteredServiceConsentPolicy",
"includeOnlyAttributes": ["java.util.LinkedHashSet", ["displayName"]],
"enabled": true
}
}
]
]
}
}
This one is way more complicated! CAS is releasing attributes:
cn
, department
, mail
and sn
only if the value of each attribute has exactly 3 characters.displayName
The user is asked to consent to the release of cn
, department
and displayName
out of the calculated released bundle.
{
"@class" : "org.apereo.cas.services.RegexRegisteredService",
"serviceId" : "^(https|imaps)://app.example.org",
"name" : "example",
"id" : 1,
"evaluationOrder" : 1,
"attributeReleasePolicy": {
"@class": "org.apereo.cas.services.ChainingAttributeReleasePolicy",
"mergingPolicy": "replace",
"policies": [ "java.util.ArrayList",
[
{
"@class" : "org.apereo.cas.services.ReturnAllowedAttributeReleasePolicy",
"allowedAttributes" : [ "java.util.ArrayList", [ "cn", "department", "mail", "sn" ] ],
"attributeFilter" : {
"@class" : "org.apereo.cas.services.support.RegisteredServiceChainingAttributeFilter",
"filters": [ "java.util.ArrayList",
[
{
"@class" : "org.apereo.cas.services.support.RegisteredServiceRegexAttributeFilter",
"pattern" : "^\\w{3}$",
"order": 1
}
]
]
},
"consentPolicy": {
"@class": "org.apereo.cas.services.consent.DefaultRegisteredServiceConsentPolicy",
"includeOnlyAttributes": ["java.util.LinkedHashSet", ["cn", "department"]],
"enabled": true
}
},
{
"@class" : "org.apereo.cas.services.ReturnAllowedAttributeReleasePolicy",
"allowedAttributes" : [ "java.util.ArrayList", [ "displayName" ] ],
"consentPolicy": {
"@class": "org.apereo.cas.services.consent.DefaultRegisteredServiceConsentPolicy",
"includeOnlyAttributes": ["java.util.LinkedHashSet", ["displayName"]],
"enabled": true
}
}
]
]
}
}
I hope this review was of some help to you and I am sure that both this post as well as the functionality it attempts to explain can be improved in any number of ways. Please feel free to engage and contribute as best as you can.
Monday-Friday
9am-6pm, Central European Time
7am-1pm, U.S. Eastern Time
Monday-Friday
9am-6pm, Central European Time