我正在尝试在 Azure B2C 自定义策略上设置使用一次性密码 (OTP)。我有一组工作Orchestration
步骤,从 URL 中提供的声明令牌中提取电子邮件,然后将随机生成的代码邮寄到该电子邮件。我知道有“VerifyCode
”和“GenerateCode
”技术配置文件可用,但它们依赖于用户首先在显示字段中输入电子邮件,这是我想避免的。
我无法触发 ValidationTechnicalProfile
以便它可以对两个声明值执行 ClaimsTransformation
。这些是邮寄给用户的生成的 OTP 以及从 TechnicalProvider
收集的输入,该技术使用 SelfAssertedAttributeProvider
来显示带有 ContentDefinition
的输入字段。
我的代码基于这篇文章还有关于ValidationTechnicalProfiles
请有人解释为什么 ValidationTechnicalProfile
似乎被跳过或未能 工作?
声明
<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>
编排步骤
<OrchestrationStep Order="4" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="SelfAsserted-OTP-Exchange" TechnicalProfileReferenceId="SelfAsserted-EnterOTP" />
</ClaimsExchanges>
</OrchestrationStep>
技术简介
使用 api.page.codeinput 内容定义来收集 VerificationCode
声明的值在输入框中。收集后,它应该将 Self-AssertedOTPCompare
TechnicalProfile
作为 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
执行 AssertSuppliedAndGenerateOTPAreEqual
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
应该比较两个声明并提出一个如果代码不同,则异常以阻止用户继续。
<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>
使用 AppInsights 进行日志记录 我认为它已经达到了技术要求,但控制权似乎又回到了编排上。如果我从 SelfAsserted-EnterOTP
技术配置文件中删除 ValidationTechnicalProfiles
部分,流程将停止在用户输入代码的页面上。
{
"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"
}
},
其他
上面的原始实现导致进程永远不会显示从用户收集 OTP 的输入字段 - jas-suri-msft 表明这是因为 ValidationTechnicalProvider 不会引发异常。
如果是这种情况,文档似乎是错误的:
AssertStringClaimsAreEqual 声明转换始终是
从由调用的验证技术配置文件执行
自称的技术配置文件,或 DisplayControl。这
UserMessageIfClaimsTransformationStringsAreNotEqual 的元数据
自断言的技术配置文件控制错误消息
呈现给用户。
我尝试按照建议将 ValidationTechnicalProfiles 更改为 OutputClaimsTransformations 节点。
我将其替换
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="Self-AssertedOTPCompare" />
</ValidationTechnicalProfiles>
为:
<OutputClaimsTransformations>
<OutputClaimsTransformation
ReferenceId="AssertSuppliedAndGeneratedOTPAreEqual" />
</OutputClaimsTransformations>
这会导致显示 OTP 收集屏幕,但如果代码错误并且不再继续,则页面不会显示错误消息。尽管在元数据中设置了UserMessageIfClaimsTransformationStringsAreNotEqual
,但是输入正确的代码可以让步骤继续进行。
那么如何让页面显示异常信息呢?
解决方案
正如评论中提到的,我无法从 ValidationTechnicalProfile
中删除 OutputClaims,因为该策略不会验证。但是,将 OutputClaim
更改为 DisplayClaim
可以解决该问题。
<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>
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>
发布评论
评论(1)
当您从验证技术配置文件部分调用声明转换技术配置文件时,错误不会像直接作为
OutputClaimsTransformation
调用时那样出现。因此,我怀疑您的观察结果是,输入的任何代码都可以工作并继续进行旅程的下一步。相反,直接从
SelfAsserted-EnterOTP
调用AssertSuppliedAndGenerateOTPAreEqual
作为OutputClaimsTransformation
。When you call a claims transformation technical profile from the validation technical profile section, the error is not bubbled up like when called directly as an
OutputClaimsTransformation
. So i suspect your observation is that, any code entered works and proceeds to the next step in the journey.Instead, call
AssertSuppliedAndGeneratedOTPAreEqual
as anOutputClaimsTransformation
directly fromSelfAsserted-EnterOTP
.