'Unable to get ValidationTechnicalProfile to valid input
I am trying to setup the use of a one time pass code (OTP) on an Azure B2C Custom Policy. I have a working set of Orchestration steps that extract an email from a claims token supplied in the URL and then mail a randomly generated code to that email. I know there are "VerifyCode" and "GenerateCode" technical profiles available, but they rely on the user entering the email into a display field first, which I want to avoid.
I am unable get a ValidationTechnicalProfile to fire so that it can execute a ClaimsTransformation to the two claims values. These are the generated OTP mailed to the user and the input collected from a TechnicalProvider that uses a SelfAssertedAttributeProvider to display the input field with a ContentDefinition.
I am basing my code on this article and also a walkthrough with regard to ValidationTechnicalProfiles
Please could someone explain why the ValidationTechnicalProfile appears to either be skipped or is failing to work?
Claims
<ClaimType Id="Otp">
<DisplayName>One-time password</DisplayName>
<DataType>string</DataType>
</ClaimType>
<ClaimType Id="VerificationCode">
<DisplayName>Secondary Verification Code</DisplayName>
<DataType>string</DataType>
<UserHelpText>Enter your verification code</UserHelpText>
<UserInputType>TextBox</UserInputType>
</ClaimType>
Orchestration Step
<OrchestrationStep Order="4" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="SelfAsserted-OTP-Exchange" TechnicalProfileReferenceId="SelfAsserted-EnterOTP" />
</ClaimsExchanges>
</OrchestrationStep>
Technical Profile
Uses the api.page.codeinput content definition to collect the value of the VerificationCode claim in an input box. Once collected, it should fire the Self-AssertedOTPCompare TechnicalProfile as a ValidationTechnicalProfile
<TechnicalProfile Id="SelfAsserted-EnterOTP">
<DisplayName>Enter OTP</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ContentDefinitionReferenceId">api.page.codeinput</Item>
<Item Key="UserMessageIfClaimsTransformationStringsAreNotEqual">Invalid OTP Code</Item>
</Metadata>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="VerificationCode" Required="true" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="Self-AssertedOTPCompare" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
Validation Technical Profile
Executes the AssertSuppliedAndGeneratedOTPAreEqual ClaimsTransformation
<TechnicalProfile Id="Self-AssertedOTPCompare">
<DisplayName>Returns the result from comparing the generated OTP with the supplied on</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="VerificationCode" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="AssertSuppliedAndGeneratedOTPAreEqual" />
</OutputClaimsTransformations>
</TechnicalProfile>
Claims Transformation
Should compare the two claims and raise an exception to prevent the user continuing if the codes are different.
<ClaimsTransformation Id="AssertSuppliedAndGeneratedOTPAreEqual" TransformationMethod="AssertStringClaimsAreEqual">
<InputClaims>
<InputClaim ClaimTypeReferenceId="Otp" TransformationClaimType="inputClaim1" />
<InputClaim ClaimTypeReferenceId="VerificationCode" TransformationClaimType="inputClaim2" />
</InputClaims>
<InputParameters>
<InputParameter Id="stringComparison" DataType="string" Value="ordinalIgnoreCase" />
</InputParameters>
</ClaimsTransformation>
Logging with AppInsights I think it's hitting the technical profile but control appears to be returning to the orchestration. If I remove the ValidationTechnicalProfiles section from the SelfAsserted-EnterOTP technical profile, the flow stops at the page where the user would enter their code.
{
"Kind": "HandlerResult",
"Content": {
"Result": true,
"RecorderRecord": {
"Values": [
{
"Key": "InitiatingClaimsExchange",
"Value": {
"ProtocolType": "Identity Experience Engine API",
"TargetEntity": "Generate-OTP",
"TechnicalProfileId": "SelfAsserted-EnterOTP",
"ProtocolProviderType": "SelfAssertedAttributeProvider"
}
}
]
},
"PredicateResult": "True"
}
},
{
"Kind": "Action",
"Content": "Web.TPEngine.StateMachineHandlers.SwitchToApiOrchestrationHandler"
},
{
"Kind": "HandlerResult",
"Content": {
"Result": true
}
},
{
"Kind": "Transition",
"Content": {
"EventName": "SELFASSERTED",
"StateName": "AwaitingNextStep"
}
},
Additional
The original implementation above caused the process to never show the input field to collect the OTP from the user - jas-suri-msft suggests this is because a ValidationTechnicalProvider does not bubble up exceptions.
If this is the case, the documentation appears to be wrong:
The AssertStringClaimsAreEqual claims transformation is always executed from a validation technical profile that is called by a self-asserted technical profile, or a DisplayControl. The UserMessageIfClaimsTransformationStringsAreNotEqual metadata of a self-asserted technical profile controls the error message that is presented to the user.
I have tried changing the ValidationTechnicalProfiles to a OutputClaimsTransformations node as suggested.
I replaced this:
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="Self-AssertedOTPCompare" />
</ValidationTechnicalProfiles>
with this:
<OutputClaimsTransformations>
<OutputClaimsTransformation
ReferenceId="AssertSuppliedAndGeneratedOTPAreEqual" />
</OutputClaimsTransformations>
This caused the OTP collection screen to show but the page to show no error message if the code was wrong and go no further. This is despite setting UserMessageIfClaimsTransformationStringsAreNotEqual in the metadata However, entering the correct code allowed the steps to progress.
So how to do I get the page to show the exception message?
SOLUTION
As mentioned in the comments, I am unable to remove the OutputClaims from the ValidationTechnicalProfile as the policy will not validate. However, changing the OutputClaim to a DisplayClaim resolves the issue.
<TechnicalProfile Id="SelfAsserted-EnterOTP">
<DisplayName>Enter OTP</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ContentDefinitionReferenceId">api.page.codeinput</Item>
<Item Key="UserMessageIfClaimsTransformationStringsAreNotEqual">Invalid OTP Code</Item>
</Metadata>
<DisplayClaims>
<DisplayClaim ClaimTypeReferenceId="suppliedOTP" Required="true" />
</DisplayClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="Self-AssertedOTPCompare" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
