Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Expand
titleCustom RelyingParty Example
Code Block
languagexml
<bean id="exampleOrgRegex" class="java.util.regex.Pattern" factory-method="compile"
	c:_0="^https://sp[\d].example\.org/shibboleth$" />

<bean id="exampleOrgRegexPredicate"
	class="com.google.common.base.Predicates" factory-method="contains"
	c:_0-ref="exampleOrgRegex" />

<bean id="custom.RelyingPartyCondition" 	classparent="net.shibboleth.idp.profile.logic.RelyingPartyIdPredicateConditions.RelyingPartyId"
	c:_0-ref="exampleOrgRegexPredicate" />

<bean id="CustomRelyingParty" parent="RelyingParty" p:activationCondition-ref="custom.RelyingPartyCondition">
	<property name="profileConfigurations">
		<list>
			<!-- Your refs or beans here. -->
		</list>
	</property>
</bean>

...

Expand
titleDynamic Overrides

All of the profile settings that can be set statically can also be computed via functions or predicates/conditions that execute at runtime. It's a better idea to look into MetadataDrivenConfiguration then to explore this feature. This is the low-level feature that makes metadata-driven settings possible but using metadata is usually more elegant and the system does all the fancy wiring for you.

The use of this feature helps if you want to apply "cross-cutting" conditions to get around the limitation that overrides don't get merged. For example, consider the following use cases:

  • You want to enable consent for attribute release for a specific set of relying parties.

  • You want to downgrade to the use of SHA-1 for a specific set of relying parties.

Of course, if these two sets don't overlap, and you have nothing else unusual to specify, you could create two overrides for each set individually. But what if the two sets overlap, with some relying parties in one, some in the other, and some in both? Now you need three overrides. Now consider that a third set requires an additional non-default setting and overlaps with some of the first two sets. The number of overrides will get out of hand quickly and start to get very confusing to manage.

As an example, let's tackle the cases above by using scripts to derive the settings involved. This can potentially be done with no overrides at all, as below, though that's a matter of style.

Use of scripts to derive profile settings
Code Block
languagexml
<!-- Whether to run attribute release interceptor. -->
<bean id="InterceptorScript" parent="shibboleth.ContextFunctions.Scripted" factory-method="inlineScript">
    <constructor-arg>
        <value>
		<![CDATA[
		interceptors = null;
		rpid = "";
		rpCtx = input.getSubcontext("net.shibboleth.idp.profile.context.RelyingPartyContext");
		if (rpCtx != null) {
			rpid = rpCtx.getRelyingPartyId();
        }

		if (rpid.equals("https://sp1.example.org/sp") ||
			rpid.equals("https://sp2.example.org/sp") ||
			rpid.equals("https://sp3.example.org/sp")) {

			listType =  Java.type("java.util.ArrayList");
			interceptors = new listType(1);
			interceptors.add("attribute-release");
		}

		interceptors;
		]]>
        </value>
    </constructor-arg>
</bean>

<!-- Map of security configurations for use by next script. -->
<util:map id="SecurityConfigMap">
	<entry key="SHA2" value-ref="shibboleth.DefaultSecurityConfiguration"/>
	<entry key="SHA1" value-ref="shibboleth.SecurityConfiguration.SHA1" />
</util:map>

<!-- Whether to use SHA-1. -->
<bean id="SecurityConfigScript" parent="shibboleth.ContextFunctions.Scripted"
	factory-method="inlineScript"
	p:customObject-ref="SecurityConfigMap">
    <constructor-arg>
        <value>
		<![CDATA[
		rpid = "";
		rpCtx = input.getSubcontext("net.shibboleth.idp.profile.context.RelyingPartyContext");
		if (rpCtx != null) {
			rpid = rpCtx.getRelyingPartyId();
        }

		securityConfig = custom["SHA2"];

		if (rpid.equals("https://sp2.example.org/sp") ||
			rpid.equals("https://sp3.example.org/sp") ||
			rpid.equals("https://sp4.example.org/sp")) {

			securityConfig = custom["SHA1"];
		}

		securityConfig;
		]]>
        </value>
    </constructor-arg>
</bean>

<!-- Apply the scripts to derive settings. -->
<bean id="shibboleth.DefaultRelyingParty" parent="RelyingParty">
	<property name="profileConfigurations">
		<list>
			<bean parent="Shibboleth.SSO"
				p:postAuthenticationFlowsLookupStrategy-ref="InterceptorScript"
				p:securityConfigurationLookupStrategy-ref="SecurityConfigScript" />
			<bean parent="SAML2.SSO"
				p:postAuthenticationFlowsLookupStrategy-ref="InterceptorScript"
				p:securityConfigurationLookupStrategy-ref="SecurityConfigScript" />
			<ref bean="SAML2.ECP"
				p:securityConfigurationLookupStrategy-ref="SecurityConfigScript" />
			<ref bean="SAML2.Logout"
				p:securityConfigurationLookupStrategy-ref="SecurityConfigScript" />
		</list>
	</property>
</bean>

Obviously the example above is somewhat contrived. It's longer than just creating three overrides, but it illustrates the general idea and once you get comfortable using scripts, it isn't as bad as it looks. It's also possible to put scripts in separate files, which makes the XML much shorter.

This becomes much more powerful when combined with other techniques, particularly the use of tag-based conditions based on <EntityAttribute> extensions in SAML metadata, which can be applied by metadata registrars or locally using a metadata filter.

A built-in way of doing this is described in the MetadataDrivenConfiguration topic, and this is the generally-advisable means of handling complex configuration of behavior now.

...