Azure B2C Custom Policy - Showing button on validation - azure

It looks like there is not a lot of help and forums on the Azure B2C Custom policy framework.
I have used the following technical profile for my custom policy.
<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="email" PartnerClaimType="signInNames.emailAddress" Required="true" />
</InputClaims>
<OutputClaims>
<!-- Required claims -->
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
<OutputClaim ClaimTypeReferenceId="strongAuthenticationPhoneNumber" />
<!-- 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>
This profile looks for the user and comes back with an error message if the user was not found in AD. However I want to show the user a button to sign up after the validation happens. How can I achieve this?
Any help will be appreciated!

Azure AD B2C Custom Policy is now a GA product and it has a lot of good documentation available.
What you want to achieve here very common and has been explained in starter pack. Its called a signuporsignin policy.
Walk through the article
https://learn.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-get-started-custom
You can also see the policies here
https://github.com/Azure-Samples/active-directory-b2c-custom-policy-starterpack/blob/master/SocialAndLocalAccountsWithMfa/TrustFrameworkBase.xml
Look at this technical profile https://github.com/Azure-Samples/active-directory-b2c-custom-policy-starterpack/blob/master/SocialAndLocalAccountsWithMfa/TrustFrameworkBase.xml#L981
providing this metadata might help
<Metadata>
<Item Key="SignUpTarget">SignUpWithLogonEmailExchange</Item>
<Item Key="setting.operatingMode">Email</Item>
<Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>
</Metadata>

Related

How to Set up direct sign-in for multi-tenant Azure Active Directory using Custom policy

