Azure B2C Azure Active Dicrectory retrieve email in token using policies - azure

I have an Azure B2C tenant I'm setting up using policies and I'm facing the following problem. One of my social providers is configured as an Azure Active Directory but, when getting the token, the email is not included.
I have other providers like Google or LinkedIn where I've been able to collect the email using these OutputClaims inside the TechnicalProfile of each ClaimProvider.
Google
<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email" />
LinkedIn
<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="elements[0].handle~.emailAddress" />
I'm wondering if there is a similar approach to what I need but the Azure Active Directory provide offers an email's PartnerClaimType.
I checked the doc for this kind of provider but found nothing. I checked as well the optional claims set and the email is mentioned but got no clue how to make it work.
Thank's for your time!

Try
<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="unique_name" />
https://learn.microsoft.com/en-us/azure/active-directory/develop/id-tokens#claims-in-an-id_token

Related

How do I add a user attribute in a SAML SSO response

I am working on using Azure AD B2C as the Identity Provider for a custom site that also provides SSO for a Blackboard Learn LMS site. Blackboard can do SSO through SAML, so I am using those capabilities within B2C. Unfortunately, SAML is not a protocol I am well-acquainted with, so my ability to troubleshoot is limited. I am working off of the tutorial at:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/saml-service-provider?tabs=windows&pivots=b2c-custom-policy
Everything is going mostly pretty well, but I am trying to map user attributes that are shared with Blackboard so that when a new user is created, they have at least a basic profile. There are a couple attributes that are coming through naturally in this tutorial, but I am trying to specify the username for the profile (specs require that it is the email address), and I am not having any luck.
I added the OutputClaim named "userPrincipalName" in the SignUpOrSignIn policy (see code below), as it has the appropriate value coming from B2C, but according to a Blackboard test page, it is not among the values that are being sent in the SAML response (see screenshot further down).
...
<RelyingParty>
<DefaultUserJourney ReferenceId="SignUpOrSignIn" />
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="SAML2"/>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="email" DefaultValue="" />
<OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="" />
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="objectId"/>
</OutputClaims>
<SubjectNamingInfo ClaimType="objectId" ExcludeAsClaim="true"/>
</TechnicalProfile>
</RelyingParty>
...
Are there further steps that need to happen? I have tinkered with the TrustFrameworkExtensions (and Base) here an there, as well, but to no avail, and I can't find any described process for adding new attributes to the SAML response. Does anyone have an example/tutorial that could walk me through it?
(I looked at this question and an answer indicates that I might need to change the NameIdFormat. I can see that the format in my B2C app metadata is incorrect as it suggests, but I'm not sure how I would go about changing it)
Update
Based on #JasSuri-MSFT's suggestion, I set a (non-empty) default value for the UPN, and sure enough, that default value came through. So it would seem that the problem is that the UPN is null.
This is strange, as in the edit page for the user in B2C, there is clearly a UPN value. It also highlights another oddity that I had not mentioned. But there are other OutputClaims listed in that policy that are not being included either. One of them, email, I explicitly provided a value for, and it is apparently presenting as null as well.
Clearly there is another piece in the plumbing somewhere that I don't have established.
Add signInNames.emailAddress as an output claim in AAD-UserReadUsingObjectId and add signInNames.emailAddress as an output claim in the RelyingParty section. Use a partnerClaimType in the output claim in the RelyingParty to issue the claim with the name you like into the SAML Response.
<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email"/>
https://github.com/azure-ad-b2c/azureadb2ccommunity.io/wiki/LocalAccount-Sign-In-and-Sign-Up-policy
https://learn.microsoft.com/en-us/azure/active-directory-b2c/user-profile-attributes#identities-attribute
https://learn.microsoft.com/en-us/azure/active-directory-b2c/active-directory-technical-profile#outputclaims

Understanding responses from just in time migration custom policy in Azure B2C

I have been slowly working through a custom policy to handle a JIT migration of an external IDP users to Azure B2C. It has been a long journey because there are many complexities in sorting out the components and the configuration steps using XML is a bit of a challenge. I am making some progress.
The basic use case is this: At sign in, the user/password is first checked against the B2C AD and if the user already exists just continue to sign in. If the user isn't in B2C AD, then check the external IDP with a REST call. I planned the response from the external IDP to be used in a binary way: If I get a 200 response, then add the user to B2C AD. If an error is returned then the user will be told to create an account.
I started with a couple of samples from a JIT Migration that I found. I had some difficulty navigating all the components with the social media logins, etc that I then reverted back to the "Local Accounts" sample found in the custom policy starterpack. I got the basic steps to work with no modification. I then added the technical profiles for the REST calls to the extensions file. I used the extension from one of the JIT migration samples and at least got the uploads to work. I am able to present a login prompt.
These are the scenarios and responses I see: 1) A user that I know is in B2C returns an error of "Unable to validate the information provided." 2) A user that I know is in the external IDP but not in B2C returns "We can't seem to find your account". 3) If I try a completely made up account that exists in neither, I see "The claims exchange 'REST-UserMigration-LocalAccount-SignIn' specified in step '1' returned HTTP error response with Code 'BadRequest' and Reason ''. "
So the question/struggle is how do I best sort out what is failing in each step. I have added app insights to the environment. I do see the traces in VS Code. But what should I look for? Here is the short responses ("Exceptions") for each of the errors listed above:
Scenario 1: The claim type "signInNames.emailAddress", designated as the identifier claim type, could not be found in the claims collection for the claims principal in tenant id "B2C_1A_JITMigration_signup_signin"
Scenario 2: A user with the specified credential could not be found.
Scenario 3: ErrorCodes: AADB2C90075
Rather than post of the code, here is the link to what I copied: https://github.com/azure-ad-b2c/user-migration/blob/master/jit-migration-v2/policy/TrustFrameworkExtensions.xml I can post up my exact code but basically I changed the tenant and the REST call. The Technical profile for the REST call snippet is:
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="username"/>
<InputClaim ClaimTypeReferenceId="password" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="needToMigrate" />
<OutputClaim ClaimTypeReferenceId="email" />
<OutputClaim ClaimTypeReferenceId="newPassword" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
The input claims are fine but I am not sure how to modify the output claims. The REST API returns a single value of an authentication token which I don't need but is an indication that the authentication succeeded. It returns an error if the authentication fails. Basically an HTTP 200 is good, an HTTP 400 means the user doesn't exist. The goal is to use that API call as a binary indicator to either migrate or not migrate the user. Perhaps I cannot use the API in that way.
My hope is to solve each scenario step by step. Figure out why the scenario 1 doesn't work although the credential are correct. Then figure out why scenario 2 is correctly identifying that the user isn't found but wasn't automatically migrated. Finally, to figure out how to manage the 400 error returned by the API when the user doesn't exist in the external IDP.
I might need to tweak the user journeys or orchestration steps? Taking baby steps here.
Thanks

