AttributeFilterConfiguration

File(s): conf/attribute-filter.xml
Format: Custom Schema
Namespace: urn:mace:shibboleth:2.0:afp
Schema: http://shibboleth.net/schema/idp/shibboleth-afp.xsd

Overview

Attribute Filtering occurs after most uses of the Attribute Resolution engine. It is about constraining the set of attributes and/or attribute values prior to them being used for some purpose, typically either for passing along to a relying party or less often to limit data passing into the IdP itself from another source. In this way, you can tailor the attributes seen by a specific relying party for a specific subject. The full range of environmental information, for instance about the relying party or (issuing party), about the specific request, and about the subject, is available to guide the filtering process.

You can exercise and debug the behavior of this process for the most common case (release to a relying party) using the AACLI tool or the web interface it uses. This is particularly helpful if you're making changes, performing upgrades, etc., to validate the results match in any given case. At present, this is not supported for the "inbound" direction.

Constraining attribute resolution and encoding using ActivationConditions

The attributes which are released to a relying party can be influenced by adding ActivationConditions to DataConnectors and AttributeDefinitions. This can limit the attributes available at the start of the filtering process, and can thus act as a form of filtering. Typically these activation conditions are used to avoid expensive operations which serve no purpose in a given situation. For instance you might not connect to an LDAP directory for attributes if you knew that those attributes would never be used in assertions for a specific relying party (or if the subject was not visible in that directory).

Equally ActivationConditions can also be attached to Transcoding Rules and Attribute Encoders. These can be used to limit the encoding an attribute into SAML under certain circumstances. This is often useful to control the format used to render a particular attribute for a particular relying party.

In general activation conditions should not be viewed as an alternative form of filtering. Rather they should be viewed as a way of achieving something which otherwise could only be achieved in more cumbersome ways. In most cases, it's simpler to start with "resolving everything" and by encoding attributes consistently, and use this feature for special situations.

In a typical (and default) configuration, only one XML resource is configured to supply the attribute filtering configuration, a file called attribute-filter.xml. All resources contain a "root"  <AttributeFilterPolicyGroup> element in the urn:mace:shibboleth:2.0:afp namespace.

Simple Attribute-Filter.xml file
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 <AttributeFilterPolicyGroup id="ShibbolethFilterPolicy" xmlns="urn:mace:shibboleth:2.0:afp" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:mace:shibboleth:2.0:afp http://shibboleth.net/schema/idp/shibboleth-afp.xsd"> <!-- Release some attributes to an SP. --> <AttributeFilterPolicy id="example1"> <PolicyRequirementRule xsi:type="Requester" value="https://sp.example.org" /> <AttributeRule attributeID="eduPersonPrincipalName"> <PermitValueRule xsi:type="ANY" /> </AttributeRule> <AttributeRule attributeID="uid"> <PermitValueRule xsi:type="ANY" /> </AttributeRule> <AttributeRule attributeID="mail"> <PermitValueRule xsi:type="ANY" /> </AttributeRule> </AttributeFilterPolicy> <!-- Release eduPersonAffiliation to two specific SPs. --> <AttributeFilterPolicy id="example2"> <PolicyRequirementRule xsi:type="OR"> <Rule xsi:type="Requester" value="https://sp.example.org" /> <Rule xsi:type="Requester" value="https://another.example.org/shibboleth" /> </PolicyRequirementRule> <AttributeRule attributeID="eduPersonScopedAffiliation"> <PermitValueRule xsi:type="ANY" /> </AttributeRule> </AttributeFilterPolicy> </AttributeFilterPolicyGroup>

