Azure AD B2C Custom Policy with Sign Up Page Only - azure

I want to create a custom policy in Azure AD B2C. I can't find such an example in the starterpack.
I checked this post Azure AD B2C Link to Sign Up Page (Not Sign In) and, if I understand it correctly, there is no URL I can use for an existing custom signup_signin policy to end up directly in the Sign Up page. Creating "Sign up v2" flow works, but I need a custom one, and copying code from the build in one and placing it to the LocalAccounts example from the starterpack doesn't work.
This is the UserJourney code downloaded from "Sign up v2" flow
<UserJourney Id="B2CSignUp_V2">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="ClaimsProviderSelection" ContentDefinitionReferenceId="api.idpselections.signup">
<ClaimsProviderSelections>
<ClaimsProviderSelection TargetClaimsExchangeId="SignUpWithLogonEmailExchange" />
</ClaimsProviderSelections>
</OrchestrationStep>
</OrchestrationSteps>
</UserJourney>
I tried to replace the OrchestrationStep 1 and 2 from the starter pack with the one here but it doesn't work.

In your Custom policies, In the B2C_1A_TrustFrameworkBase.xml file replace the 1st Orchestration Step for the User Journey Id="SignUpOrSignIn" with the following Orchestration Step and you will be directly landed to Signup page -
<OrchestrationStep Order="1" Type="ClaimsProviderSelection" ContentDefinitionReferenceId="api.idpselections.signup">
<ClaimsProviderSelections>
<ClaimsProviderSelection TargetClaimsExchangeId="SignUpWithLogonEmailExchange" />
</ClaimsProviderSelections>
</OrchestrationStep>

Alternatively, you can:
Remove orchestration step 1
Remove the objectId precondition from orchestration step 2
Renumber the following orchestration steps
Such as:
<OrchestrationStep Order="1" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="SignUpWithLogonEmailExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonEmail" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="2" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="3" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />

Related

What does a PasswordChange with TOTP for Azure B2C look like?

I have an existing Azure B2C solution using custom policies and provides sign up / sign in via AAD, MS Account, Google and Local. I'm now adding TOTP MFA as provided by https://learn.microsoft.com/en-us/azure/active-directory-b2c/multi-factor-authentication?pivots=b2c-custom-policy.
I have SignUp/SignIn and Password Reset policies using TOTP working for the Local Account. I don't need TOTP for the social accounts. However, I'm struggling with a ChangePassword policy, where a user who is already logged in can change their password. For this step, I would like the user to verify themselves via TOTP before getting to change the password.
In my non-TOTP solution, I'm using the PasswordChange UserJourney as provided by https://learn.microsoft.com/en-us/azure/active-directory-b2c/add-password-change-policy?pivots=b2c-custom-policy
For completeness, it looks like this:
<UserJourney Id="PasswordChange">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="ClaimsProviderSelection" ContentDefinitionReferenceId="api.signuporsignin">
<ClaimsProviderSelections>
<ClaimsProviderSelection TargetClaimsExchangeId="LocalAccountSigninEmailExchange" />
</ClaimsProviderSelections>
</OrchestrationStep>
<OrchestrationStep Order="2" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="3" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="NewCredentials" TechnicalProfileReferenceId="LocalAccountWritePasswordChangeUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="4" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="5" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
</OrchestrationSteps>
<ClientDefinition ReferenceId="DefaultWeb" />
</UserJourney>
I was hoping to get away with something similar for PasswordChangeWithTOTP, by inserting the TotpFactor-Input and TotpFactor-Verify steps between steps 2 and 3 of the old policy.
<UserJourney Id="PasswordChangeWithTOTP">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="ClaimsProviderSelection" ContentDefinitionReferenceId="api.signuporsignin">
<ClaimsProviderSelections>
<ClaimsProviderSelection TargetClaimsExchangeId="LocalAccountSigninEmailExchange" />
</ClaimsProviderSelections>
</OrchestrationStep>
<OrchestrationStep Order="2" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Call the TOTP enrollment ub journey. If user already enrolled the sub journey will not ask the user to enroll -->
<OrchestrationStep Order="3" Type="InvokeSubJourney">
<JourneyList>
<Candidate SubJourneyReferenceId="TotpFactor-Input" />
</JourneyList>
</OrchestrationStep>
<!-- Call the TOTP validation sub journey-->
<OrchestrationStep Order="4" Type="InvokeSubJourney">
<JourneyList>
<Candidate SubJourneyReferenceId="TotpFactor-Verify" />
</JourneyList>
</OrchestrationStep>
<OrchestrationStep Order="5" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="NewCredentials" TechnicalProfileReferenceId="LocalAccountWritePasswordChangeUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="6" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="7" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
</OrchestrationSteps>
<ClientDefinition ReferenceId="DefaultWeb" />
</UserJourney>
minor talking points: I went with a new policy due to the release cycle of the application using it, and I'm not totally sold that I should offer TOTP registration as a part of this particular step, even though it's something we do for SignUpSignIn and PasswordReset.
The error that I get "The service received a bad request" when performing the "Get available strong authentication devices" activity. The error message has a target type User and Id consistent with similar operations used during sign in. I can't see anything else particularly jumping out at me.
I did try inserting a <ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" /> OrchestrationStep before the TotpFactor-Input step, but thought that may have been defeating the purpose of TOTP. I also didn't get prompted to provide a verification code before getting to change the password.
What should a PasswordChange with TOTP policy look like?
Do you have:
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
as an output claim from SelfAsserted-LocalAccountSignin-Email?
As far as I remember from docs/samples - userPrincipalName is required for TOTP SubJourneys to work.