Is there something special about B2C's givenName and surname claims? Can't read them from the OIDC ClaimsProvider

My OIDC claims provider (Okta) provides the given_name and family_name values to my OIDC test harness app.
My Azure B2C claims provider uses the same scopes as my test app, but I can't get the given_name and family_name to be added to the B2C claim,
Scopes used when calling Okta CP:
<Item Key="scope">openid profile email</Item>
OutputClaims mapping in Okta CP:
<OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" DefaultValue="default value from input ClaimsProvider: email"/>
<OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name" DefaultValue="default value from input ClaimsProvider: givenName"/>
<OutputClaim ClaimTypeReferenceId="surname" PartnerClaimType="family_name" DefaultValue="default value from input ClaimsProvider: surname"/>
This configuration doesn't seem to get the values for these two claims. It does get the "name" and "email" values, so I feel confident the scopes are being honored. Using DefaultValues to debug, I see this in the Azure SAML test app.
SAML Login Success
Attribute Value
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress JoeBlow#xyz.com
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name Joe Blow
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname default value from input ClaimsProvider: givenName
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname default value from input ClaimsProvider: surname
http://schemas.microsoft.com/identity/claims/userprincipalname JoeBlow#xyz.com
Might be to late for the OP, but we just ran into this as well. It took us quite a while to find a solution.
Problem was not (in our case) the Azure AD B2C policy.
But instead the issue was with the Azure AD app registration (used for Ms + AAD accounts).
family_name+ given_name are optional claims
For those claims to be returned two things need to happen:
profile scope must be requested
configure the Azure AD app registration to return these 2 optional claims
This was the step we were missing
Here is the link to the doc explaining how to ensure an Azure AD app registration returns optional claims (its straight forward and only took 1min todo):
https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-optional-claims?WT.mc_id=AZ-MVP-5003445#configuring-optional-claims