I use Azure Ad b2c to authenticate users, using custom policy. I use this document to add login with Azure AD (https://learn.microsoft.com/en-us/azure/active-directory-b2c/identity-provider-azure-ad-multi-tenant?pivots=b2c -custom-policy).
I use this document to configure the iframe embedding:
(https://learn.microsoft.com/en-us/azure/active-directory-b2c/embedded-login?pivots=b2c-custom-policy)
But when I embed login page in ASP NetMVC page, and use login with Azure AD, it gives error:
My SignSignup
<RelyingParty>
<DefaultUserJourney ReferenceId="CustomSignUpSignIn" />
<UserJourneyBehaviors>
<JourneyFraming Enabled="true" Sources="https://test.dynatex.io https://testsquid.dynatex.io/" />
</UserJourneyBehaviors>
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
My B2C_1A_TRUSTFRAMEWORKEXTENSIONS.xml
<ClaimsProvider>
<Domain>onmicrosoft.com</Domain>
<DisplayName>Common AAD</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="AADCommon-OpenIdConnect">
<DisplayName>Multi-Tenant Azure Ad</DisplayName>
<Protocol Name="OpenIdConnect" />
<Metadata>
<Item Key="ProviderName">https://login.microsoftonline.com</Item>
<Item Key="METADATA">https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration</Item>
<!-- Update the Client ID below to the Application ID -->
<Item Key="response_types">code</Item>
<Item Key="response_mode">form_post</Item>
<Item Key="scope">openid profile email</Item>
<Item Key="HttpBinding">POST</Item>
<Item Key="UsePolicyInRedirectUri">false</Item>
<Item Key="DiscoverMetadataByTokenIssuer">true</Item>
<Item Key="client_id">9...</Item>
<Item Key="ValidTokenIssuerPrefixes">https://login.microsoftonline.com</Item>
<!-- <Item Key="ValidTokenIssuerPrefixes">https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000,https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111</Item> -->
</Metadata>
<CryptographicKeys>
<Key Id="client_secret" StorageReferenceId="B2C_1A_msa" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="loginHint" PartnerClaimType="login_hint" DefaultValue="{OIDC:LoginHint}" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="oid" />
<OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name" />
<OutputClaim ClaimTypeReferenceId="surName" PartnerClaimType="family_name" />
<OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="socialIdpAuthentication" />
<OutputClaim ClaimTypeReferenceId="identityProvider" PartnerClaimType="iss" />
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" />
<OutputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="email" />
<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email" />
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" />
<OutputClaim ClaimTypeReferenceId="roles" />
<OutputClaim ClaimTypeReferenceId="groups" />
You cannot perform federated logon with the "Embedded UI", since all external IdPs will block being displayed in the iframe.
For these scenarios, you need to redirect the user. One way is:
In the Sign In policy, replace the external links to point back to your app, eg myapp.com/signin?domain_hint=azureAD
Then, your app needs to redirect the user via AAD B2C policy like the normal flow, and pass a domain_hint parameter such that the user is autoamtically directed to the IdP they had selected in 1.

Azure b2c custom policy, LinkedIn Identity Provider, unable to get email address

I want to add LinkedIn as an identity provider to my azure b2c tenant.
I have already added Microsoft and Google as id providers.
However, when I added LinkedIn, it was impossible to retrieve an email address and put it in the azure b2c token.
Here is my custom policy base file: TrustFrameworkBase.xml
<ClaimsProvider>
<Domain>linkedin.com</Domain>
<DisplayName>LinkedIn</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="LinkedIn-OAuth2">
<DisplayName>LinkedIn</DisplayName>
<Protocol Name="OAuth2" />
<Metadata>
<Item Key="ProviderName">linkedin</Item>
<Item Key="authorization_endpoint">https://www.linkedin.com/oauth/v2/authorization</Item>
<Item Key="AccessTokenEndpoint">https://www.linkedin.com/oauth/v2/accessToken</Item>
<Item Key="ClaimsEndpoint">https://api.linkedin.com/v2/me</Item>
<Item Key="scope">r_emailaddress r_liteprofile</Item>
<Item Key="HttpBinding">POST</Item>
<Item Key="external_user_identity_claim_id">id</Item>
<Item Key="BearerTokenTransmissionMethod">AuthorizationHeader</Item>
<Item Key="ResolveJsonPathsInJsonTokens">true</Item>
<Item Key="UsePolicyInRedirectUri">false</Item>
<Item Key="client_id">MyLinkedInClientId</Item>
</Metadata>
<CryptographicKeys>
<Key Id="client_secret" StorageReferenceId="B2C_1A_LinkedInSecret" />
</CryptographicKeys>
<InputClaims />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="id" />
<OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="firstName.localized" />
<OutputClaim ClaimTypeReferenceId="surname" PartnerClaimType="lastName.localized" />
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="emailAddress" />
<OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="linkedin.com" AlwaysUseDefaultValue="true" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="socialIdpAuthentication" AlwaysUseDefaultValue="true" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="ExtractGivenNameFromLinkedInResponse" />
<OutputClaimsTransformation ReferenceId="ExtractSurNameFromLinkedInResponse" />
<OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName" />
<OutputClaimsTransformation ReferenceId="CreateUserPrincipalName" />
<OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId" />
<OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromAlternativeSecurityId" />
</OutputClaimsTransformations>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-SocialLogin" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
As we can see, the ClaimsEndPoint is https://api.linkedin.com/v2/me
But, this end point does not give access to the email address.
Here is the documentation detailing it:
Sign-in with linked-in
We see that to get the email address, we need to call another end point: https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))
I tried changing the ClaimsEndPoint to this but when uploading the custom policy, I got an error:
The policy being uploaded is not correctly formatted: '=' is an unexpected token.
I don't see what I could do to get the email address as a claim in the azure b2c token.
Can you please help?
As per this, you need to make an additional API call and pass the access token you already have.

Azure AD B2C AAD-UserReadUsingAlternativeSecurityId technical profile is throwing error

