MetadataDrivenConfiguration

Overview

One of the challenges of dealing with interoperability issues with SPs is maintaining all the custom configuration rules needed to drive the IdP's behavior in all kinds of different ways. Traditionally most of these kinds of settings were concentrated in the relying-party.xml file and involve defining "overrides" for SPs or groups of SPs, often through manually maintained lists of entityIDs.

As discussed in the RelyingPartyConfiguration topic in the section on dynamically-driven profile configuration, the IdP supports the ability to produce these settings on the fly at runtime, which creates opportunities for more flexible configuration, at some cost in complexity.

The best way to leverage the features described in that section involves the use of metadata "tags" (a shorthand name for the <mdattr:EntityAttributes> SAML metadata extension) to embed signals in metadata that can drive configuration. In the longer term, any hope for a simplified approach to configuration or even a GUI rests on a strategy of this general type.

The IdP supports a built-in layer of code and Spring wiring to enable the use of the metadata-driven approach to configuration in a systematic way that provides a set of conventions for tag names and values to use to drive a significant range of configuration settings. With a few up-front adjustments to the relying-party.xml file, it's possible to enable comprehensive support for metadata-driven configuration that can be freely intermixed in most cases with more static settings as required.

Bear in mind that enabling this feature requires a total degree of trust and control over one's sources of metadata, because the information in the metadata can have a wide-ranging impact on the behavior of the IdP, by design. It essentially offloads pieces of your configuration to the metadata, with all that that entails.

General Configuration

Support for this feature has been added to the runtime environment in a way that avoids overhead (and risk) if not used but allows for straightforward enablement on a per-profile basis. The existing parent beans used for defining relying party defaults, overrides, and profile configurations all have analogs with a ".MDDriven" suffix in their names. Changing the existing parent or referenced bean name by adding the suffix and reloading the configuration will cause the runtime to evaluate most of the commonly-used configuration settings by checking for appropriately-named "tags" in the SP's metadata before falling back to the default, or statically configured, value if no tag is found.

For example, if you would like to enable tag-driven configuration for SAML 2.0 Browser SSO, you can replace any reference to the SAML2.SSO bean with SAML2.SSO.MDDriven, as in this example:

<bean id="shibboleth.DefaultRelyingParty" parent="RelyingParty"> <property name="profileConfigurations"> <list> <ref bean="Shibboleth.SSO" /> <ref bean="SAML1.AttributeQuery" /> <ref bean="SAML1.ArtifactResolution" /> <ref bean="SAML2.SSO.MDDriven" /> <!-- enables metadata-driven settings --> <ref bean="SAML2.ECP" /> <ref bean="SAML2.Logout" /> <ref bean="SAML2.AttributeQuery" /> <ref bean="SAML2.ArtifactResolution" /> </list> </property> </bean>

Attribute / Property Convention

The "bridge" between the metadata and this feature is the naming and syntax of the attribute tags used to control the configuration properties in the IdP. As an implementation strategy this could be "brute forced" with arbitrary mapping dictionaries, but the supplied implementation takes the approach of automating a mapping between the names of settings and the identifiers used internally for the various profiles, and the names of the corresponding SAML Attributes in metadata for those profile/setting combinations.

Each setting has a "base" name matching its Java bean property name as would be used if the setting were explicitly configured in Spring. For example, the property set via p:defaultAuthenticationMethods is named "defaultAuthenticationMethods".

The corresponding SAML Attribute for a setting is named by suffixing the "base" name of the setting to a profile URL that is defined by the Shibboleth software for each of the supported profiles.

The URLs are as follows:

Profile

Profile URL

Profile

Profile URL

Shibboleth.SSO

http://shibboleth.net/ns/profiles/saml1/sso/browser

SAML1.AttributeQuery

http://shibboleth.net/ns/profiles/saml1/query/attribute

SAML1.ArtifactResolution

http://shibboleth.net/ns/profiles/saml1/query/artifact

SAML2.SSO

http://shibboleth.net/ns/profiles/saml2/sso/browser

SAML2.ECP

http://shibboleth.net/ns/profiles/saml2/sso/ecp

SAML2.AttributeQuery

http://shibboleth.net/ns/profiles/saml2/query/attribute

SAML2.ArtifactResolution

http://shibboleth.net/ns/profiles/saml2/query/artifact

SAML2.Logout

http://shibboleth.net/ns/profiles/saml2/logout

CAS.LoginConfiguration

https://www.apereo.org/cas/protocol/login

CAS.ProxyConfiguration

https://www.apereo.org/cas/protocol/proxy

CAS.ValidateConfiguration

https://www.apereo.org/cas/protocol/serviceValidate

It follows that the includeAttributeStatement property of the "Shibboleth.SSO" profile configuration can be set via a metadata Attribute named "http://shibboleth.net/ns/profiles/saml1/sso/browser/includeAttributeStatement"

