IDPv3.3 and programmatically selecting MFA based on attribute

Jeffrey Eaton jeaton at cmu.edu
Sun Jan 22 15:46:19 EST 2017


I am trying to recreate functionality in the current IDPv3.3 code which we currently are using with IDPv3.2 with the Chicago/Unicon Duo code.  Basically, the decision to require Duo (in addition to Password) can be made either by the SP (by requesting our custom AuthContext), or by the IDP (based on an attribute of the user).  So, for example, if a user in the GrouperAdmins group is logging in to the grouper SP, then Duo is enforced by the IDP, but for a non-privledged user, just password is enough.

So far the native MFA flow support in IDPv3 looks great and much more straightforward to implement than the Chicago/Unicon code that I was using, and I have the basics working.

If I first go to an SP with no particular requirements, then the IDP calls the MFA flow, does Password, checks my custom attribute (which returns saying that Password is sufficient), and then returns to the SP as expected.

If I first go to an SP with identity-driven Duo requirements, then the IDP calls the MFA flow, does Password, checks my custom attribute (which returns requesting Duo for an admin), then runs the Duo flow, then returns to the SP as expected:

2017-01-22 14:41:53,517 - DEBUG [net.shibboleth.idp.authn.impl.SelectAuthenticationFlow:255] - Profile Action SelectAuthenticationFlow: No specific Principals requested
2017-01-22 14:41:53,517 - DEBUG [net.shibboleth.idp.authn.impl.SelectAuthenticationFlow:290] - Profile Action SelectAuthenticationFlow: No usable active results available, selecting an inactive flow
2017-01-22 14:41:53,517 - DEBUG [net.shibboleth.idp.authn.impl.SelectAuthenticationFlow:338] - Profile Action SelectAuthenticationFlow: Selecting inactive authentication flow authn/MFA
2017-01-22 14:41:53,521 - DEBUG [net.shibboleth.idp.authn.impl.PopulateMultiFactorAuthenticationContext:164] - Profile Action PopulateMultiFactorAuthenticationContext: 0 active result(s) extracted for possible reuse
2017-01-22 14:41:53,522 - DEBUG [net.shibboleth.idp.authn.impl.TransitionMultiFactorAuthentication:195] - Profile Action TransitionMultiFactorAuthentication: Applying MFA transition rule to determine initial state
2017-01-22 14:41:53,522 - DEBUG [net.shibboleth.idp.authn.impl.TransitionMultiFactorAuthentication:214] - Profile Action TransitionMultiFactorAuthentication: MFA flow transition after 'proceed' event to 'authn/Password' flow
[snip]
2017-01-22 14:41:56,965 - DEBUG [net.shibboleth.idp.authn.impl.TransitionMultiFactorAuthentication:197] - Profile Action TransitionMultiFactorAuthentication: Applying MFA transition rule to exit state 'authn/Password'
2017-01-22 14:41:56,967 - DEBUG [net.shibboleth.idp.attribute.resolver.impl.AttributeResolverImpl:213] - Attribute Resolver 'ShibbolethAttributeResolver': Initiating attribute resolution
2017-01-22 14:41:56,968 - DEBUG [net.shibboleth.idp.attribute.resolver.impl.AttributeResolverImpl:221] - Attribute Resolver 'ShibbolethAttributeResolver': Attempting to resolve the following attribute definitions [eduPersonAssurance]
2017-01-22 14:41:56,968 - DEBUG [net.shibboleth.idp.attribute.resolver.impl.AttributeResolverImpl:411] - Attribute Resolver 'ShibbolethAttributeResolver': Resolving dependencies for 'eduPersonAssurance'
2017-01-22 14:41:56,968 - DEBUG [net.shibboleth.idp.attribute.resolver.impl.AttributeResolverImpl:411] - Attribute Resolver 'ShibbolethAttributeResolver': Resolving dependencies for 'isMemberOf’
[snip]
2017-01-22 14:41:57,191 - DEBUG [net.shibboleth.idp.attribute.resolver.AbstractAttributeDefinition:247] - Attribute Definition 'eduPersonAssurance': produced an attribute with the following values [StringAttributeValue{value=https://login.cmu.edu/duo}]
[snip]
2017-01-22 14:41:57,198 - DEBUG [net.shibboleth.idp.authn.impl.TransitionMultiFactorAuthentication:214] - Profile Action TransitionMultiFactorAuthentication: MFA flow transition after 'proceed' event to 'authn/Duo' flow
2017-01-22 14:42:02,264 - INFO [net.shibboleth.idp.authn.duo.impl.ValidateDuoWebResponse:202] - Profile Action ValidateDuoWebResponse: Duo authentication succeeded for 'jeaton'
2017-01-22 14:42:02,266 - DEBUG [net.shibboleth.idp.authn.AbstractValidationAction:341] - Profile Action ValidateDuoWebResponse: Adding custom Principal(s) defined on underlying flow descriptor
2017-01-22 14:42:02,267 - DEBUG [net.shibboleth.idp.authn.impl.TransitionMultiFactorAuthentication:184] - Profile Action TransitionMultiFactorAuthentication: Preserving authentication result from 'authn/Duo' flow
2017-01-22 14:42:02,267 - DEBUG [net.shibboleth.idp.authn.impl.TransitionMultiFactorAuthentication:197] - Profile Action TransitionMultiFactorAuthentication: Applying MFA transition rule to exit state 'authn/Duo'
2017-01-22 14:42:02,267 - DEBUG [net.shibboleth.idp.authn.impl.TransitionMultiFactorAuthentication:219] - Profile Action TransitionMultiFactorAuthentication: MFA flow completing with event 'proceed'
2017-01-22 14:42:02,268 - DEBUG [net.shibboleth.idp.authn.impl.FinalizeMultiFactorAuthentication:193] - Profile Action FinalizeMultiFactorAuthentication: MFA complete, producing merged result


What doesn’t work is “stepping up”.  If I go to first the non-Duo requiring SP, I am prompted for password then sent to the SP.  If I then go to the optionally Duo-requiring SP, it never seems to perform the MFA flow to check for second factor.  The logs indicate that it simply accepts the prior password-only MFA flow:

2017-01-22 14:42:56,859 - DEBUG [net.shibboleth.idp.session.impl.StorageBackedIdPSession:536] - Loading AuthenticationResult for flow authn/MFA in session aef1afafdfe31595a25de225f98e804e300b2a41c8b0c63b442600ea9f8656ff
2017-01-22 14:42:56,860 - DEBUG [net.shibboleth.idp.session.impl.ExtractActiveAuthenticationResults:124] - Profile Action ExtractActiveAuthenticationResults: Authentication result authn/MFA is active, copying from session
2017-01-22 14:42:56,861 - DEBUG [net.shibboleth.idp.authn.impl.InitializeRequestedPrincipalContext:152] - Profile Action InitializeRequestedPrincipalContext: Profile configuration did not supply any default authentication methods
2017-01-22 14:42:56,862 - DEBUG [net.shibboleth.idp.authn.impl.FilterFlowsByForcedAuthn:53] - Profile Action FilterFlowsByForcedAuthn: Request does not have forced authentication requirement, nothing to do
2017-01-22 14:42:56,862 - DEBUG [net.shibboleth.idp.authn.impl.FilterFlowsByNonBrowserSupport:53] - Profile Action FilterFlowsByNonBrowserSupport: Request does not have non-browser requirement, nothing to do
2017-01-22 14:42:56,862 - DEBUG [net.shibboleth.idp.authn.impl.SelectAuthenticationFlow:255] - Profile Action SelectAuthenticationFlow: No specific Principals requested
2017-01-22 14:42:56,863 - DEBUG [net.shibboleth.idp.authn.impl.SelectAuthenticationFlow:354] - Profile Action SelectAuthenticationFlow: Reusing active result authn/MFA
2017-01-22 14:42:56,863 - DEBUG [net.shibboleth.idp.authn.impl.FinalizeAuthentication:144] - Profile Action FinalizeAuthentication: Canonical principal name established from session as 'jeaton'
2017-01-22 14:42:56,864 - DEBUG [net.shibboleth.idp.authn.impl.FinalizeAuthentication:186] - Profile Action FinalizeAuthentication: Request did not have explicit authentication requirements, result is accepted

I’m sure I’m missing something in my configuration, but I’m at a loss for what.

The only flow I have enabled in idp.properties is MFA:

idp.authn.flows= MFA

and in conf/authn/mfa-authn-config.xml I have relatively simple logic for choosing the flow, based on the Wiki example    
<util:map id="shibboleth.authn.MFA.TransitionMap">
        <entry key="">
            <bean parent="shibboleth.authn.MFA.Transition" p:nextFlow="authn/Password" />
        </entry>

        <entry key="authn/Password">
            <bean parent="shibboleth.authn.MFA.Transition" p:nextFlowStrategy-ref="checkSecondFactor" />
        </entry>

    </util:map>

    <bean id="checkSecondFactor" parent="shibboleth.ContextFunctions.Scripted" factory-method=“inlineScript" p:customObject-ref="shibboleth.AttributeResolverService">
        <constructor-arg>
            <value>
            <![CDATA[
                nextFlow = "authn/Duo”;
                authCtx = input.getSubcontext("net.shibboleth.idp.authn.context.AuthenticationContext");
                mfaCtx = authCtx.getSubcontext("net.shibboleth.idp.authn.context.MultiFactorAuthenticationContext");
                resCtx = input.getSubcontext("net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext", true);
                resCtx.setPrincipal(input.getSubcontext("net.shibboleth.idp.authn.context.SubjectCanonicalizationContext").getPrincipalName());
                resCtx.getRequestedIdPAttributeNames().add("eduPersonAssurance");
                resCtx.resolveAttributes(custom);
                    
                // Check for an attribute that authorizes use of first factor.
                attribute = resCtx.getResolvedIdPAttributes().get("eduPersonAssurance");
                valueType =  Java.type("net.shibboleth.idp.attribute.StringAttributeValue");
                if (attribute != null && attribute.getValues().contains(new valueType("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"))) {
                        nextFlow = null;
                }
                    
                input.removeSubcontext(resCtx);   // cleanup                
                nextFlow;   // pass control to second factor or end with the first
            ]]>
            </value>
        </constructor-arg>
    </bean>


Why is it just accepting the previous Password authentication and not checking the attribute (and then upgrading to Duo)?

Thanks for any help,

-jeaton



More information about the users mailing list