When managing and deploying Apereo CAS as a SAML2 identity provider, it’s rather common for SAML2 service provider integrations and applications to expect a specific NameID
from the SAML2 response they receive from CAS. A SAML2 NameID
is an element that generally belongs to the Subject
tag, is assigned a specific format and
usually takes on the following form in the SAML2 response:
<saml:Subject>
<saml:NameID SPNameQualifier="http://sp.example.com/demo1/metadata.php"
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">
123456abcdefg
</saml:NameID>
</saml:Subject>
In this post, we’ll take a look at a few variations of the NameID
element in the SAML2 response, and ways to accommodate integration requirements that expect a specific NameID
format or value from CAS as a SAML2 identity provider.
This tutorial specifically requires and focuses on:
6.4.x
By default, the NameID
value is determined as the identifier of the authenticated CAS principal. Once the authentication task is complete and the principal is resolved from all sources, the principal identifier is extracted as the NameID
value.
This default behavior can be customized on a per-application degree to use a specific attribute as the basis for the NameID
value. For example, if the authenticated principal identified as casuser
carries a mail
attribute, the following snippet could be used to produce a nameid-format:emailAddress
type of NameID
based on that attribute value:
{
"@class": "org.apereo.cas.support.saml.services.SamlRegisteredService",
"serviceId": "https://spring.io/security/saml-sp",
"name": "SAML",
"metadataLocation": "/path/to/sp-metadata.xml",
"requiredNameIdFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
"usernameAttributeProvider" : {
"@class" : "org.apereo.cas.services.PrincipalAttributeRegisteredServiceUsernameProvider",
"usernameAttribute" : "mail",
}
}
…which should produce the following:
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">
user@example.org</saml:NameID>
</saml:Subject>
The same technique can be used to produce a `` type of NameID
, using the following snippet:
{
"@class": "org.apereo.cas.support.saml.services.SamlRegisteredService",
"serviceId": "https://spring.io/security/saml-sp",
"name": "SAML",
"metadataLocation": "/path/to/sp-metadata.xml",
"requiredNameIdFormat": "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
"usernameAttributeProvider": {
"@class": "org.apereo.cas.services.AnonymousRegisteredServiceUsernameAttributeProvider",
"persistentIdGenerator": {
"@class": "org.apereo.cas.authentication.principal.ShibbolethCompatiblePersistentIdGenerator",
"salt": "salty-goodness",
"attribute": "cn"
}
}
}
…which should produce the following:
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">
Qe76hjfM14GBAqeW124</saml:NameID>
</saml:Subject>
Once you have produced a NameID
for the SAML2 Subject
, you may also have to create and release a specific attribute that contains an embedded NameID
as its value. Specifically, this would take on the following form:
<saml2:Attribute FriendlyName="my-attribute"
Name="my-attribute"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
NameQualifier="https://idp.example.org/cas/idp"
SPNameQualifier="https://idp.example.org/sp">
lkXqG+QpbLU47hvjVvfiADxEQs0=
</saml2:NameID>
</saml2:Attribute>
The NameID
attribute value, in this case, is identical to that of the Subject
; the same element in a sense is copied and reused to create the above attribute. This can be achieved by tagging the attribute value type as such:
{
"@class": "org.apereo.cas.support.saml.services.SamlRegisteredService",
"serviceId": "https://spring.io/security/saml-sp",
"name": "SAML",
"metadataLocation": "/path/to/sp-metadata.xml",
"attributeValueTypes": {
"@class": "java.util.HashMap",
"my-attribute": "NameIDType"
}
}
The eduPersonTargetedID
attribute is an abstracted version of the SAML V2.0 Name Identifier format
of urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
. In abstract terms, an eduPersonTargetedID
value is a
tuple consisting of an opaque identifier for the principal, a name for the source of the identifier, and a name for the intended audience of the identifier.
CAS provides a specific attribute release policy that can generate an eduPersonTargetedID
attribute. Once in place, you may also tag this attribute to specifically be used as an embedded NameID
inside the attribute definition in the SAML2 response:
{
"@class": "org.apereo.cas.support.saml.services.SamlRegisteredService",
"serviceId": "https://spring.io/security/saml-sp",
"name": "SAML",
"metadataLocation": "/path/to/sp-metadata.xml",
"attributeValueTypes": {
"@class": "java.util.HashMap",
"urn:oid:1.3.6.1.4.1.5923.1.1.1.10": "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
},
"attributeReleasePolicy": {
"@class": "org.apereo.cas.services.ChainingAttributeReleasePolicy",
"policies": [
"java.util.ArrayList",
[
{
"@class": "org.apereo.cas.support.saml.services.EduPersonTargetedIdAttributeReleasePolicy",
"order": 1,
"salt": "salty-goodness",
"attribute": "cn",
"useUniformResourceName": true
}
]
]
}
}
The above configuration will create the eduPersonTargetedID
attribute under the name urn:oid:1.3.6.1.4.1.5923.1.1.1.10
, as instructed via the useUniformResourceName
. The attribute value is based on the cn
attribute that is already resolved for the principal from attribute sources. Once constructed, this attribute value will be transformed and encoded as a nameid-format:persistent
type of NameID
, which would be something like this:
<saml2:Attribute FriendlyName="eduPersonTargetedID"
Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.10"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
NameQualifier="https://idp.example.org/cas/idp"
SPNameQualifier="https://idp.example.org/sp">
lkXqG+QpbLU47hvjVvfiADxEQs0=
</saml2:NameID>
</saml2:Attribute>
If you have questions about the contents and the topic of this blog post, or if you need additional guidance and support, feel free to send us a note and ask about consulting and support services.
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.
Happy Coding,
Monday-Friday
9am-6pm, Central European Time
7am-1pm, U.S. Eastern Time
Monday-Friday
9am-6pm, Central European Time