Azure AD B2C SelfAssertedAttributeProvider - azure-ad-b2c

There are 4 data URIs (taking out older versions)
urn:com:microsoft:aad:b2c:elements:contract:selfasserted:1.1.0
urn:com:microsoft:aad:b2c:elements:contract:multifactor:1.1.0
urn:com:microsoft:aad:b2c:elements:contract:unifiedssp:1.1.0
urn:com:microsoft:aad:b2c:elements:contract:globalexception:1.1.0
My biggest concern is the first one as it is overloaded, and if I put it in a concrete example of the starter pack’s password-reset journey, the first tech-profile of this journey is LocalAccountDiscoveryUsingEmailAddress
The content-def this tech profile is api.localaccountpasswordreset and the data-URI is obviously urn:com:microsoft:aad:b2c:elements:contract:selfasserted:1.1.0
So while climbing up this ladder from user-journey -- > orch.-step -- > tech-profile -- > content-def. -- > data-URI (where actually B2C prepares its own portion of HTML for the browser),
as we know, the OutputClaims in the SelfAssertedAttributeProvider indicates that these claims need to be sent back by the provider and thus will be sourced from the user. In this profile we have following output-claims.
But it is obvious that this provider will NOT prepare UI-widgets to collect values of objectId OR userPrincipalName OR authenticationSource
So in general who made this decision about which output-claims user will be prompted to fill-in ?
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
<OutputClaim ClaimTypeReferenceId="strongAuthenticationPhoneNumber" />
</OutputClaims>
Thanks.

Got it Chris !!! Thank you so much.
Just for the benefit of everybody, I overlooked following sentence in the doc.
"If the self-asserted technical profile contains a validation technical profile that outputs the same claim, Azure AD B2C does not present the claim to the user."
Thanks

