How to do a two way synchronization of user credential (Microsoft AD B2C) with a proprietary database - azure-ad-b2c

We need to see the feasibility of synchronization of user credentials
between the Microsoft AD B2C and proprietary database in real time.
If it is feasible do you have any pointers on 'how to'.
What is the hashing algorithm used in the MS AD B2C credentials? is
there a ay to customize it?

Use a REST API call during the Sign Up and Password Reset authentication journey's to send the captured password claim to your API. Your API can then update your DB to keep it in sync.
You can call your REST API and can send any claims captured in the journey using this guide.
In this case, since you are looking to send a password, you must call your REST API as part of a validation technical profile, instead of directly as an orchestration step.
You can send the plaintext password to your API.
Here is an outline of what you need to configure:
In the sign up technical profile, add a call to your REST API as a validation technical profile.
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
<DisplayName>Email signup</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
...
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonEmail" />
<ValidationTechnicalProfile ReferenceId="REST-SyncPasswordToDB" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
Create the REST API technical profile to send the password to your endpoint:
<TechnicalProfile Id="REST-SyncPasswordToDB">
<DisplayName>REST API call to communicate with Legacy DB</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://myApi.com/api/syncPassword</Item>
<Item Key="AuthenticationType">None</Item>
<Item Key="SendClaimsIn">Body</Item>
<Item Key="AllowInsecureAuthInProduction">True</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="email" />
<InputClaim ClaimTypeReferenceId="password" />
</InputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>

Related

Share session between two different (but very similar) TechnicalProfiles

Scenario is that during combined SignIn/SignUp flow I'm using following TechnicalProfile for signing in the user with local account:
Base.xml
<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">Email</Item>
<Item Key="ContentDefinitionReferenceId">api.signuporsignin</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>
Extensions:
<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Email">
<Metadata>
<Item Key="setting.forgotPasswordLinkOverride">ForgotPasswordExchange</Item>
</Metadata>
</TechnicalProfile>
Base.xml is taken from one of the starter-packs available on GitHub.
This is working fine and when I'm logged in and go to combined SignUp/SignIn policy again, I'm authenticated automatically without needing to provide any credentials or to select external IdP.
Now, for some other flows (ProfileEdit, PasswordChange) I've slightly modified SelfAsserted-LocalAccountSignin-Email technical profile to not show SignUp/ForgotPassword links.
Technical profile definition:
<TechnicalProfile Id="SelfAsserted-LocalAccountSigninOnly-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="setting.showSignupLink">False</Item>
<Item Key="setting.forgotPasswordLinkLocation">none</Item>
</Metadata>
<IncludeTechnicalProfile ReferenceId="SelfAsserted-LocalAccountSignin-Email" />
</TechnicalProfile>
As you can see, it includes the SelfAsserted-LocalAccountSignin-Email and just overrides two setting values.
However, now when the user is authenticated after executing combined SignUp/SignIn policy and he goes to my ProfileEdit policy, he is prompted to authenticate again.
This happens only if user was authenticated using local account, as in my case SignUp/SignIn & ProfileEdit/PasswordChange policies are using different (but very similar) SelfAsserted technical profiles. If user was authenticated using any social idp, ProfileEdit/PasswordChange policies work fine without prompting user for reauthentication.
Any ideas how to solve the issue for the local account?
One solution would be to use the same technical profile for combined SignUp/SignIn and ProfileEdit/PasswordChange and then hide links where necessary using JavaScript, however, if possible I would like to minimize changes made by JS.

How to display REST error message in Azure B2C

I have a custom policy and we are doing a REST call to an API endpoint to do a value check. The API returns and I get the error message however it ejects/ stops the flow. From a customer point of view that is not what I am looking for.
I want to display the error message above where they entered the email address and not stop the flow.
I have the orchestration step to do the REST call working fine, but how do I get it to show a warning message instead of stopping the flow?
So an example:
In our reset password flow we are checking to see if the customer has a specific member flag in our database API.
This orchestration step is ran.
<OrchestrationStep Order="2" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="CheckMemberAccountHolder" TechnicalProfileReferenceId="REST-CheckMemberxAccountHolder" />
</ClaimsExchanges>
</OrchestrationStep>
And this is the Technical Profile
<ClaimsProvider>
<DisplayName>REST API to Check Member Account Holder</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="REST-CheckMemberAccountHolder">
<DisplayName>Rest API call to Check Member status</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">{API}</Item>
<Item Key="SendClaimsIn">QueryString</Item>
<Item Key="AuthenticationType">None</Item>
<Item Key="AllowInsecureAuthInProduction">true</Item>
<Item Key="DefaultUserMessageIfRequestFailed">Not an Active account</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="emailaddress"/>
</InputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
When testing this in B2C it displays like this when the error happens.
It is ejecting and showing the error.
I would like it to display a message where all the other error messages do.
just an example:
Edit:
Ok i made the following changes.
<ClaimsProvider>
<DisplayName>REST API to Check Member Status</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="MemberAccountHolderCollector">
<DisplayName>Verify member status</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.register</Item>
<Item Key="setting.showContinueButton">No</Item>
</Metadata>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="requireRegistration" DefaultValue="false" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="REST-CheckMemberAccountHolder" ContinueOnError="false"/>
</ValidationTechnicalProfiles>
</TechnicalProfile>
<TechnicalProfile Id="REST-CheckMemberAccountHolder">
<DisplayName>Rest API call to Check Member status</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">API</Item>
<Item Key="SendClaimsIn">QueryString</Item>
<Item Key="AuthenticationType">None</Item>
<Item Key="AllowInsecureAuthInProduction">true</Item>
<Item Key="DefaultUserMessageIfRequestFailed">You Did not say the Magic Word</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="emailaddress"/>
</InputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
</ClaimsProviders>
The orchestration step now calls the collection which will do the validation technical profile.
The api.selfasserted.register reference goes to an HTML template.
This does it no matter what.. whether the API returns 200 or anything else.
Basically, I only want it to show this if it returns anything other than 200.
Call your REST API as a validation technical profile as part of a self asserted technical profile. Then the error from your API can be presented to the screen, as there is a page being rendered.
https://learn.microsoft.com/en-us/azure/active-directory-b2c/validation-technical-profile
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonEmail" />
<ValidationTechnicalProfile ReferenceId="REST-CheckMemberAccountHolder" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>