As an additional convention, a setting can be configured for all profiles simultaneously by prefixing it with the URL "http://shibboleth.net/ns/profiles"

We reserve the right to define behavior for any current or future SAML Attributes named in the shibboleth.net domain or any other URI we own and control, so if any developers wish to develop general purpose extensions or behavior based on such tags, you should either rely on your own tag names or seek permission from the project.

While the SAML Attribute Name is handled as above, the NameFormat of all supported properties is presumed to be urn:oasis:names:tc:SAML:2.0:attrname-format:uri to prevent conflicts.

There is a property in conf/services.xml that is shipped enabled, but internally off by default for compatibility. When idp.service.relyingparty.ignoreUnmappedEntityAttributes is true, which is suggested, the system will ignore any tags that have an improper NameFormat unless they are explicitly decoded with a custom rule in the AttributeRegistryConfiguration.

A side effect of this setting is that the IdP will operate somewhat faster in locating (or not locating) tags for all of its settings using decoded and indexed data instead of having to inefficiently search the native XML-based data structures for a match. As a result, it is strongly advised that the proper NameFormat be used and the property enabled.

The supplied implementations support various built-in type conversions supporting a natural mapping between simple XML syntax and Java data types. Different kinds of settings support particular XML syntaxes as described below.

The only XML syntaxes supported are "simple content" models involving an <AttributeValue> containing only text content, but it is possible to apply specific xsi:type designations that trigger more precise handling (such as enforcing numeric or boolean data). Note that using xsi:type in this fashion requires declaring an appropriate namespace and prefix for the XSD namespace, http://www.w3.org/2001/XMLSchema, which is conventionally bound to the xsd or xs prefixes.

Setting Data Type

Supported XML Conversions

Notes

Setting Data Type

Supported XML Conversions

Notes

String

Untyped, string, boolean, integer, dateTime, base64binary

Booleans are mapped to the strings "0" or "1".

Dates are mapped into the Unix epoch, then converted to String.

Boolean

Untyped, string, boolean, integer

Strings are processed as a valid XML boolean value (0, 1, true, false) or treated as false.

Non-zero integers are true, zero is false.

Integer

Untyped, string, boolean, integer

Strings are decoded via Integer.decode() method.

Booleans are mapped to 0 or 1.

Long

Untyped, string, boolean, integer, dateTime

Strings are decoded via Long.decode() method.

Booleans are mapped to 0 or 1.

Dates are mapped to the Unix epoch, then converted to a Long.

Double

Untyped, string, boolean, integer

Strings are decoded via Double.valueOf() method.

Booleans are mapped to 0.0 or 1.0.

Duration

Untyped, string, integer

Strings are converted from the ISO Duration notation used throughout the software.

Integers are treated as a millisecond duration.

List<?>

Untyped, string, boolean, integer, dateTime, base64binary

Supports multiple <AttributeValue> elements, and each value is converted to a String and then used to construct an object of the type specified for the property via a String-based single-argument constructor.

Set<?>

Untyped, string, boolean, integer, dateTime, base64binary

Supports multiple <AttributeValue> elements, and each value is converted to a String and then used to construct an object of the type specified for the property via a String-based single-argument constructor.

Bean

Untyped, string

Converted to a String used as a name of a Spring bean to build or access

Applying Tags

There are two ways to apply tags to metadata: directly and indirectly.

The direct method applies to cases in which you control the metadata or when the source of the metadata supports the inclusion of the necessary extensions. The tags simply appear within the metadata being loaded into the IdP using an <mdattr:EntityAttributes> extension element:

<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:mdattr="urn:oasis:names:tc:SAML:metadata:attribute" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" entityID="https://sp.example.org/sp"> <Extensions> <mdattr:EntityAttributes> <saml:Attribute Name="http://shibboleth.net/ns/profiles/defaultAuthenticationMethods" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> <saml:AttributeValue>http://example.org/ac/classes/mfa</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="http://shibboleth.net/ns/profiles/saml2/sso/browser/signResponses" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> <saml:AttributeValue>false</saml:AttributeValue> </saml:Attribute> </mdattr:EntityAttributes> </Extensions> <SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> <!-- Content omitted --> </SPSSODescriptor> </EntityDescriptor>

The indirect method uses the EntityAttributesFilter to attach the tags at runtime after loading and verifying the metadata. This is useful for cases in which you want to rely on externally supplied metadata but still organize parts of your configuration around the metadata. One use for this is simply consistency: if you have both external and local metadata, you can drive the configuration with both.

Relying Party Configuration Examples

The following examples illustrate possible <Attribute> syntaxes that can be used to configure a variety of common features. The examples apply equally to either the direct or indirect methods of attaching the attributes to the metadata.

