No attribute context available in profile request context for authenContextTranslationStrategyEx hook
Description
Environment
Activity
Scott Cantor October 13, 2021 at 5:40 PM
Patch applied so the "right" PRC is fed into the hook, and I changed the logic to process each of the three possible sources of data so that the first one to add something wins.
I considered just applying all three but the whole idea was that the hooks should prevent exposing data from the IdP through the proxy if not desired, so it's one hook only.
Scott Cantor October 12, 2021 at 9:41 PM
Yes, that’s the workaround. You can basically check the input to the function. If getParent() is null, you’re operating with the bug. If it’s non-null, you have the fix and can pass that as is into the predicate.
Keith Wessel October 12, 2021 at 9:40 PM
Found it thanks to my clever director who helped me list out all of the subcontexts. We found another prc unde the authentication context class, and there were the resolved attributes. We’ll code defensively so it’ll work both ways until the fix from you is here. Thanks.
Keith Wessel October 12, 2021 at 8:42 PM
Thanks, Scott. If you can tell me where I can find the correct PRC in teh tree, I’ll experiment with a workaround, at least temporarily.
Scott Cantor October 12, 2021 at 8:24 PM
It is in fact a bug in the code that’s locating the PRC to pass into your function. This is all confusing on a whole other level because of how the proxy logic was implemented without completely rewriting all our code, and we actually nest a whole new PRC tree underneath a node in the original tree. It’s like a sub-transaction operating within the original transaction because it’s a second message exchange inside the first one. It all works, but is very complex to keep straight in the code.
I messed up by tracking back to the wrong ProfileRequestContext instead of the nested one that actually sits on top of where the AttributeContext lives.
It’s possible to work around, but once I fix the code, it will break your workaround, though I guess it could done with a script that acts defensively and could detect the change and handle both cases. Probably easier just to make a note and drop the workaround once the patch is out.
I’m ok fixing this as is since this is a very little used feature but it’s unfortunate, and I’m going to simply blame Azure and their garbage pile of bugs for all of this.
I will have to test a workaround for it first and then once I have that I can patch the code and test it without.
IdP log reports:
2021-10-11 11:04:30,614 - DEBUG [net.shibboleth.idp.attribute.filter.AttributeFilte
rPolicy:153] - Attribute Filter Policy 'UnsuppressedUserAffilsToAnyone' Applying attribute filter policy to current set
of attributes: [uid, adfsProxyAuthnMethod]
...
2021-10-11 11:04:30,620 - DEBUG [net.shibboleth.idp.attribute.filter.AttributeRule:
192] - Attribute filtering engine '/AttributeFilterPolicyGroup:ShibbolethFilterPolicy/AttributeRule:_60a9db1947f3ae2b2ed
5ebc44dee14c3' Filter has permitted the release of 3 values for attribute 'adfsProxyAuthnMethod'
But when a simple attribute predicate tries to run as part of the function used for the authnContextTranslationStrategyEx hook:
2021-10-11 11:04:30,855 - WARN [net.shibboleth.idp.profile.logic.AbstractAttributeP
redicate:105] - No AttributeContext located for evaluation
And debug code in the function reports:
2021-10-11 11:04:30,828 - DEBUG [mfa_claim_to_acr:12] - Attribute context not found
The hook is configured like this in relying party config:
<bean parent="RelyingPartyByName" c:relyingPartyIds="%{idp.saml-proxy.entityID}"
p:responderIdLookupStrategy-ref="proxySPEntityIDStrategy">
<property name="profileConfigurations">
<list>
<bean parent="SAML2.SSO"
p:authnContextTranslationStrategyEx-ref="mfaClaimToACR" />
</list>
</property>
</bean>
The function and helpers map in global.xml are:
<bean id="mfaClaimToACR" parent="shibboleth.ContextFunctions.Scripted" factory-method="inlineScript"
p:customObject-ref="mfaClaimToACRHelpersMap">
<constructor-arg>
<value>
<![CDATA[
var logger = Java.type("org.slf4j.LoggerFactory").getLogger("mfa_claim_to_acr");
var acr = null;
if (input.getSubcontext("net.shibboleth.idp.profile.context.RelyingPartyContext") == null) {
logger.debug("Relying party context not found");
}
else {
logger.debug("Relying party context found");
}
if (input.getSubcontext("net.shibboleth.idp.attribute.context.AttributeContext") == null) {
logger.debug("Attribute context not found");
}
else {
logger.debug("Attribute context found");
}
if (custom["mfaAuthnClaimCondition"].test(input)) {
logger.debug("Found matching attribute value, authentication was MFA");
acr = custom["refedsMFAAuthnContext"];
}
else {
logger.debug("No adfsProxyAuthnMethod attribute in response from IdP");
}
acr;
]]>
</value>
</constructor-arg>
</bean>
<util:map id="mfaClaimToACRHelpersMap">
<entry key="mfaAuthnClaimCondition">
<bean class="net.shibboleth.idp.profile.logic.SimpleAttributePredicate"
p:attributeContextLookupStrategy-ref="shibboleth.ChildLookup.PreRequestedAttributeContext"
p:useUnfilteredAttributes="true">
<property name="attributeValueMap">
<map>
<entry key="adfsProxyAuthnMethod">
<list>
<value>http://schemas.microsoft.com/claims/multipleauthn</value>
</list>
</entry>
</map>
</property>
</bean>
</entry>
<entry key="refedsMFAAuthnContext">
<list>
<bean parent="shibboleth.SAML2AuthnContextClassRef"
c:classRef="https://refeds.org/profile/mfa" />
</list>
</entry>
</util:map>
I'm aware that it might not be appropriate to return null for the authnContextClassRef if the simple attribute predicate returns false, but I was gong to tackle returning an appropriate value once I got the positive case to work.