Azure B2C自定义策略中获取新旧密码并传递至API的问题
背景
需要在密码重置流程的自定义策略中,获取用户当前密码和新设置的密码并传递到API端点。尝试通过AAD-Common的Read操作获取密码时失败,报错提示password输出声明不被支持;同时需要获取新密码的实现方法。
错误详情
执行New-AzureADMSTrustFrameworkPolicy时出现错误:
New-AzureADMSTrustFrameworkPolicy : Error occurred while executing NewTrustFrameworkPolicy
Code: AADB2C
Message: Validation failed: 1 validation error(s) found in policy "B2C_1A_PASSWORDRESET" of tenant "rhsb2cdev.onmicrosoft.com".Output Claim 'password' is not supported in Azure Active Directory Provider technical profile 'Get-RegisteredUserId' of policy 'B2C_1A_PasswordReset'. If it is a claim with default value, add AlwaysUseDefaultValue="true" to the output claim mapping.
InnerError:
RequestId: 3346b8e6-eaa7-4b51-9755-a08b2ce04860
DateTimeStamp: Tue, 14 Feb 2023 08:26:41 GMT
HttpStatusCode: BadRequest
当前配置
1. 获取用户信息的技术配置文件
<TechnicalProfile Id="Get-RegisteredUserId"> <Metadata> <Item Key="Operation">Read</Item> <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item> <Item Key="UserMessageIfClaimsPrincipalDoesNotExist">An account could not be found for the provided user ID.</Item> </Metadata> <IncludeInSso>false</IncludeInSso> <InputClaims> <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" Required="true" /> </InputClaims> <OutputClaims> <OutputClaim ClaimTypeReferenceId="objectId" /> <!-- 此声明正常工作 --> <OutputClaim ClaimTypeReferenceId="extension_RegisteredUserId" PartnerClaimType="extension_RegisteredUserId"/> <!-- 此声明导致错误 --> <OutputClaim ClaimTypeReferenceId="password" PartnerClaimType="password"/> </OutputClaims> <IncludeTechnicalProfile ReferenceId="AAD-Common" /> </TechnicalProfile>
2. 用户旅程配置
<UserJourney Id="PasswordReset"> <OrchestrationSteps> <OrchestrationStep Order="1" Type="ClaimsExchange"> <ClaimsExchanges> <ClaimsExchange Id="PasswordResetUsingEmailAddressExchange" TechnicalProfileReferenceId="LocalAccountDiscoveryUsingEmailAddress" /> </ClaimsExchanges> </OrchestrationStep> <OrchestrationStep Order="2" Type="ClaimsExchange"> <ClaimsExchanges> <ClaimsExchange Id="NewCredentials" TechnicalProfileReferenceId="LocalAccountWritePasswordUsingObjectId" /> </ClaimsExchanges> </OrchestrationStep> <OrchestrationStep Order="3" Type="ClaimsExchange"> <ClaimsExchanges> <ClaimsExchange Id="GetRegisteredUserId" TechnicalProfileReferenceId="Get-RegisteredUserId" /> </ClaimsExchanges> </OrchestrationStep> <OrchestrationStep Order="4" Type="ClaimsExchange"> <ClaimsExchanges> <ClaimsExchange Id="Web-API-ChangePassword" TechnicalProfileReferenceId="REST-API-ChangePassword" /> </ClaimsExchanges> </OrchestrationStep> <OrchestrationStep Order="5" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" /> </OrchestrationSteps> <ClientDefinition ReferenceId="DefaultWeb" /> </UserJourney>
3. API调用技术配置文件
<!-- Custom Restful service --> <TechnicalProfile Id="REST-API-ChangePassword"> <DisplayName>Registers a User on the Profile API</DisplayName> <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> <Metadata> <Item Key="ServiceUrl">(url for api)</Item> <Item Key="AuthenticationType">None</Item> <Item Key="SendClaimsIn">Body</Item> <Item Key="AllowInsecureAuthInProduction">true</Item> </Metadata> <InputClaims> <InputClaim ClaimTypeReferenceId="extension_RegisteredUserId" PartnerClaimType="registeredUserId"/> <InputClaim ClaimTypeReferenceId="password" PartnerClaimType="oldPassword"/> <InputClaim ClaimTypeReferenceId="newPassword" PartnerClaimType="newPassword"/> </InputClaims> <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" /> </TechnicalProfile>
解决方案
1. 关于获取当前密码(旧密码)
Azure AD B2C不会存储用户的明文密码,也不允许通过AAD-Common的Read操作读取密码相关字段,这就是报错的根本原因。无法直接获取用户的当前明文密码。
如果API需要验证旧密码,建议调整流程:
- 在密码重置流程中添加步骤,让用户输入当前密码,通过自断言技术配置文件收集该字段,再通过AAD技术配置文件验证密码正确性,最后将用户输入的旧密码作为声明传递到API。
2. 关于获取新设置的密码
新密码可以通过修改LocalAccountWritePasswordUsingObjectId技术配置文件,将新密码保留为流程中的输出声明:
- 确保声明定义中存在
newPassword(默认策略已包含):
<ClaimType Id="newPassword"> <DisplayName>New Password</DisplayName> <DataType>string</DataType> <UserHelpText>Enter new password</UserHelpText> <UserInputType>Password</UserInputType> </ClaimType>
- 修改
LocalAccountWritePasswordUsingObjectId技术配置文件,添加输出声明:
<TechnicalProfile Id="LocalAccountWritePasswordUsingObjectId"> <!-- 原有配置保留 --> <OutputClaims> <OutputClaim ClaimTypeReferenceId="newPassword" /> </OutputClaims> </TechnicalProfile>
- 编排步骤中,调用
LocalAccountWritePasswordUsingObjectId后,newPassword声明已存在于流程中,可直接在API调用的技术配置文件中引用。
关键配置调整示例
修改后的LocalAccountWritePasswordUsingObjectId
<TechnicalProfile Id="LocalAccountWritePasswordUsingObjectId"> <DisplayName>Change password (username)</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.selfasserted</Item> </Metadata> <CryptographicKeys> <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" /> </CryptographicKeys> <InputClaims> <InputClaim ClaimTypeReferenceId="objectId" /> </InputClaims> <OutputClaims> <OutputClaim ClaimTypeReferenceId="newPassword" Required="true" /> <OutputClaim ClaimTypeReferenceId="reenterPassword" Required="true" /> </OutputClaims> <ValidationTechnicalProfiles> <ValidationTechnicalProfile ReferenceId="AAD-UserWritePasswordUsingObjectId" /> </ValidationTechnicalProfiles> <UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" /> </TechnicalProfile>
内容的提问来源于stack exchange,提问作者JML