Signed Assertions vs. Responses

Enabling signed assertions for a particular SP is advisedly handled by setting the WantAssertionsSigned XML attribute in metadata, but isn't always possible and sometimes has to be combined with disabling signed responses (or just for efficiency).

Disabling Encryption

Setting idp.encryption.optional is usually a workaround for handling the majority of SPs without encryption support, but there are a couple of scenarios in which it's useful to be able to manually disable it. Some federations (InCommon for one, at least for the time being) have limitations such that SPs without encryption support are stuck registering keys they don't support. Some SPs support encryption but build in time-bombs by forcing flag day key rotations on all IdPs that cause outages or manual work. Or you may simply want to drive this more explicitly for only a subset of SPs and not as a global change.

Note that it may be helpful to make sure encryption also doesn't get used during logout, so the second tag may be useful.

NameID Format Selection

Using <NameIDFormat> elements in metadata (which can also be added at runtime with the NameIDFormatFilter) is the normal way to use metadata to select the Format to use, but the "unspecified" Format has to be triggered with a profile setting. That's not commonly needed, but it's easy to define a tag for in such cases (and if you prefer you can obviously designate any Format this way).

One concern is that any two SPs using it are only coincidentally going to want the same data, so this isn't always solely a matter of Format selection. In such cases, it may be necessary to add activationCondition properties based on SP to specific generators that are handling the same Format.

Bug Workarounds

Some of the other profile settings are workarounds for bugs, e.g., omitting the NotBefore attribute. This is not very common but easily tag-driven.

A more obscure example would be an SP that requires additional <Audience> values in addition to its own entityID. This mainly demonstrates that some settings may be multi-valued.

Forcing MFA

Handling SPs that require MFA but can't request it requires IdP-side configuration, usually involving a couple of settings. The URL below is just an example, it has to be replaced by whatever <AuthnContextClassRef> constant is used in a deployment to signal MFA, or possibly more than one.

Interceptor Flows

Triggering consent based on the SP is pretty common.

The authorization intereptor flow is another case, though the checking logic would have to be extended for each different service/scenario. In the example, both flows are enabled.

Legacy Profiles

A common use case is enabling SAML 1 for legacy systems, often combined with either enabling queries or attribute push (to eliminate the queries). This is not handled as well via this mechanism because one generally enables most profiles by default, and it's not practical to enable them and then try and disable them for all but a few SPs. This goal is the opposite, disable by default and enable the profiles for a few exceptions.

Therefore, the built-in wiring cannot accomodate this use case, but it's possible to do this with an activation condition. This is the same wiring that is provided by the system configuration for many of the other properties but is supplied here "by hand" in order to adjust the default value of the condition to "false" instead of "true".

Attribute Filtering

The AttributeFilterConfiguration has had support for metadata-driven configuration for a while now, but it hasn't been extensively used. A logical approach is to align usage with the property-driven model outlined above and move to a per-attribute policy model, in contrast to the fairly common model today of defining policies around services. Since the filter layer operates by iterating over all policies to determine if they apply, it may be more efficient for larger policy sets to redesign policies around tags that signal release of each individual attribute.

To facilitate the sharing of examples, building of tools, and a more useful set of default rules in the software, we have agreed to reserve the following SAML Attribute for use in constructing filter policies:

Name: http://shibboleth.net/ns/attributes/releaseAllValues

NameFormat: urn:oasis:names:tc:SAML:2.0:attrname-format:uri

Values: Each value is an internal IdPAttribute ID whose values should be released to an SP whose metadata contains the relevant tag/value.

Example

Here's an example policy (more or less matching an example in the default file) that applies this tag test to a couple of attributes. A couple of subtle points here.

One is that this approach is really a purely "local" one because the IdP Attribute names are local/internal only. You might assume most people use similar conventions and you'd be right, but you can't expect that to be true universally, so it is not appropriate to ever try and use this kind of metadata tag outside of a scenario that does not involve control of the IdP. It's not a fix for the brokenness of the more general SAML <RequestedAttribute> metadata element, which is usually impractical for a variety of reasons.

Less critically, note that this policy example demonstrates an optimization in that it applies the tag check in the <AttributeRule>(s) and not up in the <PolicyRequirementRule>. This has the advantage of requiring less XML to express and is about the same or better in performance than running multiple policies. It's not as good for an attribute that might have 3-5 or more values, since that would force the cost of checking for the tag to be paid for each value.

<AttributeFilterPolicy id="Per-Attribute-singleValued"> <PolicyRequirementRule xsi:type="ANY"/> <AttributeRule attributeID="eduPersonPrincipalName"> <PermitValueRule xsi:type="EntityAttributeExactMatch" attributeName="http://shibboleth.net/ns/attributes/releaseAllValues" attributeNameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" attributeValue="eduPersonPrincipalName" /> </AttributeRule> <AttributeRule attributeID="mail"> <PermitValueRule xsi:type="EntityAttributeExactMatch" attributeName="http://shibboleth.net/ns/attributes/releaseAllValues" attributeNameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" attributeValue="mail" /> </AttributeRule> </AttributeFilterPolicy>