The output claims for a self-asserted technical profile can be sourced as follows:
Collected from the end user
Defaulted to a fixed value
Returned from a validation technical profile
Returned from a claims transformation
In the following example:
The email, newPassword and reenterPassword claim is collected from the end user
The executed-SelfAsserted-Input claim is defaulted to a fixed value (so the end user isn't prompted for it)
The objectId claim is returned from the AAD-UserWriteUsingLogonEmail validation technical profile (so the end user isn't prompted for it)
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
...
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />
<OutputClaim ClaimTypeReferenceId="newPassword" Required="true" />
<OutputClaim ClaimTypeReferenceId="reenterPassword" Required="true" />
<OutputClaim ClaimTypeReferenceId="executed-SelfAsserted-Input" DefaultValue="true" AlwaysUseDefaultValue="true" />
...
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonEmail" />
</ValidationTechnicalProfiles>
...
</TechnicalProfile>
<TechnicalProfile Id="AAD-UserWriteUsingLogonEmail">
...
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
...
</OutputClaims>
...
</TechnicalProfile>
The Output claims section of the Define a self-asserted technical profile in an Azure Active Directory B2C custom policy article explains this further.

Also on the same thread, may I ask one more clarification about Self-Asserted tech-profile.
What is the need of CryptographicKeys in this profile ?
for eg., how is this signature-key logically used which I am finding in the starter pack ?
Thanks.

Related

Azure B2C sign in with username?

I'm pretty new working with B2C custom policies, and currently I'm trying to setup an integration with one client using SAML. That client is sending us their employeeId as ID in the SAML payloads.
I got an integration working with okta with I'm using emails, but haven't had any luck with something different.
This is how my technical profile looks like when I have it working with an email account.
<TechnicalProfiles>
<TechnicalProfile Id="MySAML2">
<DisplayName>SAML Integration</DisplayName>
<Protocol Name="SAML2" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="email" />
...
</OutputClaims>
</TechnicalProfile>
</TechnicalProfiles>
So I've tried changing it to look like this
<OutputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="objectId" />
or
<OutputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="sub" />
or
<OutputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="name" />
or
<OutputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="key" />
but none of those have worked so far. Any advice will be very helpful. Thanks
There's a write-up of the mappings here.
The RHS in the Technical Profile is the SAML name. The LHS is the B2C name.
So if SAML is sending a claim called "employeeId" than the mapping is:
<OutputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="employeeId" />
But you need to look at the SAML attributes to see if there is a claim called "employeeId".

Is there a way for use UserName instead of email in Password Reset flow in Azure AD B2C?

I'm customizing the PasswordReset flow in azure ad b2c using custom policies, but i can't find a way for use UserName instead Email for restore password. I've tried to use input signInName instead of email in the technical profile AAD-UserReadUsingEmailAddress, but still shows the email in the form.
<TechnicalProfile Id="AAD-UserReadUsingEmailAddress">
<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="signInName" PartnerClaimType="signInNames.userName" Required="true" />
</InputClaims>
<OutputClaims>
<!-- Required claims -->
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
<!-- Optional claims -->
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="accountEnabled" />
<OutputClaim ClaimTypeReferenceId="otherMails" />
<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="AssertAccountEnabledIsTrue" />
</OutputClaimsTransformations>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>
It's possible to do this with userName?
This technical profile is the implementation to READ the account. What you are trying to achieve is to show the Username text box first and foremost. To display something on screen, you need to modify a selfAsserted technical profile.
The key is to change the operating mode to Username in the selfAsserted technical profile which asks the user for their identifer (which from the starter pack is: LocalAccountDiscoveryUsingEmailAddress), the latest key name is setting.operatingMode, reference here, set it to username. Then the textbox validation will be for username.
There is a complete sample here, and you can quick deploy using this link.

Azure B2C: Checking if another claim exists during local account creation

In addition to the usual creation of an account based on whether the e-mail used doesn't currently exist, I would like to know how I can also check if another claim value doesn't exist in Azure Active Directory.
For example, for our application, anyone who creates an account must provide an organization name. Once they signup, they are the owner of their organization group.
Before account creation, I want to check if an organization name is not associated with any other account (we're going to do sign-up via invitation if the owner wants to add people to their organization). If it doesn't exist, then create the account. Otherwise, I want to throw an error and prevent the creation of an account.
After looking through the Azure B2C technical profiles documentation, I would think that modifying AAD-UserWriteUsingLogonEmail would be my best guess.
I've tried two approaches so far. The first approach was including the input claim for the organization name. However, this just freezes the test flow:
<TechnicalProfile Id="AAD-UserWriteUsingLogonEmail">
<Metadata>
<Item Key="Operation">Write</Item>
<Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">true</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" Required="true" />
<InputClaim ClaimTypeReferenceId="extension_organizationName" Required="true" />
</InputClaims>
<PersistedClaims>
<!-- Required claims -->
<PersistedClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" />
<PersistedClaim ClaimTypeReferenceId="newPassword" PartnerClaimType="password"/>
<PersistedClaim ClaimTypeReferenceId="displayName" DefaultValue="unknown" />
<PersistedClaim ClaimTypeReferenceId="passwordPolicies" DefaultValue="DisablePasswordExpiration" />
<!-- Optional claims. -->
<PersistedClaim ClaimTypeReferenceId="givenName" />
<PersistedClaim ClaimTypeReferenceId="surname" />
<PersistedClaim ClaimTypeReferenceId="extension_organizationName" />
</PersistedClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="newUser" PartnerClaimType="newClaimsPrincipalCreated" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
The second approach was something similar, but instead using an <InputClaimsTransformations> to check if an organization name exists via the DoesClaimExist action. When using this approach, I get the following error:
Unable to validate the information provided.
Since I'm new to creating custom policies, is modifying the AAD-UserWriteUsingLogonEmail profile on the right track or do I need a completely different approach?
EDIT:
After following Barbara's links, I was able to get the validation working. However, I'm still having issues trying to prevent an account that is using an organization that is already associated with another account. It seems that using an <InputClaimsTransformations> doesn't really do anything.
The error message Unable to validate the information provided. indicates that you did not configure your custom policy correctly to be able to use custom claims.
Thus you have to follow the documentation:
Get the application properties of the extensions app
Modify your custom policy to include the application properties in the AAD-Common-technical profile
Please follow the steps and try again.

Continue Azure B2C user journey on authentication failure

I am creating a custom user journey using Azure B2C Identity Experience Framework. My issue is that I want to continue the user journey when authentication fails. However, it appears that authentication failure is interpreted as an exception, which causes the journey to terminate.
This journey is intended to accommodate a just-in-time account migration process from a legacy idenity provider to B2C.
The flow that I am seeking to accomplish is:
Attempt authentication using a B2C sign in form
On authentication failure, query a REST API to determine if the user's email address exists in the legacy system
If email address exists, present user with a B2C signup form
Is this scenario even possible?
I am not sure if there is a way to continue on full authentication failure, but you might not need to do that if just checking the existence of the user's account is enough.
You can check if the entered username exists in B2C without attempting authentication. Setting the RaiseErrorIfClaimsPrincipalDoesNotExist metadata to false allows the B2C policy to continue if the user does not exist in the directory. You can then take the entered username and continue with other technical profiles.
I used the below snippet as a validation technical profile and if the object ID is found, I run the login-NonInteractive profile, if not, I run a custom authentication profile
<TechnicalProfile Id="AAD-UserReadUsingEmailAddress-NoError">
<Metadata>
<Item Key="Operation">Read</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">false</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="signInNames.emailAddress" />
</InputClaims>
<OutputClaims>
<!-- Required claims -->
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
<OutputClaim ClaimTypeReferenceId="extension_isMigrated" DefaultValue="False" />
<OutputClaim ClaimTypeReferenceId="strongAuthenticationPhoneNumber" />
<!-- Optional claims -->
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="accountEnabled" />
<OutputClaim ClaimTypeReferenceId="otherMails" />
<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" />
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>

When is ValidationTechnicalProfile executed?

At what stage in the processing of a TechnicalProfile X is the ValidationTP or IncludedTP executed? Before X produces OutputClaims? After?
Say my TP has the following claim. It also has a ValidationTP Y. Can Y persist 'email' (is it available to it)?
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />
Alternatively, say my TP X uses another Y as ValidationTP and Y inputs and outputs some claims (Input/OutputClaim). Are they available for output from X? Do I even need to mark them as OutputClaims if they are marked as OutputClaims in the ValidationTP?
A validation technical profile is executed after the self-asserted technical profile, which refers to validation technical profile, has executed.
Claims that are declared as output from the self-asserted technical profile are passed to the validation technical profile.
In the following example, the email claim is passed from the LocalAccountSignUpWithLogonEmail self-asserted technical profile to the AAD-UserWriteUsingLogonEmail validation technical profile:
<TechnicalProfile Id="AAD-UserWriteUsingLogonEmail">
<PersistedClaims>
<PersistedClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" />
</PersistedClaims>
</TechnicalProfile>
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonEmail" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
Claims that are declared as output from one validation technical profile that is referenced by a self-asserted technical profile are passed to other validation technical profiles that are referenced by this self-asserted technical profile.
In the following example, the objectId claim is passed from the AAD-UserWriteUsingLogonEmail validation technical profile to the REST-API-Signup validation technical profile:
<TechnicalProfile Id="AAD-UserWriteUsingLogonEmail">
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
</OutputClaims>
</TechnicalProfile>
<TechnicalProfile Id="REST-API-Signup">
<InputClaims>
<InputClaim ClaimTypeReferenceId="objectId" />
</InputClaims>
</TechnicalProfile>
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonEmail" />
<ValidationTechnicalProfile ReferenceId="REST-API-Signup" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
Claims that are declared as output from a validation technical profile and the self-asserted technical profile that refers to this validation technical profile are passed to other orchestration steps.
In the following example, the objectId claim is passed from the AAD-UserWriteUsingLogonEmail validation technical profile "through" the LocalAccountSignUpWithLogonEmail self-asserted technical profile to other orchestration steps:
<TechnicalProfile Id="AAD-UserWriteUsingLogonEmail">
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
</OutputClaims>
</TechnicalProfile>
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonEmail" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
For more information, see the Technical profile flow section of the About technical profiles in Azure Active Directory B2C custom policies article.

Resources