I have a custom policy with below technical profile to enable login from multiple Azure AD tenants. When I login with a valid work account the technical profile AAD-UserReadUsingAlternativeSecurityId is throwing an error. I have included the app insights output below. Since I have no control on how Azure AD B2C builds the graph api lookup within the technical profile, how can I go about finding and fixing the actual issue?
I checked the claim transformation that builds up the alternative security ID and found nothing, followed the starter pack and did not change anything
<TechnicalProfile Id="Common-AAD">
<DisplayName>Active Directory</DisplayName>
<!-- <DisplayName>Sign In</DisplayName> -->
<Protocol Name="OpenIdConnect" />
<Metadata>
<Item Key="client_id">dcaee4b4-61d6-45e6-88b2-b35a81e93077</Item>
<Item Key="UsePolicyInRedirectUri">0</Item>
<Item Key="METADATA">https://login.microsoftonline.com/common/.well-known/openid-configuration</Item>
<Item Key="response_types">code</Item>
<Item Key="scope">openid</Item>
<Item Key="response_mode">form_post</Item>
<Item Key="HttpBinding">POST</Item>
<Item Key="DiscoverMetadataByTokenIssuer">true</Item>
<!-- The key below allows you to specify each of the Azure AD tenants that can be used to sign in. Update the GUIDs below for each tenant. -->
<Item Key="ValidTokenIssuerPrefixes">
https://sts.windows.net/{GUID1-masked},
https://sts.windows.net/{GUID2-masked},
https://sts.windows.net/{GUID3-masked},
https://sts.windows.net/{GUID4-masked}
</Item>
<!-- The commented key below specifies that users from any tenant can sign-in. Uncomment if you would like anyone with an Azure AD account to be able to sign in. -->
<!-- <Item Key="ValidTokenIssuerPrefixes">https://sts.windows.net/</Item>-->
</Metadata>
<CryptographicKeys>
<Key Id="client_secret" StorageReferenceId="B2C_1A_AZB2CSecret" />
</CryptographicKeys>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="socialIdpAuthentication" />
<OutputClaim ClaimTypeReferenceId="identityProvider" PartnerClaimType="iss" />
<!-- <OutputClaim ClaimTypeReferenceId="socialIdpUserId" PartnerClaimType="sub" /> -->
<!-- Mark: issuerUserId below originally mapped to sub -->
<OutputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="oid" />
<OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
<OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name" />
<OutputClaim ClaimTypeReferenceId="surName" PartnerClaimType="family_name" />
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="unique_name" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName" />
<OutputClaimsTransformation ReferenceId="CreateUserPrincipalName" />
<OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId" />
<!-- <OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromAlternativeSecurityId" /> -->
</OutputClaimsTransformations>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-SocialLogin" />
</TechnicalProfile>
"AAD Request to https://graph.windows.net/34d8169d-0e97-4cc7-a8d0-57c29404f1b1/users?api-version=1.6-integrationOnly&%24filter=alternativeSecurityIds%2fany(x%3ax%2ftype+eq+6+and+x%2fidentityProvider+eq+%27https%3a%2f%2fsts.windows.net%{GUID-MASKED}%2f%27+and+x%2fkey+eq+X%2738623361343134642D623331622D343638322D396662382D663461376161666164643966%27) using method GET as request body is malformed.\r\nResponse: \n{"odata.metadata":"https://graph.windows.net/34d8169d-0e97-4cc7-a8d0-57c29404f1b1/$metadata#directoryObjects","value":[]}\r\n",
And after policy runs the error that is displayed to the app/user is : AADB2C99002: An account could not be found for the provided user ID. which is normal I guess as the user look up fails
"Open your browser and go to the OpenID Connect metadata URL for the tenant. Find the issuer object and record its value. It should look similar to https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/.well-known/openid-configuration".
When I do that, I get an issuer like:
"https://login.microsoftonline.com/GUID/v2.0"
But you have:
https://sts.windows.net/{GUID1-masked}
(The documentation seems wrong anyway - their issuer is the "well-known" address).
You shouldnt be calling AAD-UserReadUsingAlternativeSecurityId, you chould instead call AAD-UserReadUsingAlternativeSecurityId-NoError in the case of social logins, like here.
See the social login journey here for comparison from the Starter Pack.
There is a full explanation here of how this works in the readme.

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 Custom Flow Add field to login

I have an Azure B2C Custom Flow where I have defined the TrustFrameworkExtension.xml and signupsignin.xml. I have added the technicalProfile listed below with the expectation that a new free form text field will be added to the log in screen where the user can add their customer service rep's name. Unfortunately, this field is not added the login screen, but since I have the default value set to "Joe Representative", every login has an api call that is passing in "Joe Representative". So I have the part about passing the value to my API completed, I just need to know what I need to do to get the free form text to be displayed on the UI. Suggestions?
<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="setting.operatingMode">Email</Item>
<Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>
<Item Key="ServiceUrl">https://somewickedcoolurl</Item>
<Item Key="SendClaimsIn">Body</Item>
<!-- Set AuthenticationType to Basic or ClientCertificate in production environments -->
<Item Key="AuthenticationType">None</Item>
<!-- REMOVE the following line in production environments -->
<Item Key="AllowInsecureAuthInProduction">true</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" />
<!-- Claims sent to your REST API -->
<InputClaim ClaimTypeReferenceId="email" />
<InputClaim ClaimTypeReferenceId="repName" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="signInName" Required="true" />
<OutputClaim ClaimTypeReferenceId="password" Required="true" />
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
<!-- Optional claims, to be collected from the user -->
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surName" />
<OutputClaim ClaimTypeReferenceId="repName" DefaultValue="Joe Representative" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="login-NonInteractive" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
You cannot use an orchestration step with Type=CombinedSignInAndSignUp and also modify the Sign In page elements. This step type will always default to username/password regardless of adding output claims to the selfAsserted technical profile that controls the Sign In function.

Resources