Registration only site with custom policy

I have a task to create registration only custom policy. So I need a page to pick local account or different social provider. And after the user will be navigate to the proper registration site. I can manage this by standard policies, but I have to do this job with custom policies. Are there any was to do such think with custom policies? I didn't find any registration only reference in the starter pack....
rgds,
'child
This is covered here.
You can have as many IDP as you want.
The first step of the user journey will then have as many ClaimsProviderSelections as you require. This example is for adding Azure AD.
<ClaimsProviderSelections>
...
<ClaimsProviderSelection TargetClaimsExchangeId="AzureADContosoExchange" />
</ClaimsProviderSelections>
Update
Also, look in the B2C starter pack.
<UserJourney Id="SignUpOrSignIn">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
<ClaimsProviderSelections>
<ClaimsProviderSelection TargetClaimsExchangeId="FacebookExchange" />
<ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" />
</ClaimsProviderSelections>
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Check if the user has selected to sign in using one of the social providers -->
<OrchestrationStep Order="2" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="FacebookExchange" TechnicalProfileReferenceId="Facebook-OAUTH" />
<ClaimsExchange Id="SignUpWithLogonEmailExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonEmail" />
</ClaimsExchanges>
</OrchestrationStep>
You'll see there are two "ClaimsProviderSelection", one for local accounts and one for Facebook.

Azure AD B2C Custom Policy: REST technical profile validation doesn't work

I have created a custom policy for signup on Azure AD B2C, with the goal of only allowing users whose email is whitelisted to be able to register into the system.
For that, I have configured the custom policy with a REST technical profile.
I followed this guide: https://learn.microsoft.com/en-us/azure/active-directory-b2c/custom-policy-rest-api-claims-exchange?pivots=b2c-custom-policy
The associated web service receives the email of the user that wants to signup and verifies whether that user's email address is part of a list of emails that have been whitelisted. And if it's not, I return a message of the following format:
{
"userMessage": "Sorry, this email is not whitelisted",
"status": 409,
"version": "1.0.0"
}
If the email is part of the whitelist, I return:
{
"emailValue": "myemail#email.com",
"isWhiteListed": true
}
Here's what my user journey looks like (in Signup.xml file):
<UserJourneys>
<UserJourney Id="SignUp">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="SignUpWithLogonEmailExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonEmail" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- This step reads any user attributes that we may not have received when in the token. -->
<OrchestrationStep Order="2" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="3" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="RESTEmailWhitelist" TechnicalProfileReferenceId="REST-EmailWhitelist" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="4" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
</OrchestrationSteps>
<ClientDefinition ReferenceId="DefaultWeb" />
</UserJourney>
</UserJourneys>
The problem is that even after returning the 409 error in case the email is not whitelisted, it still successfully gets created in Azure AD B2C.
How do I prevent the user's account from being successfully created?
You’re probably running your “AAD-UserwriteUsingEmail” validation technical profile twice, once before the REST call, once after it. Delete the validation tech profile in your base file in the LocalAccountSignUpWithLogonEmail technical profile. Then put the validation tech profiles (AAD-userWriteUsingEmail and REST API) in your extension file, in the LocalAccountSignUpWithLogonEmail technical profile, in the correct order (REST then Write).