How can I see data for users created by a custom policy?

I have Signup and Sinin custom policy that allow users to signup or signin. It works well.
The policy uses the following claims:
<OutputClaim ClaimTypeReferenceId="extension_firstName" />
<OutputClaim ClaimTypeReferenceId="extension_lastName" />
<OutputClaim ClaimTypeReferenceId="extension_organizationName" />
<OutputClaim ClaimTypeReferenceId="extension_contactPhoneNumber" />
<OutputClaim ClaimTypeReferenceId="extension_selectRole" />
<OutputClaim ClaimTypeReferenceId="extension_terms" />
When I goto B2C portal, find the user and look the user details, none of the extension_* claims (attributes or properties) appear there.
Then I use Microsoft Graph, issue this query:
https://graph.microsoft.com/v1.0/users/[user Object ID]
I get minimal data for the user. None of the extension_* calim data appears there.
How can I see all the extension_* claim data with a give user created by custom policy?
The Azure portal doesn't display the extension properties for users.
For the Microsoft Graph query, you must add the $select parameter in order to include the extension properties, such as:
GET https://graph.microsoft.com/v1.0/users/{id}?$select=extension_{b2cExtensionsAppClientId}_firstName,extension_{b2cExtensionsAppClientId}_lastName,...
where {b2cExtensionsAppClientId} is the application (client) identifier (without hyphens) for [the b2c-extensions-app application}(https://learn.microsoft.com/en-us/azure/active-directory-b2c/extensions-app) that is registered in your Azure AD B2C tenant such as:
extension_b2ba52d57b074a5e8fa2d8b35f5a1347_firstName

Azure AD B2C Add Claims to id_token in custom policy

I have created custom policies for social and local accounts based on the example from the Active Directory B2C custom policy starter pack for social and local accounts. I have enabled the login with Microsoft and Google and tested that both work, I have also enabled logging in with a local account.
When I log in with google I get the following claims
exp,nbf,ver,iss,sub,aud,acr,nonce,iat,auth_time,email,given_name,family_name,name,idp,at_hash
When I log into a custom Azure AD tenant the set of claims is missing 'email', but the email is listed in the 'name' claim
exp,nbf,ver,iss,sub,aud,acr,nonce,iat,auth_time,given_name,family_name, name,idp,at_hash
When I log in as a local account the set of claims is missing 'email' and there is no email listed in any of the fields.
exp,nbf,ver,iss,sub,aud,acr,nonce,iat,auth_time,given_name, family_name,name,at_hash
Finally, when I look at the list of users in the B2C admin, these are all different user entries...even though the email address is the same. So I have 2 questions,
How do I get a consistent set of claims in the id_token
How do I link all these accounts together at registration time (Same UPN)
I believe these may be related, which is why I am asking them together.
You probably want to see the policies, but I assure you they are exactly the same as the policies in the starter pack, all I've done is change the tenant names and added google and azure in the trust framework extensions file.
For the Azure AD email claim, add the following <OutputClaim /> to the Azure AD OpenID Connect technical profile:
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="unique_name" />
For the local account email claim, add the following <OutputClaim /> to the AAD-UserReadUsingObjectId technical profile:
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" />

Resources