<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<style type="text/css" style="display:none;"> P {margin-top:0;margin-bottom:0;} </style>
</head>
<body dir="ltr">
<div style="font-family: Arial, Helvetica, sans-serif; font-size: 9pt; color: rgb(0, 0, 0);">
Jeff,</div>
<div style="font-family: Arial, Helvetica, sans-serif; font-size: 9pt; color: rgb(0, 0, 0);">
<br>
</div>
<div style="font-family: Arial, Helvetica, sans-serif; font-size: 9pt; color: rgb(0, 0, 0);">
I can't remember the exact error when i used the example you are using here. However, I had to add some logging to trace where the logic was breaking and ended up <span style="color: rgb(0, 0, 0); font-family: Arial, Helvetica, sans-serif; font-size: 9pt;">adding
 an attribute with a flag value, in the resolver file after checking for AD group membership there.</span></div>
<div style="font-family: Arial, Helvetica, sans-serif; font-size: 9pt; color: rgb(0, 0, 0);">
<span style="color: rgb(0, 0, 0); font-family: Arial, Helvetica, sans-serif; font-size: 9pt;"><br>
</span></div>
<div style="font-family: Arial, Helvetica, sans-serif; font-size: 9pt; color: rgb(0, 0, 0);">
<span style="color: rgb(0, 0, 0); font-family: Arial, Helvetica, sans-serif; font-size: 9pt;">I don't have an explanation of why that worked instead of checking for the AD group in that if statement like in the example. </span></div>
<div style="font-family: Arial, Helvetica, sans-serif; font-size: 9pt; color: rgb(0, 0, 0);">
<pre lang="xml"><span lang="xml"><span> //SK: Determine if the nextFlow should be DUO based on criteria or pass through</span></span>
<span lang="xml"><span> nextFlow = null; </span></span>
<span lang="xml"></span>
<span lang="xml"><span> //SK: Adding logger </span></span>
<span lang="xml"><span> logger = Java.type("org.slf4j.LoggerFactory").getLogger("net.shibboleth.idp.attribute.resolver");</span></span>
</pre>
<br>
</div>
<div style="font-family: Arial, Helvetica, sans-serif; font-size: 9pt; color: rgb(0, 0, 0);">
....few lines below ...</div>
<div style="font-family: Arial, Helvetica, sans-serif; font-size: 9pt; color: rgb(0, 0, 0);">
<pre lang="xml"><span lang="xml"><span>//SK: Check if user is part of the AD group Shib-Employee-MFA, if not skip the DUO Flow. </span></span>
<span lang="xml"><span>                    if (attribute != null && attribute.getValues().contains(new valueType("1") ) ) {</span></span>
<span lang="xml"><span>                        logger.info(" User in Shib-Employee-MFA (needs_duo). Prompting for DUO ");</span></span>
<span lang="xml"><span>                        nextFlow = "authn/Duo";</span></span>
<span lang="xml"><span>                    }else{</span></span>
<span lang="xml"><span>                        logger.info(" User NOT IN Shib-Employee-MFA. Skipping for DUO ");</span></span>
<span lang="xml"><span>                    }</span></span>
</pre>
</div>
<div style="font-family: Arial, Helvetica, sans-serif; font-size: 9pt; color: rgb(0, 0, 0);">
<br>
</div>
<div style="font-family: Arial, Helvetica, sans-serif; font-size: 9pt; color: rgb(0, 0, 0);">
attribute-resolver.xml</div>
<div style="font-family: Arial, Helvetica, sans-serif; font-size: 9pt; color: rgb(0, 0, 0);">
<pre lang="xml"><span lang="xml"><span><!-- Duo flag attribute based on memberOf from AD --></span> </span>
<span lang="xml">        <span><resolver:AttributeDefinition</span> <span>id=</span><span>"needs_duo"</span> <span>xsi:type=</span><span>"Script"</span> <span>xmlns=</span><span>"urn:mace:shibboleth:2.0:resolver:ad"</span><span>></span> </span>
<span lang="xml">         <span><resolver:Dependency</span> <span>ref=</span><span>"myLDAP"</span> <span>/></span> </span>
<span lang="xml">         <span><Script></span><span><![CDATA[ </span></span>
<span lang="xml"><span>             logger = Java.type("org.slf4j.LoggerFactory").getLogger("net.shibboleth.idp.attribute.resolver.needs_duo"); </span></span>
<span lang="xml"><span>             duoflag = "0"; </span></span>
<span lang="xml"></span>
<span lang="xml"><span>             if (typeof memberOf == "undefined" || memberOf == null ){</span></span>
<span lang="xml"><span>                logger.debug("memberOf attribute is not defined or null. Setting duoFlag to 0."); </span></span>
<span lang="xml"><span>                duoflag = "0";</span></span>
<span lang="xml"><span>             }else{</span></span>
<span lang="xml"></span>
<span lang="xml"><span>                 for (i=0; i < memberOf.getValues().size(); i++) { </span></span>
<span lang="xml"><span>                     tmp = memberOf.getValues().get(i); </span></span>
<span lang="xml"><span>                     if (tmp.toLowerCase().equals("cn=shib-employee-mfa<some other values here..>")) { </span></span>
<span lang="xml"><span>                         logger.debug("User is opted-in to Duo"); </span></span>
<span lang="xml"><span>                         duoflag = "1"; </span></span>
<span lang="xml"><span>                    } </span></span>
<span lang="xml"><span>                }</span></span>
<span lang="xml"><span>            }//end else memberOf == null</span></span>
<span lang="xml"></span>
<span lang="xml"><span>            //check if the requesting SP/relying party should be prompted for DUO.</span></span>
<span lang="xml"><span>            rpid = profileContext.getSubcontext("net.shibboleth.idp.profile.context.RelyingPartyContext").getRelyingPartyId(); </span></span>
<span lang="xml"><span>            logger.debug("rpid=" + rpid); </span></span>
<span lang="xml"><span>            if (rpid.equals("<entity_ID>")){ </span></span>
<span lang="xml"><span>                    duoflag = "1"; </span></span>
<span lang="xml"><span>            } </span></span>
<span lang="xml"><span>        </span></span>
<span lang="xml">           <b> needs_duo.addValue(duoflag); </b></span>
<span lang="xml"><span>             </span></span>
<span lang="xml"><span>            logger.debug("needs_duo final value: " + needs_duo.getValues().get(0)); </span></span>
<span lang="xml"><span>         ]]></span><span></Script></span> </span>
</pre>
<br>
</div>
<div style="font-family: Arial, Helvetica, sans-serif; font-size: 9pt; color: rgb(0, 0, 0);">
<br>
</div>
<div id="Signature">
<div></div>
<div style="font-family:Tahoma; font-size:13px">
<div class="BodyFragment"><font size="2">
<div class="PlainText">Thanks, </div>
<div class="PlainText"><br>
</div>
<div class="PlainText">Shweta Kautia</div>
<div class="PlainText"></div>
</font></div>
</div>
</div>
<div id="appendonsend"></div>
<div style="font-family:Arial,Helvetica,sans-serif; font-size:9pt; color:rgb(0,0,0)">
<br>
</div>
<hr tabindex="-1" style="display:inline-block; width:98%">
<div id="divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" color="#000000" style="font-size:11pt"><b>From:</b> users <users-bounces@shibboleth.net> on behalf of Jeffrey Williams <jfwillia@uncg.edu><br>
<b>Sent:</b> Tuesday, September 17, 2019 3:20 PM<br>
<b>To:</b> users@shibboleth.net <users@shibboleth.net><br>
<b>Subject:</b> [External] Re: SP requesting MFA login</font>
<div> </div>
</div>
<div><b>[<font color="red">CAUTION</font>: External email. Do not click links or open attachments unless verified. Send all suspicious email as an attachment to
<a href="mailto:spam@northcarolina.edu">spam@northcarolina.edu</a>]</b><br>
<br>
<div>
<div dir="ltr">David is correct.  Apologies for the lack of detail.  Any user, regardless of their MFA enrollment status, will encounter that error when they try to log into an SP that is requesting the MFA profile.  Here is how our flow looks today(largely
 adapted from our 2.x environment that used this as a reference: <a href="https://wiki.shibboleth.net/confluence/pages/viewpage.action?pageId=32112643" target="_blank">https://wiki.shibboleth.net/confluence/pages/viewpage.action?pageId=32112643</a>  )
<div><br>
<blockquote class="x_gmail_quote" style="margin:0px 0px 0px 0.8ex; border-left:1px solid rgb(204,204,204); padding-left:1ex">
  <font face="monospace">  <util:map id="shibboleth.authn.MFA.TransitionMap"><br>
        <!-- First rule runs the authn/Password login flow. --><br>
        <entry key=""><br>
            <bean parent="shibboleth.authn.MFA.Transition" p:nextFlow="authn/Password" /><br>
        </entry><br>
        <br>
        <!--<br>
        Second rule runs a function if authn/Password succeeds, to determine whether an additional<br>
        factor is required.<br>
        --><br>
        <entry key="authn/Password"><br>
<bean parent="shibboleth.authn.MFA.Transition" p:nextFlowStrategy-ref="checkSecondFactor" /><br>
        </entry><br>
        <br>
        <!-- An implicit final rule will return whatever the final flow returns. --><br>
    </util:map><br>
<br>
    <bean id="checkSecondFactor" parent="shibboleth.ContextFunctions.Scripted" factory-method="inlineScript"<br>
        p:customObject-ref="shibboleth.AttributeResolverService"><br>
        <constructor-arg><br>
            <value><br>
            <![CDATA[<br>
                nextFlow = null;<br>
<br>
                // Go straight to second factor if we have to, or set up for an attribute lookup first.<br>
                authCtx = input.getSubcontext("net.shibboleth.idp.authn.context.AuthenticationContext");<br>
                mfaCtx = authCtx.getSubcontext("net.shibboleth.idp.authn.context.MultiFactorAuthenticationContext");<br>
                if (mfaCtx.isAcceptable()) {<br>
                    // Attribute check is required to decide if first factor alone is enough.<br>
                    resCtx = input.getSubcontext(<br>
                        "net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext", true);<br>
                    resCtx.setPrincipal(input.getSubcontext(<br>
                        "net.shibboleth.idp.authn.context.SubjectCanonicalizationContext").getPrincipalName());<br>
                    resCtx.getRequestedIdPAttributeNames().add("ADmemberOf");<br>
                    resCtx.resolveAttributes(custom);<br>
                    <br>
                    // Check for an attribute that authorizes use of first factor.<br>
                    attribute = resCtx.getResolvedIdPAttributes().get("ADmemberOf");<br>
                    valueType =  Java.type("net.shibboleth.idp.attribute.StringAttributeValue");<br>
                    if (attribute != null && attribute.getValues().contains(new valueType("CN=duoActiveUsers,OU=are,OU=here,O=uncg"))) {<br>
                        nextFlow = "authn/Duo";<br>
                    }<br>
                    <br>
                    input.removeSubcontext(resCtx);   // cleanup<br>
                }<br>
                <br>
                nextFlow;   // pass control to second factor or end with the first<br>
            ]]><br>
   </value><br>
        </constructor-arg><br>
    </bean></font><br>
</blockquote>
<div><br>
</div>
<div>Based on it's behavior, it looks like it's making a non-proceed decision after the first factor without proceeding to the checkSecondFactor(where the MFA magic happens). I can provide more configs if it helps.</div>
</div>
<div><br>
</div>
<div><br>
</div>
</div>
<br>
<div class="x_gmail_quote">
<div dir="ltr" class="x_gmail_attr">On Tue, Sep 17, 2019 at 12:58 PM Jeffrey Williams <<a href="mailto:jfwillia@uncg.edu" target="_blank">jfwillia@uncg.edu</a>> wrote:<br>
</div>
<blockquote class="x_gmail_quote" style="margin:0px 0px 0px 0.8ex; border-left:1px solid rgb(204,204,204); padding-left:1ex">
<div dir="ltr">
<div>I'm looking for guidance on the best approach to a request.</div>
<div><br>
</div>
We're currently running 3.3.3 using the native Duo plugin and the IDP has only one flow. It's scripted to check to see if the user is enrolled in MFA before presenting authn/Duo.  
<div><br>
</div>
<div>We have a vendor using Shibboleth SP that we're looking to integrate with and one of the requirements is that authorized users must MFA into the service.  My first thought was to have the SP configured their 
<code style="color:rgb(23,43,77); font-size:14px">authnContextClassRef</code><span style="color:rgb(23,43,77); font-size:14px"> </span>  to our MFA value ("<font face="monospace"><a href="https://refeds.org/profile/mfa" target="_blank">https://refeds.org/profile/mfa</a></font>"). 
 However, it seems that the IdP's authentication flow short-circuits after 1FA and sends an error back to the SP saying:<br>
<blockquote class="x_gmail_quote" style="margin:0px 0px 0px 0.8ex; border-left:1px solid rgb(204,204,204); padding-left:1ex">
<br>
SAML response reported an IdP error.<br>
Error from identity provider:<br>
<strong>Sub-Status:</strong> urn:oasis:names:tc:SAML:2.0:status:NoAuthnContext<br>
<strong>Message:</strong> An error occurred.<br>
</blockquote>
<blockquote><strong>Status:</strong> urn:oasis:names:tc:SAML:2.0:status:Requester<br>
</blockquote>
<div>
<div>With the following in the IdP logs:</div>
<div><br>
</div>
<div><font face="monospace">2019-09-16 19:21:30,180 - INFO [net.shibboleth.idp.authn.impl.ValidateUsernamePasswordAgainstLDAP:152] - Profile Action ValidateUsernamePasswordAgainstLDAP: Login by 'jfwillia' succeeded<br>
2019-09-16 19:21:30,191 - DEBUG [net.shibboleth.idp.session.impl.DetectIdentitySwitch:148] - Profile Action DetectIdentitySwitch: No previous session found, nothing to do<br>
2019-09-16 19:21:30,191 - WARN [net.shibboleth.idp.authn.impl.FinalizeAuthentication:179] - Profile Action FinalizeAuthentication: Authentication result for flow authn/MFA did not satisfy the request<br>
2019-09-16 19:21:30,195 - WARN [org.opensaml.profile.action.impl.LogEvent:105] - A non-proceed event occurred while processing the request: RequestUnsupported</font><br>
</div>
<div><font face="monospace"><br>
</font></div>
<div><font face="arial, sans-serif">This is regardless of MFA enrollment.  </font></div>
<div><font face="arial, sans-serif"><br>
</font></div>
<div><font face="arial, sans-serif">I checked through the docs and didn't find anything that seemed to answer the question.  Is there a way to maintain the single authentication flow and have it only authenticate MFA users for this SP?</font></div>
<div><font face="monospace"><br>
</font></div>
-- <br>
<div dir="ltr" class="x_gmail-m_-3909351219914740749gmail-m_-5631630486695327573m_-451548204329762626m_5808403822012160684gmail_signature">
<div dir="ltr">
<div>
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div>
<div dir="ltr">Jeffrey Williams </div>
<div dir="ltr">Identity Engineer<br>
Identity & Access Services<br>
<a href="https://its.uncg.edu" target="_blank">https://its.uncg.edu</a></div>
</div>
<div dir="ltr"><br>
</div>
<div dir="ltr"><img src="https://uncgcdn.blob.core.windows.net/email/UNCGLogo.png"><br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</div>
<br clear="all">
<div><br>
</div>
-- <br>
<div dir="ltr" class="x_gmail-m_-3909351219914740749gmail_signature">
<div dir="ltr">
<div>
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div>
<div dir="ltr">Jeffrey Williams </div>
<div dir="ltr">Identity Engineer<br>
Identity & Access Services<br>
<a href="https://its.uncg.edu" target="_blank">https://its.uncg.edu</a></div>
</div>
<div dir="ltr"><br>
</div>
<div dir="ltr"><img src="https://uncgcdn.blob.core.windows.net/email/UNCGLogo.png"><br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>