Use group for MFA

Andrew Morgan morgan at orst.edu
Wed Apr 5 16:41:34 EDT 2017


On Wed, 5 Apr 2017, Richard Frovarp wrote:

> I'm trying to figure out how to trigger MFA in Shib 3.3 using the built in 
> Duo integration based off of group membership in AD.
>
> I have figured out how to get the MFA workflow to work, and how to write the 
> most simplistic code to either just go with password or to push on with Duo. 
> What I haven't figured out how to do is get user attributes. I'm resolving 
> attributes out of AD, and I'm hoping that takes place after password, and is 
> somehow available at the MFA checkSecondFactor spot. Is it in the 
> SubjectContext, and is that available via the getSubcontext() calls? Is there 
> something else I need to be looking at? From the javadocs, it isn't entirely 
> clear as to what I should be looking at.

It's not too bad.  Here is my MFA flow script:

<![CDATA[
   nextFlow = null;

   logger = Java.type("org.slf4j.LoggerFactory").getLogger("checkSecondFactor");
   logger.debug('Starting checkSecondFactor');

   // 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())) {
       logger.debug('First factor is not enough - proceeding to Duo');
       nextFlow = "authn/Duo";
   }
   else {
       // other checks to see if Duo is required
       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("needs_duo");
       resCtx.resolveAttributes(custom);
       attribute = resCtx.getResolvedIdPAttributes().get("needs_duo");
       valueType =  Java.type("net.shibboleth.idp.attribute.StringAttributeValue");
       if (attribute != null && attribute.getValues().contains(new valueType("1"))) {
           nextFlow = "authn/Duo";
       }
       input.removeSubcontext(resCtx);   // cleanup
   }

   nextFlow;   // pass control to second factor or end with the first
]]>


This is almost the same as the example that Shibboleth distributes.

Here is how the "needs_duo" attribute is generated:

<AttributeDefinition id="needs_duo" xsi:type="ScriptedAttribute">
     <Dependency ref="myLDAP" />
     <Script><![CDATA[
         logger = Java.type("org.slf4j.LoggerFactory").getLogger("net.shibboleth.idp.attribute.resolver.needs_duo");
         duoflag = "0";
         for (i=0; i < ismemberof.getValues().size() - 1; i++) {
             tmp = ismemberof.getValues().get(i);
             if (tmp.toLowerCase().equals("cn=duo-opt-in,ou=duo,ou=app,ou=is,ou=org,ou=osu,ou=grouper,ou=groups,o=orst.edu")) {
                 logger.debug("User is opted-in to Duo");
                 duoflag = "1";
             }
         }
         needs_duo.addValue(duoflag);
         logger.debug("needs_duo final value: " + needs_duo.getValues().get(0));
     ]]></Script>
</AttributeDefinition>


You can do fancier things in the attribute definition as well, such as 
comparing against the relying party's entityID.  Here is a code snippet 
for that:

     rpid = profileContext.getSubcontext("net.shibboleth.idp.profile.context.RelyingPartyContext").getRelyingPartyId();
     logger.debug("rpid=" + rpid);
     if (rpid.equals("http://people.oregonstate.edu/~morgan/simplesaml/module.php/saml/sp/metadata.php/default-sp")) {
         duoflag = "1";
     }


This example might be useful if you want to enable Duo for specific users 
for a specific relying party.  Watch out for gaps with step-up MFA though!

However, if you want to force Duo for a particular relying party, it's 
better to do it in relying-party.xml.

I hope this helps.

 	Andy


More information about the users mailing list