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