File(s): conf/attribute-filter.xml

Format: Custom Schema

Overview

Attribute Filtering occurs between Attribute Resolution and Attribute Encoding. It is about constraining the set of attributes and/or attribute values prior to them being passed over to a relying party. 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, 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 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.

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 be attached to AttributeEncoders. 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 V2, this could only be achieved by cumbersome duplication of attributes with specific filters.

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 in V2 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.

<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 counter intuitive. 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.AttributeFilterResource) defined in the services.xml file.

Properties

While not all that common, the attribute-filter.xml file can leverage property replacement to externalize particular settings. By default, these properties are defined in the idp.properties file. Properties are referenced via a brace syntax (e.g., %{idp.home}).

The properties which affect the filtering process are names staring with idp.service.attribute.filter as described here

Schema Name

Elements described in this page and its children are defined by the urn:mace:shibboleth:2.0:afp namespace, the schema for which can be located at http://shibboleth.net/schema/idp/shibboleth-afp.xsd

In addition, IdP versions prior to 3.2.0 used the following additional namespaces:

Use of these additional namespaces remains supported in newer versions, but is not required or advised in newer deployments, and they will be removed from V4.0. Plugin types defined in these two namespaces have corresponding types with the same, or a truncated version of, the name. The tables of legacy to current name mappings are given here.

Attribute

The  <AttributeFilterPolicyGroup> element should have an id attribute. This must be unique and is used for logging purposes.

Child Elements

The  <AttributeFilterPolicyGroup> contains a series of zero or more <AttributeFilterPolicy> elements expressing the policies that may be applied.

In V2, it was possible for other "rule" elements to appear at the top level, but this referencing/reuse feature was inconsistently implemented and is no longer supported. It should be avoided.

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:

<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:

<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:

To confuse the issue further:

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 nothing) case.