XMLAttributeExtractorExamples

In all the examples below, the default XML namespace is assumed to be urn:mace:shibboleth:2.0:attribute-map, to match the default file shipped with the software. Thus <Attribute> refers to a mapping rule in the attribute-map.xml file, whereas <saml2:Attribute> refers to a SAML construct in a message.

Simple Attributes

Some simple cases first, involving string-valued data, which is generally the most common case. You don't generally need to attach an AttributeDecoder to the mapping rules unless the attribute needs filtering rules attached to it later or will be used in access control rules and the attribute has to be processed in a case-insensitive manner. By default, strings will be decoded and assumed to be case-sensitive for the purposes of most value comparisons.

The SP prefers, favors, and encourages Attributes to be named with URIs, because they are unique and provide an inherent way of federating names that avoids conflict. Matching rules for such names will be simpler as a result.

Common Cases

If you want to create a rule to extract this into a variable called "mail":

Input SAML 2.0 Attribute for e-mail address
<saml2:Attribute FriendlyName="mail"
	NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
	Name="urn:oid:0.9.2342.19200300.100.1.3">
	<saml2:AttributeValue>foo@example.org</saml2:AttributeValue>
</saml2:Attribute>

you would do this (note, there's no need to specify the NameFormat constant to match because it's the Shibboleth default):

Mapping rule for the "mail" attribute
<Attribute name="urn:oid:0.9.2342.19200300.100.1.3" id="mail"/> 

For the eduPerson-defined "eduPersonAffiliation" attribute, which is case-insensitive, you would map this:

Input SAML 2.0 Attribute for eduPersonAffiliation
<saml2:Attribute FriendlyName="eduPersonAffiliation"
	NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
	Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.1">
	<saml2:AttributeValue>member</saml2:AttributeValue>
	<saml2:AttributeValue>student</saml2:AttributeValue>
 </saml2:Attribute>

using this:

Mapping rule for the "eduPersonAffiliation" attribute
<Attribute name="urn:oid:1.3.6.1.4.1.5923.1.1.1.1" id="unscoped-affiliation">
	<AttributeDecoder xsi:type="StringAttributeDecoder" caseSensitive="false"/>
</Attribute>

Hacky Naming

In the common case that you're faced with someone  providing made-up names for SAML Attributes, you may or may not need to take extra steps with the rules by setting the nameFormat XML attribute. There are basically three cases, SAML 1.1 usage, one of the actual alternative NameFormat values in SAML 2.0, and the extremely ill-advised SAML 2.0 constant for "unspecified" naming.

With SAML 1.1, there was a completely undefined concept called an AttributeNamespace used as a secondary naming key. In Shibboleth, we defined a fixed value to use, urn:mace:shibboleth:1.0:attributeNamespace:uri, that is automatically matched. If you actually need to support SAML 1.1 now, you probably have bigger problems than how to use the SP, but chances are you might run into some made up value, and you'll need to include that value in the rule as the nameFormat.

The more common case is just made-up SAML 2.0 naming. You may run into the "basic" naming format. If you need to map this:

Input SAML 2.0 Attribute with a "basic" name
<saml2:Attribute
	NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
	Name="emailAddress">
	<saml2:AttributeValue>foo@example.org</saml2:AttributeValue>
 </saml2:Attribute>

you would use this:

Mapping rule for a "basic" naming scheme
<Attribute name="emailAddress" nameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" id="mail"/> 

The other case is when the NameFormat XML attribute is omitted or set to its default value. We also match that indiscriminately, so you can map this:

Input SAML 2.0 Attribute with an "unspecified" name
<saml2:Attribute
	NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"
	Name="emailAddress">
	<saml2:AttributeValue>foo@example.org</saml2:AttributeValue>
 </saml2:Attribute>

with this:

Mapping rule for a "unspecified" naming scheme
<Attribute name="emailAddress" id="mail"/> 

Thus, that rule matches an input SAML Attribute with any of the following NameFormat values:

  • None / omitted
  • urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified
  • urn:oasis:names:tc:SAML:2.0:attrname-format:uri

Name Identifiers

Avoiding the use of Name Identifiers is the best option but in the event that you have to accept them, they can be extracted like an Attribute by treating the Format of the incoming identifier as the name to map against. It's also necessary to attach a specialized NameID AttributeDecoder to the rule and specify how to produce a simple string from the non-simple XML input format.

As a simple example, to accept an email address in a form like:

Input SAML 2.0 e-mail NameID
<saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">foo@example.org</saml2:NameID>

the rule would be:

Mapping rule for SAML 2.0 e-mail NameID
<Attribute name="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" id="mail">
    <AttributeDecoder xsi:type="NameIDAttributeDecoder" formatter="$Name" />
</Attribute>

A more complex example, a SAML 2.0 "persistent" Name Identifier, is a full "triple" in which both the qualifier XML attributes have to be included in a string representation to be fully accurate:

Input SAML 2.0 persistent NameID
<saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
	NameQualifier="https://idp.example.org/idp"
	SPNameQualifier="https://sp.example.org/sp">
	JGHDGEGKDGSGJSGJKNNFLDLJDJDADAFJJDJG
</saml2:NameID>

and the rule might be (might, because the exact serialization is entirely a local choice):

Mapping rule for SAML 2.0 persistent NameID
<Attribute name="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" id="persistent-id">
    <AttributeDecoder xsi:type="NameIDAttributeDecoder" formatter="$NameQualifier!$SPNameQualifier!$Name" defaultQualifiers="true"/>
</Attribute>

Scoped Attributes

The most common "special" case to deal with is decoding a scoped attribute. A scoped attribute is one whose values have two parts, one actual value and one "scope", usually resembling a DNS domain, that qualifies the value. The special part of this is that it's usually important to control which IdP can supply a particular scope by using an AttributeFilter rule, usually based on SAML Metadata containing a Shibboleth-defined metadata extension.

While an email address looks like a scoped value, one doesn't generally apply policy like this to an email address, which should never be used as an important identifier but only as, obviously, a contact address. So email addresses are decoded as "simple" values, but actual identifiers with scopes should usually have a special Scoped AttributeDecoder attached inside the rule.

A good example of a scoped attribute is the new standard "subject ID" SAML Attribute that should be used in new applications, which looks like:

Input SAML 2.0 Attribute for subject ID
<saml2:Attribute FriendlyName="subject-id"
	NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
	Name="urn:oasis:names:tc:SAML:attribute:subject-id">
	<saml2:AttributeValue>AJDKHDDISGKHKSHLFLHFHSGKSGK@example.org</saml2:AttributeValue>
</saml2:Attribute>

and would be mapped with:

Mapping rule for scoped subject ID
<Attribute name="urn:oasis:names:tc:SAML:attribute:subject-id" id="subject-id">
    <AttributeDecoder xsi:type="ScopedAttributeDecoder" caseSensitive="false"/>
</Attribute>

Same as all the earlier examples, just a different decode type.