The semantics of the attribute language can be deceptive. Informally it is easy to see what is going on (for instance the last case in the example could read "If the relying party has an ID of 'https://sp.example.org' or 'https://another.example.org/shibboleth' then release all values of eduPersonScopedAffiliation". However the detailed semantics can be extremely confusing and often downright counterintuitive. This is explained in detail below. A good rule of thumb is "If it seems like a cute trick and a good idea, it isn't. Do it the obvious way."

Configuration

Formally, this is the configuration of the "AttributeFilter" service. By default, one file, attribute-filter.xml, defines the attributes and values to be passed on. Multiple files can be specified by changing the bean referred to by the property idp.service.attribute.filter.resources (default value "shibboleth.AttributeFilterResources") defined in the services.xml file.

The bulk of the filter policy is contained in one or more <AttributeFilterPolicy> elements.

While not all that common, the attribute-filter.xml file can leverage property replacement to externalize particular settings. Properties are referenced via a brace syntax (e.g., %{idp.home}).
The built-in properties which impact the filtering process (moreso just the filter service itself) are names staring with idp.service.attribute.filter as described here.

Name

Type

Description

Name

Type

Description

id

XML ID

Optional but recommended, unique ID for policy group used for logging purposes

Name

Cardinality

Description

Name

Cardinality

Description

<AttributeFilterPolicy>

0 or more

A list of policies to apply

Semantics

During attribute filtering, the engine:

  1. Examines all the <AttributeFilterPolicyGroup> elements provided (for instance across multiple files) in an unspecified order.

  2. Examines all the <AttributeFilterPolicy> elements within each <AttributeFilterPolicyGroup>, again in an unspecified order.

  3. For each policy, if the <PolicyRequirementRule> is true:

    1. Applies each of the child <AttributeRule> elements, such that:

      1. The attributes (and their values) returned by <PermitValueRule> get added to a "permit list".

      2. The attributes (and their values) returned by <DenyValueRule> get added to a "deny list".

  4. At the end of filtering, the final results are calculated by:

    1. Populating the result initially from the permit list.

    2. Removing all attribute values found in the deny list.

    3. Removing all attributes with no values.

In this way, it can be seen that a <DenyValueRule> 'trumps' the result of a <PermitValueRule> in the manner typically found in such policy languages.

This is relatively uncontroversial, although some of the side effects of a deny rule can be surprising. For instance, denying is not the same as not permitting.

The difficulty arises in that anything that can be used in an <AttributeRule> can be used in a <PermitValueRule> or <DenyValueRule>. The fist example below is relatively obvious:

Obvious Example
1 2 3 4 5 6 <AttributeFilterPolicy id="example1"> <PolicyRequirementRule xsi:type="Requester" value="https://sp.example.org" /> <AttributeRule attributeID="eduPersonPrincipalName"> <PermitValueRule xsi:type="Value" value="jsmith" ignoreCase="true" /> </AttributeRule> </AttributeFilterPolicy>

"If the RP is named 'https://sp.example.org', then (only) release the 'eduPersonPrincipalName' attribute value of 'jsmith'."

But the rules can be swapped:

Non-obvious Example
1 2 3 4 5 6 <AttributeFilterPolicy id="example2"> <PolicyRequirementRule xsi:type="Value" value="jsmith" ignoreCase="true" /> <AttributeRule attributeID="eduPersonPrincipalName"> <PermitValueRule xsi:type="Requester" value="https://sp.example.org" /> </AttributeRule> </AttributeFilterPolicy>

This is valid and has a specific meaning. But what is the meaning?

PolicyRules and Matchers

In order to make this tractable, the implementation considers plugin types as being either 'PolicyRules' or 'Matchers'. PolicyRules can be expected to give a "yes/no" answer and are usually used within a <PolicyRequirementRule>. Matchers usually return sets of values when applied to an attribute and are usually used within an <AttributeRule>.

The rules used are as follows:

  • If a Matcher is specified inside a <PolicyRequirementRule>, then if the plugin returns a value when applied to any of the input attributes then it is taken as being true, otherwise it is taken as being false.

  • If a PolicyRule is specified inside an <AttributeRule>, then if the plugin returns true then all the values of the attribute concerned are returned (and added to the permit or deny list, as appropriate for the containing rule).

To confuse the issue further:

  • The logic rules (and, or, not), which are natural PolicyRules have specific semantics when they are being used inside Matcher rules

  • Some value-based rules change from being Matchers to being PolicyRules when the attributeId attribute is specified.
    So <...xsi:type="Value" value="jsmith" ignoreCase="true" /> is a Matcher (return all values which case-insensitively match "jsmith"), but <...xsi:type="Value" value="jsmith" ignoreCase="true" attributeId="uid" /> is a PolicyRule (true if and only if there is an attribute called "uid" with a value which case-insensitively matches jsmith).

So to answer the question above, the non-obvious second example means "If any value of any attribute matches 'jsmith' in a case-insensitive manner, then release all values of 'eduPersonPrincipalName' if the name of the SP is 'https://sp.example.org'". This is intelligible, but probably useless in practice. Most "swaps" of plugin types result in similar meaning.

Once compounded with NOT and deny rules, working out what is going on becomes incredibly non-intuitive. A good guiding rule is to only ever use PolicyRules inside <PolicyRequirementRule> and to only use Matchers inside <AttributeRule>.

Error Handling

Because of the dangers of the NOT plugin, it becomes impossible for any particular rule to "do the right thing" if a failure occurs during processing. The filtering engine handles this by special-casing errors to the fail-safe (release or accept nothing) case.