AgentResolverBeanInheritance

This software is not yet released and this is preliminary documentaton subject to significant change. It should not be used in production or to protect important resources at this stage.

AgentResolverBeanInheritance

The Hub’s Agent Resolver service configuration supports the notion of inheritance in a number of cases to make configuring “exceptions” simpler than it has been at times in the past. Inheritance can be complex to understand, however, so this is a dive into how it works, though playing around with the beans is the best way to understand it. Reading the source code, even for those so inclined, is not an advisable way to understand it, quite frankly.

This inheritance is distinct from the way Spring itself implements bean inheritance, though it relies to some extent on that mechansim, and it isn’t the same thing as “reuse” of some of the beans, which is more of a configuration convenience that is built-in to how the beans are defined so as to actually limit the amount of special configuration needed in the first place.

In addition, the point of the inheritance features was to simplify (seriously) the use of Application and RelyingPartyConfiguration overrides, and as we have taken great pains for a long time to emphasize, they are a bad idea (moreso the former) and are almost always the worst possible way to achieve whatever is motivating their use. If you didn’t understand it all in the legacy SP, you’re going to understand it even less now.

Inheritance Model

The primary source of “specialized” inheritance is in the implementation of the Application interface, which allows Application overrides to default-inherit most of their settings from the containing Agent (which doubles as the default Application definition for that Agent). Most settings, if they evaluate to unset/null values in a particular override, will default to inheriting their parent Agent’s corresponding setting.

This is a key point: the inheritance works by triggering on detection of the absence of a setting. That means you (mostly) can’t effectively “unset” a setting in an override unless you want the parent Agent’s setting to take affect.) There is one notable exception to this rule: theauthenticatingAuthority setting. If this is directly and explicitly configured to be null, that will be honored; this is one setting where the null value is of greater significance/use.

To support this feature, when you define an override using the shibboleth.sp.Application bean, it has no required settings apart from the p:id property that names it so that Agent requests can associate themselves with it. All the other settings will by design default to inheriting from the containing Agent unless explicitly set. For example, if the issuer property were defined for a given Agent bean, an Application override that doesn’t set the issuer property will inherit the parent setting.

Notably, this extends to its RelyingPartyConfigurations “collection”: if there are no RelyingPartyConfiguration overrides defined explicitly, the parent Agent’s overrides will be in effect. (In contrast, if any are defined, the parent’s overrides will not be visible.)

Where things get even fancier: the inheritance model also extends to the RelyingPartyConfiguration layer such that:

  • When a RelyingPartyConfiguration override is in effect for a request, any absent/null settings on that object will generally be replaced by the containing Application’s settings.

  • When the default RelyingPartyConfiguration is in effect for a request to an overridden Application, absent/null settings on that Application override will generally be replaced by the default/parent Application’s settings.

What tends to hapen then is that an Agent bean’s settings tend to “default into” all of the “lower level” objects that it might contain, allowing only the overridden settings to be specified on those objects.

Howeber, while this extends to the level of the ProfileConfigurations that are enabled, it does not extend to actual profile settings. That is, if a ProfileConfiguration for profile “Foo” is installed for an Agent at the “top” level, it will be visible/exposed to any Application or RelyingPartyConfiguration overrides in that Agent if they don’t explicitly override the set they want enabled. However, defining a lower-level ProfileConfiguration for “Foo” does not allow absent settings to be inherited from the other “Foo” configuration bean. (This is consistent with the way the IdP’s configuration works.)

Summing this up:

  • Agent beans act as a default Application bean

  • Application beans act as a default RelyingPartyConfiguration bean

  • Individual settings on an Application and its RelyingPartyConfiguration overrides can generally be inherited from above when absent

  • The collections of RelyingPartyConfiguration overrides and of default ProfileConfigurations inherit when absent at a lower level

  • ProfileConfiguration beans when explicitly defined do not inherit settings from anywhere else other than in some very specialized cases

Suppressing Inheritance

In some cases, you may have a need to “unset” a property/setting (that is, make it null/empty). That does not generally work (with one exception noted earlier, the authenticatingAuthority setting) when inheritance is in effect since the absence of the setting will trigger the inheritance. To support this (hopefully very rare) situation, you can define Application overrides using a special bean named shibboleth.sp.Application.NoInheritance.

This definition explicitly turns off any inheritance back to the parent Agent’s default Application and for convenience the bean definition “redefines” its settings based on the system’s defaults, global properties, etc. For example, its issuer property will default to the value of the sp.issuer global property.

Example

To see this in action, the example below shows a few of the various beans.

For the purposes of the example, the following Java properties are set:

  • sp.issuer = https://example.org/sp

  • sp.defaultAuthority = https://example.org/idp

Assume the following content in agents.xml:

<bean p:id="localhost" parent="shibboleth.sp.Agent" /> <bean p:id="sp2.example.org" parent="shibboleth.sp.Agent" p:issuer="https://example.org/sp2" p:authenticatingAuthority="https://example.org/idp2"> <property name="applications"> <list> <bean p:id="override1" parent="shibboleth.sp.Application" p:authenticatingAuthority="#{null}"> <property name="relyingPartyConfigurations"> <list> <bean parent="RelyingPartyByName" c:relyingPartyIds="https://example.org/op1" /> </list> </property> </bean> <bean p:id="override2" parent="shibboleth.sp.Application.NoInheritance"> <property name="relyingPartyConfigurations"> <list> <bean parent="RelyingPartyByName" c:relyingPartyIds="https://example.org/op2" /> </list> </property> </bean> </list> </property> <property name="relyingPartyConfigurations"> <list> <bean parent="RelyingPartyByName" c:relyingPartyIds="https://example.org/op3" p:issuer="https://example.org/rp3"/> </list> </property> </bean>

In the example, there is a single Agent with a few properties set and some overrides of various kinds. The issuer and authenticatingAuthority settings will be as follows:

  • Agent is “localhost“

    • Application is “default”

      • No authority specified in request

        • issuer → “https://example.org/sp” (as set via Java property)

        • authenticatingAuthority → “https://example.org/idp” (as set via Java property)

      • Agent request specifies authority is “https://example.org/op3”

        • issuer → “https://example.org/sp” (as set via Java property)

  • Agent is “sp2.example.org”

    • Application is “default”

      • No authority specified in request

        • issuer → “https://example.org/sp2”

        • authenticatingAuthority → “https://example.org/idp2”

      • Agent request specifies authority is “https://example.org/op3”

        • issuer → “https://example.org/rp3” (as the global/default RPC override for this system is in effect)

    • Application is “override1”

      • No authority specified in request

        • issuer → “https://example.org/sp2”

        • authenticatingAuthority → null

      • Agent request specifies authority is “https://example.org/op3”

        • issuer → “https://example.org/sp2” (as set via parent Agent because the global/default RPC override list was supplanted)

    • Application is “override2”

      • No authority specified in request

        • issuer → “https://example.org/sp” (as set via Java property since inheritance was disabled)

        • authenticatingAuthority → “https://example.org/idp” (as set via Java property since inheritance was disabled)

      • Agent request specifies authority is “https://example.org/op3”

        • issuer → “https://example.org/sp” (as set via Java property because the global/default RPC override list was supplanted)