Are there any facilities in AAD B2C to allow me to prevent users from using pwds which have their name in it or that have been used before by the same user? Could I do the former through an IEF policy and a REST function? (I suspect not assuming that at no stage will my code have access to the pwd value but perhaps I am wrong and a pwd claim is just another claim)
It's possible for a custom policy to validate a new password if you're wanting to implement a REST API for this.
For example, for a password reset, you can add one validation technical profile that calls the REST API to check if the new password is valid for the current user against the password history and another validation technical profile that calls the REST API to then save the new password for the current user in the password history:
<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" />
...
<InputClaims>
<InputClaim ClaimTypeReferenceId="objectId" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="newPassword" Required="true" />
<OutputClaim ClaimTypeReferenceId="reenterPassword" Required="true" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="API-CheckNewPassword" />
<ValidationTechnicalProfile ReferenceId="AAD-UserWritePasswordUsingObjectId" />
<ValidationTechnicalProfile ReferenceId="API-SaveNewPassword" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
It's best that you hash the new password before it's passed to the REST API (although this will limit whether the REST API can determine if the new password contains the user name) for security.
You can hash the new password using the Hash claims transformation:
<ClaimsTransformation Id="HashNewPassword" TransformationMethod="Hash">
<InputClaims>
<InputClaim ClaimTypeReferenceId="newPassword" TransformationClaimType="plaintext" />
<InputClaim ClaimTypeReferenceId="objectId" TransformationClaimType="salt" />
</InputClaims>
<InputParameters>
<InputParameter Id="randomizerSecret" DataType="string" Value="B2C_1A_MyRandomizerSecret" />
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="newPasswordHash" TransformationClaimType="hash" />
</OutputClaims>
</ClaimsTransformation>
<ClaimsProvider>
<DisplayName>APIs</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="API-CheckNewPassword">
<DisplayName>Check New Password API</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
...
<InputClaimTransformations>
<InputClaimTransformation ReferenceId="HashNewPassword" />
</InputClaimTransformations>
<InputClaims>
<InputClaim ClaimTypeReferenceId="objectId" />
<InputClaim ClaimTypeReferenceId="newPasswordHash" />
</InputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
Related
I have created a 2 step sign-up custom policy. Where the first step verifies the email, and the second step generates a new password, and it was working well.
Then I followed all the steps here:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/custom-email-sendgrid?pivots=b2c-custom-policy
to create a custom email verifier, so I could send the verification code with custom content.
This, also seems to work fine.
However, adding it changed my flow somehow so that the email claim doesn't seem to be outputted by my first step and my claim transformation in my second step which uses the 'email' claim is failing.
In other words this works fine without the display claims portion below, and starts failing after I add it. What am I missing?
<ClaimsTransformation Id="CreateReadonlyEmailClaim" TransformationMethod="FormatStringClaim">
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" TransformationClaimType="inputClaim" />
</InputClaims>
<InputParameters>
<InputParameter Id="stringFormat" DataType="string" Value="{0}" />
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="readonlyEmail" TransformationClaimType="outputClaim" />
</OutputClaims>
</ClaimsTransformation>
<!-- 2 step partner sign-up -->
<TechnicalProfile Id="PartnerSignUpVerifyEmailPage">
<DisplayName>Local Email Verification</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="IpAddressClaimReferenceId">IpAddress</Item>
<Item Key="ContentDefinitionReferenceId">api.signUpVerifyEmailPage</Item>
<Item Key="UserMessageIfClaimsTransformationStringsAreNotEqual">A user with this email address already exists.</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" />
</InputClaims>
<!-- this breaks the next step when I add the display claims -->
<DisplayClaims>
<DisplayClaim DisplayControlReferenceId="emailVerificationControl" />
</DisplayClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />
</OutputClaims>
<ValidationTechnicalProfiles>
<!-- this validation asserts the email provided isn't already in use -->
<ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingEmailAddress-RaiseIfExists" />
</ValidationTechnicalProfiles>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
<TechnicalProfile Id="PartnerSignUpSetNewPasswordPage">
<DisplayName>Local Email SignUp</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="IpAddressClaimReferenceId">IpAddress</Item>
<Item Key="ContentDefinitionReferenceId">api.signUpSetNewPasswordPage</Item>
<Item Key="EnforceEmailVerification">False</Item>
</Metadata>
<InputClaimsTransformations>
<InputClaimsTransformation ReferenceId="CreateReadonlyEmailClaim" />
</InputClaimsTransformations>
<InputClaims>
<InputClaim ClaimTypeReferenceId="readOnlyEmail" />
</InputClaims>
<OutputClaims>
<!--OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="readOnlyEmail" /-->
<OutputClaim ClaimTypeReferenceId="newPassword" Required="true" />
<OutputClaim ClaimTypeReferenceId="reenterPassword" Required="true" />
<OutputClaim ClaimTypeReferenceId="executed-SelfAsserted-Input" DefaultValue="true" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
<OutputClaim ClaimTypeReferenceId="newUser" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonEmail" />
</ValidationTechnicalProfiles>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
Removing PartnerClaimType="Verified.Email" from the output claim made it work.
Credit to Jas on this older post: https://github.com/azure-ad-b2c/samples/issues/193
I have a scenario where i have to pass a query parameter in the URL to my custom sign-up policy and so far all my attempts did not work. there seem to be something that i am missing following the guidelines i found in github. I am trying to pass LoyaltyNumber and i have this attribute defined in my policy as extension_LoyaltyNumber. Below is the snippet
my custom signup policy
<RelyingParty>
<DefaultUserJourney ReferenceId="SignUp" />
<UserJourneyBehaviors>
<ContentDefinitionParameters>
<Parameter Name="LoyaltyNumber">{OAUTH-KV:LoyaltyNumber}</Parameter>
</ContentDefinitionParameters>
</UserJourneyBehaviors>
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect" />
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" />
<InputClaim ClaimTypeReferenceId="extension_LoyaltyNumber" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email" />
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
<OutputClaim ClaimTypeReferenceId="tenantId" AlwaysUseDefaultValue="true" DefaultValue="{Policy:TenantObjectId}" />
<OutputClaim ClaimTypeReferenceId="extension_ValidPassword" />
<OutputClaim ClaimTypeReferenceId="extension_LoyaltyNumber" AlwaysUseDefaultValue="true"/>
</OutputClaims>
<SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>
in my TrustFrameworkExtension.xml, i have defined it in the Local Account as follows
<ClaimsProvider>
<DisplayName>Local Account</DisplayName>
<TechnicalProfiles>
<!--Local account sign-up page-->
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
<Metadata>
<Item Key="IncludeClaimResolvingInClaimsHandling">true</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="extension_LoyaltyNumber" AlwaysUseDefaultValue="true" DefaultValue="{OAUTH-K:LoyaltyNumber}" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />
<OutputClaim ClaimTypeReferenceId="newPassword" Required="true" />
<OutputClaim ClaimTypeReferenceId="reenterPassword" Required="true" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surName" />
</OutputClaims>
</TechnicalProfile>
<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Email">
<Metadata>
<Item Key="setting.showSignupLink">false</Item>
</Metadata>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
i also have it in the building bolocks section as...
<BuildingBlocks>
<ClaimsSchema>
<ClaimType Id="extension_LoyaltyNumber">
<DisplayName>Loyality-Number</DisplayName>
<DataType>string</DataType>
<UserHelpText>Your loyality from your membership card</UserHelpText>
</ClaimType>
</ClaimsSchema>
</BuildingBlocks>
i have it also to write to Azure Active Directory claims provider section as follows
<ClaimsProvider>
<DisplayName>Azure Active Directory</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="AAD-Common">
<Metadata>
<!--Insert b2c-extensions-app application ID here, for example: 11111111-1111-1111-1111-111111111111-->
<Item Key="ClientId">11111111-1111-1111-1111-111111111111</Item>
<!--Insert b2c-extensions-app application ObjectId here, for example: 22222222-2222-2222-2222-222222222222-->
<Item Key="ApplicationObjectId">22222222-2222-2222-2222-222222222222</Item>
</Metadata>
</TechnicalProfile>
<TechnicalProfile Id="AAD-UserWriteUsingLogonEmail">
<PersistedClaims>
<PersistedClaim ClaimTypeReferenceId="extension_LoyaltyNumber" />
</PersistedClaims>
</TechnicalProfile>
<TechnicalProfile Id="AAD-UserReadUsingObjectId">
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="extension_LoyaltyNumber" />
</OutputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
And the redirect happens from my web application using the following method
public void SignUpNewUser()
{
if (!Request.IsAuthenticated)
{
var authenticationProperties = new AuthenticationProperties();
authenticationProperties.Dictionary.Add("LoyaltyNumber", "556677");
authenticationProperties.RedirectUri = "/";
HttpContext.GetOwinContext().Authentication.Challenge(authenticationProperties, Startup.SignUpPolicyId);
}
}
The result i am getting after the user sign-up for the custom attribute extension_LoyaltyNumber is {OAUTH-K:LoyaltyNumber}
Somehow the value 556677 i pass as a query param is not getting to this custom attribute and get stored in Azure user attribute
Can you help?
Thanks
Add
<OutputClaim ClaimTypeReferenceId="extension_LoyaltyNumber" />
to LocalAccountSignUpWithLogonEmail. Output claims allow the claim to be used in subsequent orchestration steps.
In the <RelyingParty> section, change your output claim to the following, its already resolved so no need to resolve it again here:
<OutputClaim ClaimTypeReferenceId="extension_LoyaltyNumber" />
What I do when I want to have query string parameters handled is this:
Create a TechnicalProfile:
<TechnicalProfile Id="GetMyParameter">
<DisplayName>GetMyParameter</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
<Metadata>
<Item Key="IncludeClaimResolvingInClaimsHandling">true</Item>
</Metadata>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="myParameter" AlwaysUseDefaultValue="true" DefaultValue="{OAUTH-KV:myparameter}" />
</OutputClaims>
</TechnicalProfile>
Then run that profile in an OrchestrationStep before the claim value is required (it can be the first one or somewhere later along the way, doesn't matter much as far as I can tell).
You can have as many parameters in the technical profile as you wish. Works every time, doesn't crash if you don't provide value.
I Faced with the same problem, and found answer in official documentation
Don't forget to create claimType in your claims schema
<ClaimType Id="q_param">
<DisplayName>q_param</DisplayName>
<DataType>string</DataType>
<UserHelpText>Special parameter passed for authentication context</UserHelpText>
</ClaimType>
Additionally you need to set output claim in technical profile like in example
from TrustFrameworkExtensions.xml
<ClaimsProvider>
<DisplayName>Local Account SignIn</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="login-NonInteractive">
<Metadata>
<Item Key="client_id">ProxyIdentityExperienceFrameworkAppId</Item>
<Item Key="IdTokenAudience">IdentityExperienceFrameworkAppId</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="client_id" DefaultValue="ProxyIdentityExperienceFrameworkAppId" />
<InputClaim ClaimTypeReferenceId="resource_id" PartnerClaimType="resource" DefaultValue="IdentityExperienceFrameworkAppId" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="q_param" DefaultValue="{OAUTH-KV:q_param}" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
I have an extension claim type say extension_isEmailVerified. I want to block user from login based on the value of this claim type. If it is true then user can login and if false then need to show an error message in the login page that your email is not verified.
<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Email">
<DisplayName>Local Account Signin</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="SignUpTarget">SignUpWithLogonEmailExchange</Item>
<Item Key="setting.operatingMode">Username</Item>
<Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="signInName" Required="true" />
<OutputClaim ClaimTypeReferenceId="password" Required="true" />
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="login-NonInteractive" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
Above is my sign in technical profile.
You can add additional validation technical profiles to validate the custom attribute and display an error message if it isn't set to the expected value as follows:
(Note that if the login-NonInteractive validation technical profile doesn't succeed then the additional validation technical profiles aren't executed.)
<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Email">
...
<Metadata>
<Item Key="UserMessageIfClaimsTransformationBooleanValueIsNotEqual">Oops, your email hasn't been verified.</Item>
</Metadata>
...
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="login-NonInteractive" />
<ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingObjectId" />
<ValidationTechnicalProfile ReferenceId="ClaimsTransformation-AssertEmailVerified" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
The ClaimsTransformation-AssertEmailVerified technical profile (see Define a claims transformation technical profile for more information about a claims transformation technical profile) is defined as:
<ClaimsProvider>
<DisplayName>Claims Transformation</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="ClaimsTransformation-AssertEmailVerified">
<DisplayName>Assert Email Verified Claims Transformation</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="extension_EmailVerified" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="AssertEmailVerified" />
</OutputClaimsTransformations>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
The AssertEmailVerified claims transformation is defined as:
<ClaimsTransformation Id="AssertEmailVerified" TransformationMethod="AssertBooleanClaimIsEqualToValue">
<InputClaims>
<InputClaim ClaimTypeReferenceId="extension_EmailVerified" TransformationClaimType="inputClaim" />
</InputClaims>
<InputParameters>
<InputParameter Id="valueToCompareTo" DataType="boolean" Value="true" />
</InputParameters>
</ClaimsTransformation>
Can you pass password claims between steps in Azure AD B2C Custom Policies?
My symptom is that after signing up using a multiple page custom policy, a user cannot sign in until they reset their password.
I am asking this as I spent many hours debugging a problem that it turns out could not be fixed. I found the answer under another question (Azure AD B2C Multi steps custom policy) that was differently worded but had similar symptoms.
I am posting here in the hope it is more easily found and helpful to others. Apologies if you think this is a duplicate.
In short, no. See Azure AD B2C Multi steps custom policy.
A password claim is "scoped" to a given step. This means the orchestration step that collects the password claim from the end user must be the same step that writes it to the User object.
I was looking for the same and have found a way to do multi step sign up. I tried several methods, including a outputclaimstransformation to store the password in another claim, but that did not work out. Because I already needed to do some input validation against an API I found a way to also copy the password to a new claim (plaintextPassword) that is not scoped to one orchestration step. This claim can be used in a later step to create the user account with the password provided by the plaintextPassword claim.
Create a self asserted technical profile that has an inputclaim (the password) and a validation technical profile. In the validation technical profile you can copy the password to a claim of type string with an inputclaimstransformation. Then add the new claim as outputclaim to the validation profile and to the technical profile. See code below for an example:
<ClaimType Id="plaintextPassword">
<DisplayName>password</DisplayName>
<DataType>string</DataType>
<UserInputType>TextBox</UserInputType>
</ClaimType>
<ClaimType Id="password">
<DisplayName>Your password</DisplayName>
<DataType>string</DataType>
<UserHelpText>Your password</UserHelpText>
<UserInputType>Password</UserInputType>
</ClaimType>
<ClaimsTransformation Id="CopyPassword" TransformationMethod="FormatStringClaim">
<InputClaims>
<InputClaim ClaimTypeReferenceId="password" TransformationClaimType="inputClaim" />
</InputClaims>
<InputParameters>
<InputParameter Id="stringFormat" DataType="string" Value="{0}" />
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="plaintextPassword" TransformationClaimType="outputClaim" />
</OutputClaims>
</ClaimsTransformation>
<TechnicalProfile Id="SignUp-PasswordValidation">
<DisplayName>Email signup</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</Item>
<Item Key="AuthenticationType">ClientCertificate</Item>
<Item Key="SendClaimsIn">Body</Item>
</Metadata>
<CryptographicKeys>
<Key Id="ClientCertificate" StorageReferenceId="B2C_1A_ClientCertificate" />
</CryptographicKeys>
<InputClaimsTransformations>
<InputClaimsTransformation ReferenceId="CopyPassword" />
</InputClaimsTransformations>
<InputClaims>
<InputClaim ClaimTypeReferenceId="claim_to_validate" PartnerClaimType="claim_to_validate" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="plaintextPassword" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
<TechnicalProfile Id="SignUp">
<DisplayName>Email signup</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="IpAddressClaimReferenceId">IpAddress</Item>
<Item Key="ContentDefinitionReferenceId">api.localaccountsignup</Item>
<Item Key="setting.retryLimit">3</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="email" Required="true" />
<OutputClaim ClaimTypeReferenceId="claim_to_validate" Required="true" />
<OutputClaim ClaimTypeReferenceId="password" Required="true" />
<OutputClaim ClaimTypeReferenceId="executed-SelfAsserted-Input" DefaultValue="true" />
<OutputClaim ClaimTypeReferenceId="plaintextPassword" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="SignUp-Validation" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
In the technical profile where you create the user in AAD add this line:
<PersistedClaim ClaimTypeReferenceId="plaintextPassword" PartnerClaimType="password"/>
I was able to solve the problem. When we have to add the user information (LocalAccountSignUpWithLogonEmail) I removed the validation that called the technical profile that is written in AAD, I changed it to a validation that calls another technical profile. This will copy our password through a ClaimsTransformation that will save our password in another InputClaim to be visible in any other step of our flow.
<ClaimType Id="plaintextPassword">
<DisplayName>password</DisplayName>
<DataType>string</DataType>
</ClaimType>
<ClaimType Id="passwordTransformation">
<DisplayName>requestSocialRestSecondCall</DisplayName>
<DataType>string</DataType>
</ClaimType>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="TransformationPassword" />
</ValidationTechnicalProfiles>
<ClaimsProvider> <!-- Copy Password-->
<DisplayName>Copy Password</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="TransformationPassword">
<DisplayName>Copy Pass</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<InputClaims>
<InputClaim ClaimTypeReferenceId="passwordTransformation" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="passwordTransformation" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="Generate_TranformationPassword" />
</OutputClaimsTransformations>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsTransformation Id="Generate_TranformationPassword" TransformationMethod="CopyClaim">
<InputClaims>
<InputClaim ClaimTypeReferenceId="newPassword" TransformationClaimType="inputClaim" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="plaintextPassword" TransformationClaimType="outputClaim" />
</OutputClaims>
</ClaimsTransformation>
I removed the validation that called the technical profile that is written in AAD and changed it to a validation that calls another technical profile.
This will copy the password through a ClaimsTransformation that will save our password in another InputClaim to be visible in any other step of our flow.
<TechnicalProfile Id="SignUp-PasswordValidation">
<Metadata>
<Item Key="ServiceUrl">url</Item>
<Item Key="AuthenticationType">ClientCertificate</Item>
<Item Key="SendClaimsIn">Body</Item>
</Metadata>
What is the url you used?
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
What was you application to create the Secret?
I am developing a RESTful Service, which gets called during the Signup/Signin Process in Azure AD B2C. My Service logs state, that data successfully arrives, and output-claims (customerId) get created.
But I receive the following error message, and the user doesn't get created:
AADB2C90161 A self-asserted send response has failed with reason (Internal Server Error).
Correlation ID 7eac5fd2-cd85-4535-b166-4cc8f0264d07
I have oriented myself towards this example: https://github.com/Azure-Samples/active-directory-b2c-custom-policy-starterpack/tree/master/scenarios/aadb2c-ief-rest-api-netfw/
Did anyone experience similar issues and has a hint what could be the problem in my case?
in TrustFrameworkExtension:
<ClaimsProvider>
<DisplayName>KTM REST APIs</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="REST-API-SignUp">
<DisplayName>Generate and return customerID claim</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">https://<my.service.com>/api/Identity/Signup</Item>
<Item Key="AuthenticationType">None</Item>
<Item Key="SendClaimsIn">Body</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="Email" />
<InputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="FirstName" />
<InputClaim ClaimTypeReferenceId="surname" PartnerClaimType="LastName" />
<InputClaim ClaimTypeReferenceId="testClaim" PartnerClaimType="ObjectId" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="customerId" PartnerClaimType="CustomerId" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="customerId" PartnerClaimType="CustomerId" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="REST-API-SignUp" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
In this case, you have a run-time error. The claim type "customerId" is defined as a string in the policy, but looks like the value coming over the wire (where partnerClaimType is "CustomerId") is a number, so the system is unable to map it. See this line:
<OutputClaim ClaimTypeReferenceId="customerId" PartnerClaimType="CustomerId" />
This is how a Rest API will return a string vs a number (note the absence of quotes in a number):
{
"name": "John",
"age": 24
}
While this message can be improved, you should configure your policy to collect logs using Application Insights. This will allow you to debug similar run-time issues more easily.