102 lines
5.4 KiB
XML
102 lines
5.4 KiB
XML
|
<?xml version="1.0" encoding="UTF-8"?>
|
||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||
|
xmlns:context="http://www.springframework.org/schema/context"
|
||
|
xmlns:util="http://www.springframework.org/schema/util"
|
||
|
xmlns:p="http://www.springframework.org/schema/p"
|
||
|
xmlns:c="http://www.springframework.org/schema/c"
|
||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||
|
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
|
||
|
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
|
||
|
|
||
|
default-init-method="initialize"
|
||
|
default-destroy-method="destroy">
|
||
|
|
||
|
<!--
|
||
|
This is a map of transition rules that guide the behavior of the MFA flow
|
||
|
and controls how factors are sequenced, skipped, etc. The key of each entry
|
||
|
is the name of the step/flow out of which control is passing. The starting
|
||
|
rule has an empty key.
|
||
|
|
||
|
Each entry is a bean inherited from "shibboleth.authn.MFA.Transition". Per
|
||
|
the Javadoc for net.shibboleth.idp.authn.MultiFactorAuthenticationTransition:
|
||
|
|
||
|
p:nextFlow (String)
|
||
|
- A flow to run if the previous step signaled a "proceed" event, for simple
|
||
|
transitions.
|
||
|
|
||
|
p:nextFlowStrategy (Function<ProfileRequestContext,String>)
|
||
|
- A function to run if the previous step signaled a "proceed" event, for dynamic
|
||
|
transitions. Returning null ends the MFA process.
|
||
|
|
||
|
p:nextFlowStrategyMap (Map<String,Object> where Object is String or Function<ProfileRequestContext,String>)
|
||
|
- Fully dynamic way of expressing control paths. Map is keyed by a previously
|
||
|
signaled event and the value is a flow to run or a function to
|
||
|
return the flow to run. Returning null ends the MFA process.
|
||
|
|
||
|
When no rule is provided, there's an implicit "null" that ends the MFA flow
|
||
|
with whatever event was last signaled. If the "proceed" event from a step is
|
||
|
the final event, then the MFA process attempts to complete itself successfully.
|
||
|
-->
|
||
|
<util:map id="shibboleth.authn.MFA.TransitionMap">
|
||
|
<!-- First rule runs the IPAddress login flow. -->
|
||
|
<entry key="">
|
||
|
<bean parent="shibboleth.authn.MFA.Transition" p:nextFlow="authn/IPAddress" />
|
||
|
</entry>
|
||
|
|
||
|
<!--
|
||
|
Second rule runs a function if IPAddress succeeds, to determine whether an additional
|
||
|
factor is required.
|
||
|
-->
|
||
|
<entry key="authn/IPAddress">
|
||
|
<bean parent="shibboleth.authn.MFA.Transition" p:nextFlowStrategy-ref="checkSecondFactor" />
|
||
|
</entry>
|
||
|
|
||
|
<!-- An implicit final rule will return whatever the final flow returns. -->
|
||
|
</util:map>
|
||
|
|
||
|
<!-- Example script to see if second factor is required. -->
|
||
|
<bean id="checkSecondFactor" parent="shibboleth.ContextFunctions.Scripted" factory-method="inlineScript"
|
||
|
p:customObject-ref="shibboleth.AttributeResolverService">
|
||
|
<constructor-arg>
|
||
|
<value>
|
||
|
<![CDATA[
|
||
|
nextFlow = "authn/Password";
|
||
|
|
||
|
// Go straight to second factor if we have to, or set up for an attribute lookup first.
|
||
|
authCtx = input.getSubcontext("net.shibboleth.idp.authn.context.AuthenticationContext");
|
||
|
mfaCtx = authCtx.getSubcontext("net.shibboleth.idp.authn.context.MultiFactorAuthenticationContext");
|
||
|
if (mfaCtx.isAcceptable()) {
|
||
|
// Attribute check is required to decide if first factor alone is enough.
|
||
|
resCtx = input.getSubcontext(
|
||
|
"net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext", true);
|
||
|
rpCtx = input.getSubcontext("net.shibboleth.idp.profile.context.RelyingPartyContext");
|
||
|
resCtx.setAttributeRecipientID(rpCtx.getRelyingPartyId());
|
||
|
|
||
|
// Look up the username using a standard function.
|
||
|
usernameLookupStrategyClass
|
||
|
= Java.type("net.shibboleth.idp.session.context.navigate.CanonicalUsernameLookupStrategy");
|
||
|
usernameLookupStrategy = new usernameLookupStrategyClass();
|
||
|
resCtx.setPrincipal(usernameLookupStrategy.apply(input));
|
||
|
|
||
|
resCtx.getRequestedIdPAttributeNames().add("allowedLoginMethods");
|
||
|
resCtx.resolveAttributes(custom);
|
||
|
|
||
|
// Check for an attribute that authorizes use of first factor.
|
||
|
attribute = resCtx.getResolvedIdPAttributes().get("allowedLoginMethods");
|
||
|
valueType = Java.type("net.shibboleth.idp.attribute.StringAttributeValue");
|
||
|
if (attribute != null && attribute.getValues().contains(new valueType("IPAddress"))) {
|
||
|
nextFlow = null;
|
||
|
}
|
||
|
|
||
|
input.removeSubcontext(resCtx); // cleanup
|
||
|
}
|
||
|
|
||
|
nextFlow; // pass control to second factor or end with the first
|
||
|
]]>
|
||
|
</value>
|
||
|
</constructor-arg>
|
||
|
</bean>
|
||
|
|
||
|
</beans>
|