Custom policy add overlay message

I am using a custom policy for password change. I am following the custom policy mentioned here
https://learn.microsoft.com/en-us/azure/active-directory-b2c/add-password-change-policy?pivots=b2c-custom-policy
Is there any way to add an orchestration step that displays overlay message that password has been changed before SendClaims step.
The User Journey as mentioned in the link:
<UserJourney Id="PasswordChange">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="ClaimsProviderSelection" ContentDefinitionReferenceId="api.signuporsignin">
<ClaimsProviderSelections>
<ClaimsProviderSelection TargetClaimsExchangeId="LocalAccountSigninEmailExchange" />
</ClaimsProviderSelections>
</OrchestrationStep>
<OrchestrationStep Order="2" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="3" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="NewCredentials" TechnicalProfileReferenceId="LocalAccountWritePasswordChangeUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="4" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="5" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
</OrchestrationSteps>
<ClientDefinition ReferenceId="DefaultWeb" />
</UserJourney>
Between step 4 and step 5, add an orchestration step to call a selfAsserted technical profile.
Demonstrated here:
Add a step (you can remove the preconditions node)
https://github.com/azure-ad-b2c/samples/blob/master/policies/invite/policy/SignUpInvitation.xml#L165
SelfAsserted technical profile with a message
https://github.com/azure-ad-b2c/samples/blob/master/policies/invite/policy/SignUpInvitation.xml#L110
You must have one output claim in the selfAsserted technical profile. Here a claim transform is used to generate a string to display to the user.
All options available to a self asserted page
https://learn.microsoft.com/en-us/azure/active-directory-b2c/self-asserted-technical-profile
Apply custom html to the page to deliver the message/branding
https://learn.microsoft.com/en-us/azure/active-directory-b2c/customize-ui-with-html?pivots=b2c-custom-policy

Azure AD B2C Custom SignIn Policy Displays SignUpSignIn

I have a custom SignIn policy, because I need to fetch something from an application database (via REST API) during the sign in process.
So I have this user journey
<UserJourney Id="SignIn">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.localaccountsignin">
<ClaimsProviderSelections>
<ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" />
</ClaimsProviderSelections>
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="2" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="3" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="GetCustomDbObj" TechnicalProfileReferenceId="GetCustomDbObj" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="4" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
</OrchestrationSteps>
<ClientDefinition ReferenceId="DefaultWeb" />
</UserJourney>
You can see that in step #3, I have a reference to a custom technical profile that fetches some data from a custom REST API.
In the first step, I display (supposedly) the sign in page, it references api.localaccountsignin
<ContentDefinition Id="api.localaccountsignin">
<LoadUri>https://mytenant.b2clogin.com/static/tenant/default/signin.cshtml</LoadUri>
<RecoveryUri>https://mytenant.b2clogin.com/static/tenant/default/signin.cshtml</RecoveryUri>
<DataUri>urn:com:microsoft:aad:b2c:elements:contract:unifiedssp:1.0.0</DataUri>
<Metadata>
<Item Key="TemplateId">azureBlue</Item>
</Metadata>
</ContentDefinition>
The problem is that when I use the policy, I see a page that resembles the signup+signin unified policy
Instead of just the sign in policy, which is what I desire.
I suspect that it has something to do with
<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.localaccountsignin">
More specifically, CombinedSignInAndSignUp
But I don't know what to put instead. I tried using ClaimsExchange but it didn't work.
Is there a solution?
As per this:
You can achieve this by setting SignUp to “False”.
<Item Key=”setting.showSignupLink”>False</Item>

Resources