Forcing Duo by Service Provider

Andrew Morgan morgan at orst.edu
Fri Mar 31 17:14:48 EDT 2017


On Wed, 29 Mar 2017, Michael A Grady wrote:

>
>> On Mar 29, 2017, at 7:35 PM, Cantor, Scott <cantor.2 at osu.edu> wrote:
>>
>> Yes, Marvin or I at some point fixed the CASLoginConfiguration bean to 
>> inherit appropriately so you can set the defaultAuthenticationMethods 
>> property. Since there's no native CAS object to present the 
>> authentication used, we copied the AuthnContextClassRefPrincipal type 
>> from the SAML 2 bean so you just use that. Since there's no inbound 
>> request capability, setting it is defintive / not overrideable.
>>
>> -- Scott
>
> And you can do the same "list multiple ones" and do it by user if you 
> want. I configured a set of CAS services in the CAS config, where some 
> had 'p:group="2FAselectUsers"', and some had 'p:group="2FA";, and then 
> in relying-party.xml the following. Probably don't need the 
> p:disallowedFeatures-ref="SAML2.SSO.FEATURE_AUTHNCONTEXT", given there 
> isn't a way for the request to contain a requested one, but it also 
> doesn't (seem to) hurt anything.
>
>        <!-- CAS must use Duo services -->
>        <bean id="casMfaGroup" parent="RelyingPartyByGroup" c:groupNames="2FA">
>            <property name="profileConfigurations">
>                <list>
>                    <bean parent="CAS.LoginConfiguration"
>                                                          p:disallowedFeatures-ref="SAML2.SSO.FEATURE_AUTHNCONTEXT">
>                        <property name="defaultAuthenticationMethods">
>                            <list>
>                              <ref bean="MfaPrincipal" />
>                            </list>
>                        </property>
>                    </bean>
>                    <ref bean="CAS.ValidateConfiguration" />
>                </list>
>            </property>
>        </bean>
>
>        <!-- CAS: select users  must use Duo services -->
>        <bean id="casMfaSelectUsersGroup" parent="RelyingPartyByGroup" c:groupNames="2FAselectUsers">
>            <property name="profileConfigurations">
>                <list>
>                    <bean parent="CAS.LoginConfiguration"
>                                                          p:disallowedFeatures-ref="SAML2.SSO.FEATURE_AUTHNCONTEXT">
>                        <property name="defaultAuthenticationMethods">
>                            <list>
>                              <ref bean="MfaPrincipal" />
>                              <ref bean="PasswordPrincipal" />
>                            </list>
>                        </property>
>                    </bean>
>                    <ref bean="CAS.ValidateConfiguration" />
>                </list>
>            </property>
>        </bean>
>    </util:list>
>
> and then the resolver attribute decided if the user was in the group 
> that had to do 2FA for selected SPs.
>
> That does bring up the question -- can one access that CAS group name in 
> the attribute-resolver, and if so, as what?

Forcing a CAS service to require Duo (for all users) worked great using 
both RelyingPartyByGroup and RelyingPartyByName methods in 
relying-party.xml.

Now I'm trying to require Duo for only some users for a specific SP.  In 
order to simplify the flow logic and make the logic reloadable, I decided 
to base my flow logic on a single attribute named "needs_duo".  Here is 
that scripted attribute definition:

     <AttributeDefinition id="needs_duo" xsi:type="ScriptedAttribute">
         <Dependency ref="ONIDLDAP" />
         <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";
                 }
             }
             //rpid = resolutionContext.getAttributeRecipientID();
             //if (rpid.equals("http://people.oregonstate.edu/~morgan/CAS-1.3.4/test.php")) {
             //    duoflag = "1";
             //}
             needs_duo.addValue(duoflag);
             logger.debug("needs_duo final value: " + needs_duo.getValues().get(0));
         ]]></Script>
     </AttributeDefinition>


When I uncomment the entityID check, I get the following error:

2017-03-31 13:14:16,391 - DEBUG [checkSecondFactor:4] - Starting checkSecondFactor
2017-03-31 13:14:16,560 - ERROR [net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext:242] - Error resolving attributes
net.shibboleth.idp.attribute.resolver.ResolutionException: Attribute Definition 'needs_duo': unable to execute script
         at net.shibboleth.idp.attribute.resolver.ad.impl.ScriptedAttributeDefinition.doAttributeDefinitionResolve(ScriptedAttributeDefinition.java:190)
Caused by: javax.script.ScriptException: TypeError: null has no such function "equals" in <eval> at line number 11
         at jdk.nashorn.api.scripting.NashornScriptEngine.throwAsScriptException(NashornScriptEngine.java:470)
Caused by: jdk.nashorn.internal.runtime.ECMAException: TypeError: null has no such function "equals"
         at jdk.nashorn.internal.runtime.ECMAErrors.error(ECMAErrors.java:57)

If I put that entityID check into a separate scripted attribute definition 
that is NOT called as part of the MFA flow, there is no error and the 
correct value is generated.

Does the resolutionContext exist during the MFA flow?  The behavior 
suggests it is only created/populated later.

Thanks,
 	Andy


More information about the users mailing list