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.
Related
I am using B2C custom policies which allows signup/signin with the username instead of the traditional email.
As part of the signup process, I am saving the Email in the otherMails attribute.
when choosing MFA as Email, I don't see the email field prepopulated with the email that I have on user record.
Can otherMails attribute be used for MFA email?
<ClaimsTransformation Id="CreateEmailsFromOtherMailsAndSignInNamesInfo" TransformationMethod="AddItemToStringCollection">
<InputClaims>
<InputClaim ClaimTypeReferenceId="otherMails" TransformationClaimType="collection" />
</InputClaims>
<TechnicalProfile Id="AAD-UserWriteUsingLogonName">
<PersistedClaims>
<PersistedClaim ClaimTypeReferenceId="otherMails" />
</PersistedClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="otherMails" />
</OutputClaims>
<TechnicalProfile Id="LocalAccountSignUpWithLogonName">
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="otherMails" />
</OutputClaims>
<TechnicalProfile Id="LocalAccountDiscoveryUsingUserNameAndValidateStrongAuthenticationEmailAddress">
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="otherMails" />
</OutputClaims>
<TechnicalProfile Id="AAD-ReadCommon">
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="otherMails" />
</OutputClaims>
<RelyingParty>
<OutputClaim ClaimTypeReferenceId="otherMails" PartnerClaimType="emails" />
</RelyingParty>
The field used for MFA is "strongAuthenticationEmailAddress".
That's used by the back end so I doubt it can be changed.
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.
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>
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.
I am using starter pack of custom polices with SocialAndLocalAccounts pack.
It is working fine for me.
But I am facing one issue.I need to get email as claim after successfully login.
I am getting email as claim, once user has been been signed-up and redirects back immediately to application.
but I am not getting it when a user simply signs-in.
How can I get that?
where do I need to write an Output Claim to get the value of email in claim?
Kindly help me.
Thanks
For Chris Padgett's answer, you can add other emails (Alternate email) into the claim.
If you just want to add email claim from the SignIn name into the token, you can just take following steps:
Open your SignUporSignIn.xml file
Replace <OutputClaim ClaimTypeReferenceId="email" /> with <OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email" />
Save this SignUporSignIn.xml file and upload it to Azure AD B2C to overwrite the policy.
Run the SignUporSignIn policy to test it.
Here is my test result, you can see the email claim in the token:
Hope this helps.
Following describes how you can save, load, and then issue the otherMails claim as emails from the sign-up/sign-in and password reset policies.
When writing a local account: You must create the otherMails claim from the email claim using the CreateOtherMailsFromEmail claims transformation and then persist the otherMails claim in the AAD-UserWriteUsingLogonEmail technical profile:
<TechnicalProfile Id="AAD-UserWriteUsingLogonEmail">
...
<IncludeInSso>false</IncludeInSso>
<InputClaimsTransformations>
<InputClaimsTransformation ReferenceId="CreateOtherMailsFromEmail" />
</InputClaimsTransformations>
<InputClaims>
...
</InputClaims>
<PersistedClaims>
...
<PersistedClaim ClaimTypeReferenceId="otherMails" />
</PersistedClaims>
<OutputClaims>
...
<OutputClaim ClaimTypeReferenceId="otherMails" />
</OutputClaims>
...
</TechnicalProfile>
You must then pass the otherMails claim out from the LocalAccountSignUpWithLogonEmail technical profile that is invoked to register a local account:
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
...
<OutputClaims>
...
<OutputClaim ClaimTypeReferenceId="otherMails" />
</OutputClaims>
</TechnicalProfile>
When writing a social account: The otherMails claim is already created from the email claim and then persisted in the AAD-UserWriteUsingAlternativeSecurityId technical profile.
You must then pass the otherMails claim out from the SelfAsserted-Social technical profile that is invoked to register a social account:
<TechnicalProfile Id="SelfAsserted-Social">
...
<OutputClaims>
...
<OutputClaim ClaimTypeReferenceId="otherMails" />
</OutputClaims>
</TechnicalProfile>
When reading a local or social account: The otherMails claim is already read in the AAD-UserReadUsingObjectId, AAD-UserReadUsingEmailAddress, and AAD-UserReadUsingAlternativeSecurityId technical profiles.
You must then pass the otherMails claim out from the LocalAccountDiscoveryUsingEmailAddress technical profile that is invoked to recover a local password:
<TechnicalProfile Id="LocalAccountDiscoveryUsingEmailAddress">
...
<OutputClaims>
...
<OutputClaim ClaimTypeReferenceId="otherMails" />
</OutputClaims>
</TechnicalProfile>
To issue the otherMails claim as emails from the sign-up/sign-in and password reset policies: You must add the otherMails claim as <OutputClaim /> to the relying party policies:
<RelyingParty>
...
<TechnicalProfile Id="PolicyProfile">
<OutputClaims>
...
<OutputClaim ClaimTypeReferenceId="otherMails" PartnerClaimType="emails" />
</OutputClaims>
</TechnicalProfile>
</RelyingParty>
Another option that is working for me was to extend AAD-UserReadUsingObjectId so that it copies the signInNames.emailAddress claim into email. That brought sign-in into alignment with our other journeys/sub-journeys for integrated sign-up, password reset, and social log-in -- which each populate email during first log-in/sign-up.
All I needed to do was add this to TrustFrameworkExtension.xml (under <ClaimsProviders>):
<ClaimsProvider>
<DisplayName>Azure Active Directory</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="AAD-UserReadUsingObjectId">
<OutputClaims>
<OutputClaim
ClaimTypeReferenceId="email"
PartnerClaimType="signInNames.emailAddress"
/>
</OutputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>