Current File(s): conf/authn/mfa-authn-config.xml, conf/authn/authn.properties (V4.1+)
Format: Native Spring, Properties (V4.1+)
Table of Contents | ||||
---|---|---|---|---|
|
Overview
The authn/MFA login flow is a special "composite" mechanism that provides a scriptable (or programmable) way of combining other login flows to produce simple or complex sequences of login challenges that combine to provide stronger or more flexible authentication options than individual methods can provide on their own.
...
By itself, the MFA flow is just an orchestration tool and doesn't itself perform any specific kinds of authentication, instead relying on existing login methods to do its work, together with rules you must provide to control behavior. It requires that you plan out what you need to do first, and then implement that plan using Java code or Java Scripting to supply the business logic.
General Configuration
Localtabgroup | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Tip |
---|
Note that when you use the MFA flow, it's common that it will be the only flow enabled via the idp.authn.flows property. In particular, any flows you direct the MFA flow to run via rules and scripts should not be enabled themselves because to do so may cause the IdP to run them itself in ways that are likely to subvert your intent. |
Tip |
---|
Another note which is repeated below, regarding the overall method selection process: at the top level, the IdP won't run the MFA login flow at all if its As an example, if your MFA processing rules allow for certificate authentication, then you will need to ensure the MFA flow includes appropriate supported principals reflecting use of certificates, or the IdP won't know it can run the MFA flow for requests for that type of authentication. |
A bean called shibboleth.authn.MFA.TransitionMap contains the map of rules to run to control the transition between flows and determine when to complete work. This is a map whose keys are the flows to "exit" from, and whose values are a bean of the class type net.shibboleth.idp.authn.MultiFactorAuthenticationTransition (a parent bean called shibboleth.authn.MFA.Transition is provided). The first rule is marked with an empty or null key value in the map.
Each transition rule is a mapping from the exit state (event) of a flow and the logic to run to decide the next flow to run. There are a couple of simple properties to define transitions to use after a "proceed" event (the usual success indicator), and a more advanced property to supply a full range of event/logic mappings.
If you need to support multiple workflows at the same time (e.g., if you wish to deploy special workflows to handle different profiles and functions provided by the IdP), you can supply a function in a bean called shibboleth.authn.MFA.TransitionMapStrategy to return the actual map of rules to use. Normally a single set is enough, since you can embed conditional logic in the rules, but this provides a separate axis of conditional logic you can use.
Defining Transitions
There are three approaches to defining transitions, outlined below, with examples.
Directly Selecting Flows
The simplest type of transition rule just provides a specific subflow to run if the previous step (if any) was successful. This is specified with the nextFlow
property of a transition bean. Note that this can invoke any subflow, not just login flows, though that is the most common case. You could build your own subflows to display views to collect user input, etc. and invoke them using the same mechanism.
Consider a simple example that implements this sequence:
- Run the "authn/Flow1" flow.
- If Step 1 succeeds, run the "authn/Flow2" flow.
- If Step 2 succeeds, combine the results of the two flows into one.
- If either Step 1 or 2 fails, return that failure as the MFA flow result.
This simple example doesn't require any logic or scripting:
...
Enabling Module (V4.1+)
For V4.1+, configuring and using this feature requires that you first enable the "idp.authn.MFA" 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.
Code Block |
---|
(Windows)
C:\opt\shibboleth-idp> bin\module.bat -t idp.authn.MFA || bin\module.bat -e idp.authn.MFA
(Other)
$ bin/module.sh -t idp.authn.MFA || bin/module.sh -e idp.authn.MFA |
General Configuration
Expand | ||
---|---|---|
| ||
Use authn/mfa-authn-config.xml to configure this flow. |
Expand | ||
---|---|---|
| ||
Most of the flow configuration is in authn/mfa-authn-config.xml but some generic settings applicable to all login flows are in authn/authn.properties. |
Tip |
---|
Note that when you use the MFA flow, it's common that it will be the only flow enabled via the idp.authn.flows property. In particular, any flows you direct the MFA flow to run via rules and scripts should not be enabled themselves because to do so may cause the IdP to run them itself in ways that are likely to subvert your intent. |
Tip |
---|
Another note which is repeated below, regarding the overall method selection process: at the top level, the IdP won't run the MFA login flow at all if its As an example, if your MFA processing rules allow for certificate authentication, then you will need to ensure the MFA flow includes appropriate supported principals reflecting use of certificates, or the IdP won't know it can run the MFA flow for requests for that type of authentication. |
A bean called shibboleth.authn.MFA.TransitionMap contains the map of rules to run to control the transition between flows and determine when to complete work. This is a map whose keys are the flows to "exit" from, and whose values are a bean of the class type net.shibboleth.idp.authn.MultiFactorAuthenticationTransition (a parent bean called shibboleth.authn.MFA.Transition is provided). The first rule is marked with an empty or null key value in the map.
Each transition rule is a mapping from the exit state (event) of a flow and the logic to run to decide the next flow to run. There are a couple of simple properties to define transitions to use after a "proceed" event (the usual success indicator), and a more advanced property to supply a full range of event/logic mappings.
If you need to support multiple workflows at the same time (e.g., if you wish to deploy special workflows to handle different profiles and functions provided by the IdP), you can supply a function in a bean called shibboleth.authn.MFA.TransitionMapStrategy to return the actual map of rules to use. Normally a single set is enough, since you can embed conditional logic in the rules, but this provides a separate axis of conditional logic you can use.
Defining Transitions
There are three approaches to defining transitions, outlined below, with examples.
Directly Selecting Flows
The simplest type of transition rule just provides a specific subflow to run if the previous step (if any) was successful. This is specified with the nextFlow
property of a transition bean. Note that this can invoke any subflow, not just login flows, though that is the most common case. You could build your own subflows to display views to collect user input, etc. and invoke them using the same mechanism.
Consider a simple example that implements this sequence:
Run the "authn/Flow1" flow.
If Step 1 succeeds, run the "authn/Flow2" flow.
If Step 2 succeeds, combine the results of the two flows into one.
If either Step 1 or 2 fails, return that failure as the MFA flow result.
This simple example doesn't require any logic or scripting:
Simple sequence of factors Flow1 and Flow2
Expand | |||||
---|---|---|---|---|---|
|
The "combine the results" behavior in step 3 above actually comes from a built-in bean that you can override for more customized behavior. A bean named shibboleth.authn.MFA.resultMergingStrategy will be used to supply a function to run to merge together all of the authentication results produced by an entire sequence of steps in a customized way (this is discussed in more detail below).
...
This relatively complex example relies on a single script that does a number of interesting things to achieve the following sequence:
Run the "authn/Flow1" flow.
If Step 1 succeeds and the result is sufficient to satisfy the request, resolve an attribute about the user identified by Step 1.
If the result from Step 1 is sufficient AND the attribute resolved indicates that a user may use that method alone, then finish with the result from Step 1.
If the result from Step 1 is not sufficient OR the attribute resolved indicates that an additional factor is required, run the "authn/Flow2" flow.
If successful, combine the results from the two flows into one.
If either method fails, return that failure as the MFA flow result.
...
Conditional use of two factors, Flow1 and Flow2
collapse | true|||||
---|---|---|---|---|---|
Expand | |||||
|
There's a fair amount going in on the script, but it's mostly just navigating and populating contexts into the tree, and the whole middle section is doing the attribute lookup and check.
...
For full control, you must build a map bean and set it as the value of the nextFlowStrategyMap
property of a transition bean. The keys to the map are the events to "catch", and the values of the map can either be a simple String (a subflow to run) or a Function<ProfileRequestContext,String> to run to return the flow to run.
...
As an example, if you built a view-centric flow that signaled events indicating the type of authentication to perform, it might look something like the following:
...
Example with a method selection UI
Expand | ||||||||
---|---|---|---|---|---|---|---|---|
| collapse
| true
|
The example above is geared around using a dedicated custom webflow to offer a selection UI, so such a flow controls its own rules for what events it can signal. If you wanted to, for example, stick a button or link on the login form used by the Password login flow and signal that back to the MFA logic as a custom event, you will need to modify conf/authn/authn-events-flow.xml (see the general discussion under Custom Events).
...
The IdP expects/requires a login flow to produce a single AuthenticationResult when it finishes work successfully. To avoid a total redesign, the MFA flow is built to maintain this constraint by combining the individual results it may accumulate in the course of executing into one final result. It does this using a default function that can be overridden by defining a bean named shibboleth.authn.MFA.resultMergingStrategy of type Function<ProfileRequestContext,AuthenticationResult> (i.e., a function that returns the result to use).
It is hoped that the default behavior will be sufficient for most people, which is to perform a true merge of all of the Principals, and public and private Credentials contained in the individual Subjects across all of the active results contained in the MultiFactorAuthenticationContext that tracks the overall state of the request. In addition, to enable the SSO behavior described below, the default function actually wraps the individual results into a special custom Principal type that allows the MFA login flow to actually recover the individual results that it obtained earlier and use them to avoid re-prompting a user with factors that have already been performed, just as the IdP itself does.
...
One thing that is normally done by the IdP that is not done in the MFA flow is to check whether individual login flows are compatible with the authentication requirements of a request (see also AuthenticationFlowSelection). Often MFA scenarios require more customized decision making (e.g., forcing use of a method because of the user's identity, or preventing a method from running for some reason), and so you have more latitude in this area. But you need to bear in mind that at the end of the process, the result you produce had still better satisfy the request or the IdP will reject it. For example, if a service requests strong authentication in some way, and you short-circuit that by returning the result of password authentication and you accurately communicate that, that is likely to be rejected by the IdP and fail the request. You can lie of course, with sufficient cleverness, but the IdP isn't going to lie for you.
...
Unless a request includes forced re-authentication, any active/previous results produced and tracked by the MFA flow will be reused under these conditions:
the login flow is known to the system (i.e., it hasn't been removed with no descriptor bean left in place)
the result remains within the lifetime of the login flow, per policy
You will note this does not include a check for whether the result is specifically applicable to the request's requirements, because it assumes you are in control of that decision if you choose to run the flow.
...
There is an explicit property you can set on the login flow descriptor bean in authn/general-authn.xml (V4.0), or by defining a bean and setting a corresponding idp.authn.FlowMFA.reuseCondition property (V4.1+) that attaches a second kind of condition logic to the login flows called a "reuse condition". Think of it as a "SSO or not?" flag on each login method that allows you to customize when the system will reuse a previously built result or re-run the flow. This is possible with any login flow, but it's of particular value with the MFA flow since it generally contains logic that may need to run to determine whether SSO should happen.
You can split these concerns any way you prefer, but if you can include at least some of your logic in the reuse condition rather than the MFA logic itself, that can improve efficiency. But in the simplest case, if you want the MFA rules to run on every request no matter what:
Localtabgroup | |||||||
---|---|---|---|---|---|---|---|
Localtab | active | true||||||
Expand | |||||||
| |||||||
Code Block | |||||||
xml | title |
Code Block | ||
---|---|---|
| ||
...
<bean id="authn/MFA" parent="shibboleth.AuthenticationFlow"
p:passiveAuthenticationSupported="true" p:forcedAuthenticationSupported="true" p:reuseCondition="false"> ...etc... </bean> ... |
Expand | ||||
---|---|---|---|---|
| code||||
title |
Code Block |
---|
...
idp.authn.MFA.reuseCondition = shibboleth.Conditions.FALSE
... |
That simply says "never reuse results". Bear in mind this is referring to the MFA flow itself, and not the individual "sub factors" that it uses internally to build its results, so individual factors may have results reused when the MFA logic actually runs them, which is generally what is desired.
For more advanced cases or to improve efficiency, a bean can be defined for a script or Java logic that defines the condition to evaluate to decide on reuse, and you can attach that bean by name.
Reference
Beans
The beans defined in authn/mfa-authn-config.xml follow:
...
shibboleth.authn.MFA.TransitionMap
Map<String,MultiFactorAuthenticationTransition>
...
shibboleth.authn.MFA.TransitionMapStrategy
Function<ProfileRequestContext,Map<String,MultiFactorAuthenticationTransition>
...
shibboleth.authn.MFA.Transition
MultiFactorAuthenticationTransition
...
shibboleth.authn.MFA.validateLoginTransitions
Boolean
...
shibboleth.authn.MFA.resultMergingStrategy
Function<ProfileRequestContext,AuthenticationResult>
...
shibboleth.authn.MFA.resultCachingPredicate
Predicate<ProfileRequestContext>
...
Notes
It's been observed by early deployersto evaluate to decide on reuse, and you can attach that bean by name.
Reference
Expand | |||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| |||||||||||||||||||||
The beans defined in authn/mfa-authn-config.xml follow:
|
Expand | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||||||||
The beans defined in authn/mfa-authn-config.xml follow:
|
Expand | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Properties specific to this flow defined in authn/authn.properties are:
The general properties configuring this flow via authn/authn.properties are:
As a generic flow, the
In property form, this is expressed as:
This default is not intended to be applicable to most systems, but matches the behavior of the flow's default/example configuration which accounts for both the IPAddress and Password flows being combined. |
Expand | |||||
---|---|---|---|---|---|
| |||||
To replace the internally defined flow descriptor bean, the following XML is required:
In older versions and upgraded systems, this list is defined in conf/authn/general-authn.xml. In V4.1+, no default version of the list is provided and it may simply be placed in conf/global.xml if needed. |
Notes
It's been observed, accurately, that the data required to track the use of this feature in the session cache is on the order of 2-3 times as large as just a "simple" authentication result. While it is believed that this remains acceptable with the use of cookies, and certainly with HTML Storage, some storage service implementations such as that for Memcached rely on a less reliable persistence model that may prematurely evict data, so such options may not be a good fit with this feature.