The Shibboleth IdP V4 software will leave support on September 1, 2024.

Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 15 Next »

Current File(s): conf/intercept/context-check-intercept-config.xml

Format: Native Spring

Overview

The "context-check" interceptor flow is an example of how to use an interceptor to interrupt processing and either continue or halt processing based on the state of the "context tree" that makes up the state of the request. A common use case for this feature is to impose authorization rules at the IdP to work around the limitations of a service that either does not implement any authorization or does not provide an adequate user experience in the event of failure. A frequently cited example of the latter is Google Apps for Education. Must be their limited budget.

Everything about a request is tracked in the tree of context objects (or can be injected into the condition bean applied), so there is no "hidden" information. Anything is on the table for examination, including:

  • information about the relying party

  • information about the user, the user's session, the user's authentication state, or attributes

  • environmental information from the client request

  • any configuration/rules you define and inject with Spring

All interceptors are enabled or disabled on a per-relying-party basis using properties in the profile bean(s) you want to enable the flow for. See the ProfileInterceptConfiguration topic for an example.

Enabling Module (V4.1+)

For V4.1+, configuring and using this feature requires that you first enable the "idp.intercept.ContextCheck" module if it isn't already enabled. Systems upgraded from older releases generally come pre-enabled due to the prior state of the configuration tree.

(Windows)
C:\opt\shibboleth-idp> bin\module.bat -t idp.intercept.ContextCheck || bin\module.bat -e idp.intercept.ContextCheck
 
(Other)
$ bin/module.sh -t idp.intercept.ContextCheck || bin/module.sh -e idp.intercept.ContextCheck

General Configuration

This flow can operate in a limited "single condition" mode, or a more flexible functional mode. The functional mode is strongly suggested.

Notable Events

A couple of internal event strings are noteworthy for some specific cases that come up occasionally. Your flow can signal these events to cause the IdP to react in a controlled way:

  • RestartAuthentication

    • This event will cause the IdP to reset the request state and start the authentication (and attribute resolution) stages from scratch.

  • UpdateSecurityParameters

    • This event will cause the IdP to re-derive the internal settings that govern how the IdP identifies itself and how it signs and encrypts messages. As an example, if the IdP's entityID and/or signing key needs to change mid-transaction, you can install functions into the profile configuration to derive them dynamically and signal this event to cause those functions to be called again in case their results are expected to be different.

Examples

Enforcing Authentication Policy

In most cases, it is strongly advisable that the authentication "strength" required for a given transaction be managed by expressing requirements through requested principal types associated with the request, either via a SAML 2.0 <RequestedAuthnContext> element, or when necessary via the defaultAuthenticationMethods Profile Configuration property. When properly configured, the IdP will automatically prevent an inadequate authentication result from being used for a request.

In some cases, this may not be sufficient, such as when the user's identity or associated attributes dictate whether authentication is sufficient, regardless of the service. If the MFA login flow is being used, the suggested approach is to manipulate the RequestedPrincipalContext object in the context tree as part of the MFA ruleset, so that the IdP will enforce the appropriate policy for you.

If the MFA login flow is not being used, another possible technique is to perform this enforcement check yourself by means of this interceptor flow. As a simple example, consider a case where the presence of an attribute is a signal to require a particular principal be present in the result. The example demonstrates use of an InCommon-defined MFA profile in which the values represent "use of MFA" or "non-use of MFA".

Example enforcing use of MFA based on user policy
 Example enforcing use of MFA based on user policy
<!--
	Returns true if a user's directory entity authorizes use of the "basic" profile or
	if the active results include the "mfa" profile constant.
	-->
    <bean id="shibboleth.context-check.Condition" parent="shibboleth.Conditions.OR">
        <constructor-arg>
            <list>
                <bean class="net.shibboleth.idp.profile.logic.SimpleAttributePredicate"
                        p:useUnfilteredAttributes="true">
                    <property name="attributeValueMap">
                        <map>
                            <entry key="eduPersonAssurance">
                                <list>
                                    <value>http://id.incommon.org/assurance/basic</value>
                                </list>
                            </entry>
                        </map>
                    </property>
                </bean>
                <ref bean="CheckForMFA" />
            </list>
        </constructor-arg>
    </bean>

	<!-- Checks all the active authentication results for the appropriate AuthnContextClassRefPrincipal. -->
	<bean id="CheckForMFA" parent="shibboleth.Conditions.Scripted" factory-method="inlineScript">
		<constructor-arg>
			<value>
<![CDATA[
			value = false;

			principalType = Java.type("net.shibboleth.idp.saml.authn.principal.AuthnContextClassRefPrincipal");

			subjectCtx = profileContext.getSubcontext("net.shibboleth.idp.authn.context.SubjectContext");
			if (subjectCtx != null) {
				var subjectIter = subjectCtx.getSubjects().iterator();
				while (!value && subjectIter.hasNext()) {
					var princIter = subjectIter.next().getPrincipals(principalType.class).iterator();
					while (!value && princIter.hasNext()) {
						if (princIter.next().getName() == "http://id.incommon.org/assurance/mfa") {
							value = true;
						}
					}
				}
			}

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

Reference


  • No labels