Sending a Claim in a validation Technical Profile

I am dong a validation check to our database during our password forget policy.
During this process, it calls and API and needs a bearer token. I already have a technical profile to do this we use in another step.
So in this process, It keeps failing to look for the bearer token. It is saying the only token available in the email.
I need to do a step in between to get the bearer token, but I'm not sure how to do that since I'm doing a validation...
Here is what I have. After I type in the email to validate it.
<ClaimsProvider>
<DisplayName>REST API to Check Member</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="LocalAccountDiscoveryUsingEmailAddress">
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="REST-CheckMemberAccountHolder" ContinueOnError="false"/>
</ValidationTechnicalProfiles>
</TechnicalProfile>
<TechnicalProfile Id="REST-CheckMemberAccountHolder">
<DisplayName>Rest API call to Check Member status</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">{API}</Item>
<Item Key="SendClaimsIn">Body</Item>
<Item Key="AuthenticationType">Bearer</Item>
<Item Key="UseClaimAsBearerToken">bearerToken</Item>
<Item Key="AllowInsecureAuthInProduction">false</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="emailaddress"/>
<InputClaim ClaimTypeReferenceId="bearerToken" />
</InputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
I need it to call
<TechnicalProfile Id="REST-AcquireAccessToken">
To get the bearertoken for the REST call in the validation.
I cant seem to figure out how to do it.
As per this, I assume you had something like:
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="bearerToken" PartnerClaimType="access_token" />
</OutputClaims>
when you acquired the token?
Is this all part of the same user journey?
What do you mean by "saying the only token available in the email"?

Getting access token for an api protected by B2C, using custom policies

I have an api that is protected using ADB2C authentication. I need to call this api via custom policies. I followed the documentation enter link description here and have added the two technical profiles as validation technical profile of a self asserted profile.
I am getting an access token returned by the below technical profile :
<TechnicalProfile Id="SecureREST-AccessToken">
<DisplayName></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://login.microsoftonline.com/{tenant id here}/oauth2/v2.0/token</Item>
<Item Key="AuthenticationType">Basic</Item>
<Item Key="SendClaimsIn">Form</Item>
</Metadata>
<CryptographicKeys>
<Key Id="BasicAuthenticationUsername" StorageReferenceId="B2C_1A_SecureRESTClientId" />
<Key Id="BasicAuthenticationPassword" StorageReferenceId="B2C_1A_SecureRESTClientSecret" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="grant_type" DefaultValue="client_credentials" />
<InputClaim ClaimTypeReferenceId="scope" DefaultValue="{app id uri for protected resource}/.default" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="bearerToken" PartnerClaimType="access_token" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
And then making the rest api call using below profile :
<TechnicalProfile Id="UserMigrationViaLegacyIdp">
<DisplayName>REST API call to communicate with Legacy IdP</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://99a0a14a6402.ngrok.io/api/Identity/SignUpAsync
</Item>
<Item Key="AuthenticationType">Bearer</Item>
<Item Key="SendClaimsIn">Header</Item>
<Item Key="AllowInsecureAuthInProduction">false</Item>
<Item Key="UseClaimAsBearerToken">bearerToken</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="bearerToken"/>
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="phonePresent"/>
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
However, scopes are missing from the returned access token, hence token validation is failing on the api.
Is my call to get access token missing anything?
For the client credentials grant flow, the API permissions must be created as roles (see How to: Add app roles to your application and receive them in the token) and then granted admin consent (see Admin consent button).
As result, the bearer token contains the roles claim, rather than the scp claim.
The API application checks access using this roles claim (see Verify app roles in APIs called by daemon apps).

Howto Enable Email Verification in Azure AD B2C

How do I enable email verification in B2C w/ custom policies?
In an attempt to reverse engineer it, I tried disabling it in a built-in policy and downloaded the policy. I tried adding that metadata item to my self-asserted technical profile but that didn't work.
Reverse Engineer Test | Built-In Policy
<TechnicalProfile Id="SelfAsserted-Input">
<Metadata>
<Item Key="EnforceEmailVerification">False</Item>
</Metadata>
</TechnicalProfile>
My Self-Asserted Technical Profile
<TechnicalProfile Id="LocalAccountSignUp">
<DisplayName>User signup</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="EnforceEmailVerification">True</Item>
</Metadata>
...
</TechnicalProfile>
I'm using usernames for local accounts incase that matters.
Whether a local account is created with an email address- or user name-based sign-in name, you add email verification by adding PartnerClaimType="Verified.Email" to the "email" output claim of your self-asserted technical profile, as follows:
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />

Resources