Reference

Beans

Bean ID

Type

Function

Bean ID

Type

Function

RelyingParty.MDDriven                                          

RelyingPartyConfiguration

A template bean for use in defining metadata-driven RelyingParty overrides by hand

RelyingPartyByName.MDDriven

RelyingPartyConfiguration

A template bean for defining metadata-driven RelyingParty overrides based on matching by name

RelyingPartyByGroup.MDDriven

RelyingPartyConfiguration

A template bean for defining metadata-driven RelyingParty overrides based on matching by <EntitiesDescriptor> groups or SAML metadata-based <AffiliationDescriptor> groups

RelyingPartyByEntitiesDescriptor.MDDriven

RelyingPartyConfiguration

A template bean for defining metadata-driven RelyingParty overrides based on matching by <EntitiesDescriptor> groups only

RelyingPartyByTag.MDDriven

RelyingPartyConfiguration

A template bean for defining metadata-driven RelyingParty overrides based on matching <EntityAttributes> extension content

RelyingPartyByMappedTag.MDDriven

RelyingPartyConfiguration

A template bean for defining metadata-driven RelyingParty overrides based on matching <EntityAttributes> extension content mapped via the AttributeRegistryConfiguration

Shibboleth.SSO.MDDriven

BrowserSSOProfileConfiguration

Default metadata-driven configuration for SAML 1.1 SSO profile

SAML1.AttributeQuery.MDDriven

AttributeQueryProfileConfiguration

Default metadata-driven configuration for SAML 1.1 Attribute Query profile

SAML1.ArtifactResolution.MDDriven

ArtifactResolutionProfileConfiguration

Default metadata-driven configuration for SAML 1.1 Artifact Resolution profile

SAML2.SSO.MDDriven

BrowserSSOProfileConfiguration

Default metadata-driven configuration for SAML 2.0 SSO profile

SAML2.ECP.MDDriven

ECPProfileConfiguration

Default metadata-driven configuration for SAML 2.0 Enhanced Client/Proxy profile

SAML2.Logout.MDDriven

SingleLogoutProfileConfiguration

Default metadata-driven configuration for SAML 2.0 Single Logout profile

SAML2.AttributeQuery.MDDriven

AttributeQueryProfileConfiguration

Default metadata-driven configuration for SAML 2.0 Attribute Query profile

SAML2.ArtifactResolution.MDDriven

ArtifactResolutionProfileConfiguration

Default metadata-driven configuration for SAML 2.0 Artifact Resolution profile

CAS.LoginConfiguration.MDDriven

LoginConfiguration

Default metadata-driven configuration for CAS login prototol

CAS.ProxyConfiguration.MDDriven

ProxyConfiguration

Default metadata-driven configuration for CAS proxy login protocol

CAS.ValidateConfiguration.MDDriven

ValidateConfiguration

Default metadata-driven configuration for CAS ticket validation protocol

shibboleth.DefaultMDProfileAliases

List<String>

A built-in list of alternate URL "prefixes" to property names, this is used to automate the generation of property tag names that apply to all profiles at the same time.

shibboleth.MDProfileAliases

List<String>

An optional user-supplied list of additional URL prefixes to support custom property tag names

shibboleth.MDDrivenStringProperty

StringConfigurationLookupStrategy

Parent bean for defining new lookup strategies for string settings

shibboleth.MDDrivenBoolProperty

BooleanConfigurationLookupStrategy

Parent bean for defining new lookup strategies for boolean settings

shibboleth.MDDrivenIntProperty

IntegerConfigurationLookupStrategy

Parent bean for defining new lookup strategies for integer settings

shibboleth.MDDrivenLongProperty

LongConfigurationLookupStrategy

Parent bean for defining new lookup strategies for long integer settings

shibboleth.MDDrivenDoubleProperty

DoubleConfigurationLookupStrategy

Parent bean for defining new lookup strategies for double settings

shibboleth.MDDrivenDurationProperty

DurationConfigurationLookupStrategy

Parent bean for defining new lookup strategies for Duration settings

shibboleth.MDDrivenListProperty

ListConfigurationLookupStrategy

Parent bean for defining new lookup strategies for List settings

shibboleth.MDDrivenSetProperty

SetConfigurationLookupStrategy

Parent bean for defining new lookup strategies for Set settings

shibboleth.MDDrivenBeanProperty

BeanConfigurationLookupStrategy

Parent bean for defining new lookup strategies for arbitrary Spring bean settings