<div dir="ltr">Two comments:<div><br></div><div> In my experience, comment lines do not count when exceptions are reported in inlineScripts, so the number returned is likely earlier than the actual line that caused the exception.</div><div><br></div><div> Your only reference to length is " if (attribute != null && attribute.getValues().length()" a few lines below ... since getValues() returns a Map of values, I believe you need to use size() rather than length() in that test... </div><div><br></div><div>Steve.</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Sep 6, 2024 at 5:52 AM Francesco Malvezzi via users <<a href="mailto:users@shibboleth.net">users@shibboleth.net</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">hi everybody,<br>
<br>
I am facing a runtime exception in a MFA flow.<br>
<br>
My idea is to setup a MFA flow where, after the authn/Password, user is <br>
prompted the authn/TOTP according to the presence/absence of a user <br>
attribute (the TOTP seed in the directory, by the way).<br>
<br>
This is my $IDP_HOME/conf/authn/mfa-authn-config.xml<br>
<br>
<?xml version="1.0" encoding="UTF-8"?><br>
<beans xmlns="<a href="http://www.springframework.org/schema/beans" rel="noreferrer" target="_blank">http://www.springframework.org/schema/beans</a>"<br>
xmlns:context="<a href="http://www.springframework.org/schema/context" rel="noreferrer" target="_blank">http://www.springframework.org/schema/context</a>"<br>
xmlns:util="<a href="http://www.springframework.org/schema/util" rel="noreferrer" target="_blank">http://www.springframework.org/schema/util</a>"<br>
xmlns:p="<a href="http://www.springframework.org/schema/p" rel="noreferrer" target="_blank">http://www.springframework.org/schema/p</a>"<br>
xmlns:c="<a href="http://www.springframework.org/schema/c" rel="noreferrer" target="_blank">http://www.springframework.org/schema/c</a>"<br>
xmlns:xsi="<a href="http://www.w3.org/2001/XMLSchema-instance" rel="noreferrer" target="_blank">http://www.w3.org/2001/XMLSchema-instance</a>"<br>
xsi:schemaLocation="<a href="http://www.springframework.org/schema/beans" rel="noreferrer" target="_blank">http://www.springframework.org/schema/beans</a> <br>
<a href="http://www.springframework.org/schema/beans/spring-beans.xsd" rel="noreferrer" target="_blank">http://www.springframework.org/schema/beans/spring-beans.xsd</a><br>
<br>
<a href="http://www.springframework.org/schema/context" rel="noreferrer" target="_blank">http://www.springframework.org/schema/context</a> <br>
<a href="http://www.springframework.org/schema/context/spring-context.xsd" rel="noreferrer" target="_blank">http://www.springframework.org/schema/context/spring-context.xsd</a><br>
<a href="http://www.springframework.org/schema/util" rel="noreferrer" target="_blank">http://www.springframework.org/schema/util</a> <br>
<a href="http://www.springframework.org/schema/util/spring-util.xsd" rel="noreferrer" target="_blank">http://www.springframework.org/schema/util/spring-util.xsd</a>"<br>
<br>
default-init-method="initialize"<br>
default-destroy-method="destroy"><br>
<br>
<util:map id="shibboleth.authn.MFA.TransitionMap"><br>
<!-- Run authn/Flow1 first. --><br>
<entry key=""><br>
<bean parent="shibboleth.authn.MFA.Transition" <br>
p:nextFlow="authn/Password" /><br>
</entry><br>
<br>
<!--<br>
Second rule runs a function if authn/Flow1 succeeds, to <br>
determine whether an additional<br>
factor is required.<br>
--><br>
<entry key="authn/Password"><br>
<bean parent="shibboleth.authn.MFA.Transition" <br>
p:nextFlowStrategy-ref="checkSecondFactor" /><br>
</entry><br>
<br>
<!-- An implicit final rule will return whatever the second <br>
flow returns. --><br>
</util:map><br>
<br>
<!-- Example script to see if second factor is required. --><br>
<bean id="checkSecondFactor" <br>
parent="shibboleth.ContextFunctions.Scripted" factory-method="inlineScript"<br>
p:customObject-ref="shibboleth.AttributeResolverService"><br>
<constructor-arg><br>
<value><br>
<![CDATA[<br>
nextFlow = "authn/TOTP";<br>
<br>
// Go straight to second factor if we have to, or set up <br>
for an attribute lookup first.<br>
authCtx = <br>
input.getSubcontext("net.shibboleth.idp.authn.context.AuthenticationContext");<br>
mfaCtx = <br>
authCtx.getSubcontext("net.shibboleth.idp.authn.context.MultiFactorAuthenticationContext");<br>
if (mfaCtx.isAcceptable()) {<br>
// Attribute check is required to decide if first <br>
factor alone is enough.<br>
resCtx = input.getSubcontext(<br>
<br>
"net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext", <br>
true);<br>
<br>
// Look up the username<br>
usernameLookupStrategyClass = <br>
Java.type("net.shibboleth.idp.session.context.navigate.CanonicalUsernameLookupStrategy");<br>
usernameLookupStrategy = new usernameLookupStrategyClass();<br>
resCtx.setPrincipal(usernameLookupStrategy.apply(input));<br>
<br>
<br>
// resolve the attribute to determine if a first factor is sufficient<br>
<br>
resCtx.getRequestedIdPAttributeNames().add("unimoreTotpSeed");<br>
resCtx.resolveAttributes(custom);<br>
<br>
// Check for an attribute value that authorizes use of <br>
first factor.<br>
attribute = <br>
resCtx.getResolvedIdPAttributes().get("unimoreTotpSeed");<br>
//valueType = <br>
Java.type("net.shibboleth.idp.attribute.StringAttributeValue");<br>
if (attribute != null && attribute.getValues().length() <br>
> 0) {<br>
nextFlow = "authn/TOTP";<br>
}<br>
else<br>
{<br>
nextFlow = null;<br>
}<br>
<br>
input.removeSubcontext(resCtx); // cleanup<br>
}<br>
<br>
nextFlow; // pass control to second factor or end with <br>
the first<br>
]]><br>
</value><br>
</constructor-arg><br>
</bean><br>
</beans><br>
<br>
Note that it has been lifted from:<br>
<a href="https://shibboleth.atlassian.net/wiki/spaces/IDP5/pages/3199505534/MultiFactorAuthnConfiguration" rel="noreferrer" target="_blank">https://shibboleth.atlassian.net/wiki/spaces/IDP5/pages/3199505534/MultiFactorAuthnConfiguration</a><br>
only 4 lines have been changed (flow names and the attribute name).<br>
Please also note I didn't even change the comments from the example. <br>
They are now somewhat misleading.<br>
<br>
In the logs I read (idp-process.log):<br>
2024-09-06 11:21:21,158 - 155.185.3.38 - DEBUG <br>
[net.shibboleth.idp.authn.AbstractSubjectCanonicalizationAction:225] - <br>
Profile Action SimpleSubjectCanonicalization: trimming whitespace of <br>
input string 'this-user'<br>
2024-09-06 11:21:21,159 - 155.185.3.38 - DEBUG <br>
[net.shibboleth.idp.authn.impl.TransitionMultiFactorAuthentication:195] <br>
- Profile Action TransitionMultiFactorAuthentication: Preserving <br>
authentication result from 'authn/Password' flow<br>
2024-09-06 11:21:21,160 - 155.185.3.38 - DEBUG <br>
[net.shibboleth.idp.authn.impl.TransitionMultiFactorAuthentication:212] <br>
- Profile Action TransitionMultiFactorAuthentication: Applying MFA <br>
transition rule to exit state 'authn/Password'<br>
2024-09-06 11:21:21,309 - 155.185.3.38 - ERROR <br>
[net.shibboleth.idp.authn:35] - Uncaught runtime exception<br>
java.lang.NullPointerException: Cannot invoke <br>
"java.lang.CharSequence.length()" because "this.text" is null<br>
at <br>
java.base/java.util.regex.Matcher.getTextLength(Matcher.java:1769)<br>
2024-09-06 11:21:21,321 - 155.185.3.38 - WARN <br>
[org.opensaml.profile.action.impl.LogEvent:94] - A non-proceed event <br>
occurred while processing the request: RuntimeException<br>
<br>
the idp-warn.log confirms:<br>
<br>
2024-09-06 10:42:00,753 - 155.185.3.38 - ERROR <br>
[net.shibboleth.idp.authn:35] - Uncaught runtime exception<br>
java.lang.NullPointerException: Cannot invoke <br>
"java.lang.CharSequence.length()" because "this.text" is null<br>
at <br>
java.base/java.util.regex.Matcher.getTextLength(Matcher.java:1769)<br>
at java.base/java.util.regex.Matcher.reset(Matcher.java:415)<br>
at java.base/java.util.regex.Matcher.<init>(Matcher.java:252)<br>
at java.base/java.util.regex.Pattern.matcher(Pattern.java:1134)<br>
at com.google.common.base.JdkPattern.matcher(JdkPattern.java:36)<br>
at <br>
com.google.common.base.Predicates$ContainsPatternPredicate.apply(Predicates.java:662)<br>
at <br>
com.google.common.base.Predicates$ContainsPatternPredicate.apply(Predicates.java:651)<br>
at com.google.common.base.Predicate.test(Predicate.java:79)<br>
at <br>
net.shibboleth.shared.logic.StrategyIndirectedPredicate.test(StrategyIndirectedPredicate.java:74)<br>
at <br>
java.base/java.util.function.Predicate.lambda$negate$1(Predicate.java:80)<br>
at <br>
net.shibboleth.idp.attribute.resolver.AbstractResolverPlugin.resolve(AbstractResolverPlugin.java:174)<br>
at <br>
net.shibboleth.idp.attribute.resolver.impl.AttributeResolverImpl.resolveDataConnector(AttributeResolverImpl.java:400)<br>
at <br>
net.shibboleth.idp.attribute.resolver.impl.AttributeResolverImpl.resolveDependencies(AttributeResolverImpl.java:453)<br>
at <br>
net.shibboleth.idp.attribute.resolver.impl.AttributeResolverImpl.resolveAttributeDefinition(AttributeResolverImpl.java:328)<br>
at <br>
net.shibboleth.idp.attribute.resolver.impl.AttributeResolverImpl.resolveAttributes(AttributeResolverImpl.java:244)<br>
at <br>
net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext.resolveAttributes(AttributeResolutionContext.java:334)<br>
at <br>
org.openjdk.nashorn.internal.scripts.Script$\^eval\_.:program(<eval>:19)<br>
at <br>
org.openjdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:646)<br>
[...]<br>
<br>
line n# 19 is:<br>
resCtx.resolveAttributes(custom);<br>
<br>
I already checked the obvious:<br>
1) attribute-resolver loads without errors;<br>
2) aacli.sh works and resolves the TOTP seed attribute.<br>
<br>
$ ./bin/version.sh<br>
5.1.3<br>
$ sudo ./bin/plugin.sh -l<br>
INFO - Including auto-located properties in ./bin/../conf/ldap.properties<br>
INFO - Including auto-located properties in <br>
./bin/../conf/saml-nameid.properties<br>
INFO - Including auto-located properties in <br>
./bin/../conf/c14n/subject-c14n.properties<br>
INFO - Including auto-located properties in <br>
./bin/../conf/services.properties<br>
INFO - Including auto-located properties in <br>
./bin/../conf/authn/SpidExternal.properties<br>
INFO - Including auto-located properties in <br>
./bin/../conf/authn/X509External.properties<br>
INFO - Including auto-located properties in <br>
./bin/../conf/authn/authn.properties<br>
INFO - Including auto-located properties in <br>
./bin/../conf/admin/admin.properties<br>
Plugin: net.shibboleth.idp.plugin.nashorn Current Version: 2.0.0<br>
Plugin: net.shibboleth.idp.plugin.authn.totp Current Version: 2.1.0<br>
<br>
Of course I am not looking in the right place. What did i forget?<br>
<br>
(and sorry for the very lenghty post),<br>
<br>
Francesco<br>
-- <br>
For Consortium Member technical support, see <a href="https://shibboleth.atlassian.net/wiki/x/ZYEpPw" rel="noreferrer" target="_blank">https://shibboleth.atlassian.net/wiki/x/ZYEpPw</a><br>
To unsubscribe from this list send an email to <a href="mailto:users-unsubscribe@shibboleth.net" target="_blank">users-unsubscribe@shibboleth.net</a><br>
</blockquote></div><br clear="all"><div><br></div><span class="gmail_signature_prefix">-- </span><br><div dir="ltr" class="gmail_signature"><div dir="ltr"><div style="color:rgb(136,136,136);font-size:12.8px">Steven Premeau, <span style="font-size:12.8px">Director of Enterprise Systems Architecture & Administration</span></div><div style="color:rgb(136,136,136);font-size:12.8px"><span style="font-size:12.8px">University of Maine System:</span> Information Technology</div><div style="color:rgb(136,136,136);font-size:12.8px"><br></div></div></div>