Limiting Claims by App in Azure AD B2C - azure-ad-b2c

We have 3 different applications requiring different sets of extension claims.
Application A - Claim A1, Claim A2, Claim A3
Application B - Claim B1, Claim B2, Claim B3
We defined the six Claims in TrustFrameworkExtensions, updated the various TechnicalProfiles to take the input from user and as well write it to directory.
To support the needs of the individual applications, we created 2 RP files, one for each Application and defined the User Journey's specific to the Apps.
The 6 claims are showing up for both Apps, and we want to restrict by App the Claims.
Tried to copy everything from TrustFrameworkExtensions into RP file, the RP does not load and throws an error as follows
Unable to upload policy. Reason : Validation failed: 3 validation error(s) found in policy "B2C_1A_1182017SIGNUP_SIGNIN" of tenant "XXXXXXXXX.onmicrosoft.com".
A required Metadata item with key "ApplicationObjectId" was not found in the TechnicalProfile with id "AAD-UserWriteUsingAlternativeSecurityId" in policy "B2C_1A_1182017signup_signin" of tenant "XXXXXXXXX.onmicrosoft.com".
A required Metadata item with key "ApplicationObjectId" was not found in the TechnicalProfile with id "AAD-UserWriteUsingLogonEmail" in policy "B2C_1A_1182017signup_signin" of tenant "XXXXXXXXX.onmicrosoft.com".
A required Metadata item with key "ApplicationObjectId" was not found in the TechnicalProfile with id "AAD-UserWriteProfileUsingObjectId" in policy "B2C_1A_1182017signup_signin" of tenant "XXXXXXXXX.onmicrosoft.com".
Appreciate advise and guidance to support multiple Apps with different claims.

To use extension attributes in your custom policy you need to add some configuration to your file involving the b2c-extensions-app that is automatically created and registered in the Portal for each B2C tenant.
In your case, you seem to be missing the ApplicationObjectID and possibly the ClientId of the b2c-extensions-app in the Metadata key section of your AAD-Common technical profile.
The Next Steps section of the Create Custom Attribute documentation describes how to perform this configuration.
https://learn.microsoft.com/en-us/azure/active-directory-b2c/custom-policy-custom-attributes#modify-your-custom-policy
Open the extensions file of your policy. For example, SocialAndLocalAccounts/TrustFrameworkExtensions.xml.
Find the ClaimsProviders element. Add a new ClaimsProvider to the ClaimsProviders element.
Replace ApplicationObjectId with the Object ID that you previously recorded. Then replace ClientId with the Application ID that you previously recorded in the below snippet.
<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"></Item>
<!--Insert b2c-extensions-app application ObjectId here, for example: 22222222-2222-2222-2222-222222222222-->
<Item Key="ApplicationObjectId"></Item>
</Metadata>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>

Use <RelyingParty><TechnicalProfile><OutputClaims> to control the claims returned.
<RelyingParty>
<DefaultUserJourney ReferenceId="SignInAppA" />
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="ClaimA1" />
</OutputClaims>
<SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>
</RelyingParty>
and
<RelyingParty>
<DefaultUserJourney ReferenceId="SignInAppB" />
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="ClaimB1" />
</OutputClaims>
<SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>
</RelyingParty>

Related

Azure B2c error 'Unable to validate the information provided.' when using custom attributes

I'm trying to add custom attributes to a custom policy. However it generates this error 'Unable to validate the information provided.'
I followed the documentation of the links below, I have already added application id b2c-extensions-app and object too.
https://learn.microsoft.com/pt-br/azure/active-directory-b2c/custom-policy-custom-attributes
https://learn.microsoft.com/pt-br/azure/active-directory-b2c/configure-user-input?pivots=b2c-custom-policy
Error log message "Error returned was 400/Request_BadRequest: The following extension properties are not available: extension_f41be....._tipoUsuario."
Part of the code in my TrustFrameworkExtensions file, where it writes and retrieves the information in AD:
<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="5bfd........"></Item>
<!--Insert b2c-extensions-app application ObjectId here, for example: 22222222-2222-2222-2222-222222222222-->
<Item Key="18bd6......."></Item>
</Metadata>
</TechnicalProfile>
<TechnicalProfile Id="AAD-UserWriteUsingLogonEmail">
<Metadata>
<Item Key="client_id">f41be......</Item>
<!--Insert b2c-extensions-app application ID here, for example: 11111111-1111-1111-1111-111111111111-->
</Metadata>
<PersistedClaims>
<PersistedClaim ClaimTypeReferenceId="extension_tipoUsuario"/>
</PersistedClaims>
</TechnicalProfile>
<!-- Write data during edit profile flow. -->
<TechnicalProfile Id="AAD-UserWriteProfileUsingObjectId">
<PersistedClaims>
<PersistedClaim ClaimTypeReferenceId="extension_tipoUsuario"/>
</PersistedClaims>
</TechnicalProfile>
<!-- Read data after user authenticates with a local account. -->
<TechnicalProfile Id="AAD-UserReadUsingEmailAddress">
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="extension_tipoUsuario" />
</OutputClaims>
</TechnicalProfile>
<!-- Read data after user authenticates with a federated account. -->
<TechnicalProfile Id="AAD-UserReadUsingObjectId">
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="extension_tipoUsuario" />
</OutputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
One of the common root causes to this problem is misconfiguration of client ID metadata of B2C Extension App.
Make sure the tutorial here is followed.

Get email (username) in Claims azure ad b2c signed In with AzureAd like a Social account

I am using starter pack of custom polices with the SocialAndLocalAccounts package to sign in with an Azure Active Directory account.
I customized the flows with custom attributes and it works well for me.
I need to receive the email used for the login (username = email).
In RelyingParty I have this OutputClaims
<OutputClaim ClaimTypeReferenceId = "signInName" />
<OutputClaim ClaimTypeReferenceId = "signInNames.emailAddress" PartnerClaimType = "email" />
<OutputClaim ClaimTypeReferenceId = "otherMails" />
When a user signs-in with a local b2c account, I get the email
in "signInName" and "email" claims,
but when a user signs-in with an AzureAd account , the claims are empty.
How can I get the email?
How must I write the custom policies (TrustFrameworkBase and TFExtensions) ?
Can you help me ?
When the Azure AD identity is signed-in with for the first time, you must map from the upn claim that is issued by Azure AD to the email claim that is used by Azure AD B2C, so that this email claim can be:
Written as the otherMails property in the user object to the Azure AD B2C directory.
Issued by Azure AD B2C in the ID token to the client application.
To map from the upn claim that is issued by Azure AD to the email claim that is used by Azure AD B2C, add a new <OutputClaim /> to the Azure AD authentication technical profile:
<ClaimsProvider>
<Domain>commonaad</Domain>
<DisplayName>Common AAD</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="Common-AAD">
<DisplayName>Multi-Tenant AAD</DisplayName>
<Protocol Name="OpenIdConnect" />
...
<OutputClaims>
...
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="upn" />
</OutputClaims>
...
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
The AAD-UserWriteUsingAlternativeSecurityId technical profile converts the email claim to the otherMails claim by invoking the CreateOtherMailsFromEmail claims transformation and then saves the otherMails claim to the user object.
To issue the email claim in the ID token to your client application, add a new <OutputClaim /> to the relying party technical profile:
<RelyingParty>
<DefaultUserJourney ReferenceId="SignUpOrSignIn" />
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect" />
...
<OutputClaims>
...
<OutputClaim ClaimTypeReferenceId="otherMails" PartnerClaimType="emails" />
</OutputClaims>
...
</TechnicalProfile>
</RelyingParty>

Differently-formatted issuerUserId when using Microsoft Account provider in Azure AD B2C

We're investigating a migration of our existing authentication system to Azure AD B2C. Our current system accepts both MSA and Google logins, and we use an in-house developed service based on IdentityServer, which stores the IDs from the third-party IdPs in Azure Table storage.
I've followed the instructions for setting up MSA as an ID provider and for migrating users with a social account, and have converted my existing MSA IDs to base64 when posting them as userIdentities to the AD Graph API (in line with the sample code from the second link above). But when I sign in with an MSA, instead of recognizing my account, it directs me to the sign-up page (as part of the Sign-in/Sign-up policy I have defined).
If I follow through with creating the user, and then inspect the newly created user with the /users/<new-user-id> endpoint in the Graph API, I get back a strange-looking issuerUserId when compared to what I have stored for my Microsoft users currently.
My existing users have ids that look something like 1234ab56789cde01, and the IDs being sent to me via B2C are formatted as something like AAAAAAAAAAAAAAAAAAAAAAbCdEF12GhIj_KlM34nOPQwhen base64 decoded. (Values altered to avoid any potential privacy issues.) The capital 'A's are always there at the beginning, and I get characters from the full range of alphanumeric values in the new format as compared to the original IDs that only have a range of hexadecimal characters.
I've managed to get the Google accounts working just fine. All that's necessary there is to convert them to base64 and they just work. But I'm struggling to figure out how to migrate the MSAs. Either I'm doing something wrong on the app registration side, or there's another step to generating the AAAAAAAA-prefixed IDs that I'm just missing. Any help is appreciated. Thanks!
The built-in identity provider for Microsoft Account maps from the sub (subject) claim for the Microsoft account to the issuerUserId property of the userIdentity object.
If you are wanting to migrate identities that are mapped from a different claim (such as the oid (object identifier) claim) of a Microsoft account, then you must use custom policies and then add a custom identity provider for Microsoft Account with the following modification:
<ClaimsProvider>
<Domain>live.com</Domain>
<DisplayName>Microsoft Account</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="MSA-OIDC">
<DisplayName>Microsoft Account</DisplayName>
<Protocol Name="OpenIdConnect" />
<Metadata>
<Item Key="ProviderName">https://login.live.com</Item>
<Item Key="METADATA">https://login.live.com/.well-known/openid-configuration</Item>
<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">0</Item>
<Item Key="client_id">Your Microsoft application client id</Item>
</Metadata>
<CryptographicKeys>
<Key Id="client_secret" StorageReferenceId="B2C_1A_MSASecret" />
</CryptographicKeys>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="live.com" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="socialIdpAuthentication" />
<!-- ORIGINAL: The following output claims maps from the "sub" claim to the "issuerUserId" property. -->
<!--<OutputClaim ClaimTypeReferenceId="socialIdpUserId" PartnerClaimType="sub" />-->
<!-- MODIFICATION: The following output claims maps from the "oid" claim to the "issuerUserId" property. -->
<OutputClaim ClaimTypeReferenceId="socialIdpUserId" PartnerClaimType="oid" />
<OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
<OutputClaim ClaimTypeReferenceId="email" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName" />
<OutputClaimsTransformation ReferenceId="CreateUserPrincipalName" />
<OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId" />
<OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromAlternativeSecurityId" />
</OutputClaimsTransformations>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-SocialLogin" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
For information about getting started with custom policies, see Azure Active Directory B2C: Get started with custom policies.

Reading Extension Claims in Azure AD B2C

I have 2 claims that I want to store in the Directory for my application to use. These are not available for the user to edit however is available for the application to read from the Token.
The BuiltIn policies are able to retrieve the claims however, I have not had any success with retrieving these claims using Custom Policies.
Reading through Next Steps of the article “Creating and using custom attributes in a custom profile edit policy” the claims will need to be added to the RP and TechnicalProfile to read from Directory. I accordingly updated the RP and as well the TP's that read from Directory such as
<TechnicalProfile Id="AAD-UserReadUsingAlternativeSecurityId">
<TechnicalProfile Id="AAD-UserReadUsingObjectId">
<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Email">
<TechnicalProfile Id="AAD-UserReadUsingEmailAddress">
Unable to figure out what might be missing to retreive the 2 extension claims.
Assuming you are reading the custom claims in the user journeys and writing them via the Azure AD Graph API, then you must:
1: Add the custom claims as <ClaimType />s to the base policy.
<ClaimType Id="extension_UserAttribute1">
<DisplayName>User Attribute 1</DisplayName>
<DataType>string</DataType>
</ClaimType>
<ClaimType Id="extension_UserAttribute2">
<DisplayName>User Attribute 2</DisplayName>
<DataType>string</DataType>
</ClaimType>
2: Add the application and object identifiers for the extensions app to the "AAD-Common" technical profile which is required to read the custom claims from the Azure AD B2C directory.
<TechnicalProfile Id="AAD-Common">
<DisplayName>Azure Active Directory</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AzureActiveDirectoryProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ApplicationObjectId">Insert the object identifier for the b2c-extensions-app application here</Item>
<Item Key="ClientId">Insert the application identifier for the b2c-extensions-app application here</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="TokenSigningKeyContainer" />
</CryptographicKeys>
...
</TechnicalProfile>
Note: If you are wanting to read the custom claims in both built-in policies and custom policies, then you must use the application and object identifiers for the built-in b2c-extensions-app application rather than a custom extensions app as suggested by the Azure Active Directory B2C: Creating and using custom attributes in a custom profile edit policy tutorial.
3: Add the custom claims as <OutputClaim />s to the following technical profiles:
"AAD-UserReadUsingObjectId" for local account sign-in and profile editing
"AAD-UserReadUsingAlternativeSecurityId" for a social account sign-in and profile editing
"LocalAccountDiscoveryUsingEmailAddress" and "AAD-UserReadUsingEmailAddress" for a local account password reset
<OutputClaims>
...
<OutputClaim ClaimTypeReferenceId="extension_UserAttribute1" />
<OutputClaim ClaimTypeReferenceId="extension_UserAttribute2" />
</OutputClaims>
4: Issue the custom claims as <OutputClaim />s in any relying party policies.
Thanks #ChrisPadget. For anybody still struggling. Make sure that the UserJourney Step that reads data from AD is actually available in your User Journey. In my case, I had to add:
<OrchestrationStep Order="2" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>

How can I map a property from an Azure AD login to a B2C identity?

Following this example https://learn.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-setup-aad-custom we have managed to federate an Azure AD directory ('AD') with an Azure AD B2C directory ('B2C'), so we can have social and self-asserted sign up to a public application, which our work users can also sign into with their normal work IDs. This works well and solves a complex scenario for us.
In the application which is secured with B2C, we need to show AD users content that is relevant to their work identity (specifically we need to filter products based on their work role), but this information is not available to us, since the process of signing up to the app generates a new B2C identity for the user (effectively a proxy for their AD identity).
What we need to do is to map the user's original AD identity onto the new B2C identity. Other properties of the AD user such as Given Name and Surname are already mapped, and that seems to take place here, in the ClaimsProvider element of our custom policy, via the PartnerClaimType property:
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="socialIdpUserId" PartnerClaimType="oid"/>
<OutputClaim ClaimTypeReferenceId="tenantId" PartnerClaimType="tid"/>
<OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name" />
<OutputClaim ClaimTypeReferenceId="surName" PartnerClaimType="family_name" />
<OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="contosoAuthentication" />
<OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="AzureADContoso" />
</OutputClaims>
Indeed, it even appears that the ID we're looking for might be mapped to a property (oid) - but when we later query the B2C graph for the user, this oid property is not returned.
So - how can we map the user's Object ID from the work AD directory onto a property on the new B2C identity that is created?
CREATED on 28 Nov 17
Currently, the object identifier for the Azure AD user (or any external user) is saved to the "alternativeSecurityId" attribute in the Azure AD B2C directory, but this built-in attribute can't be queried via the Azure AD Graph API.
You can, however, create a custom attribute and map the "oid" claim from the Azure AD identity provider to a custom claim that is associated with this custom attribute.
Creating a custom attribute and using this as a custom claim is described at Azure Active Directory B2C: Creating and using custom attributes in a custom profile edit policy.
For your specific scenario, you should:
1: Add a <ClaimType />, declaring the custom claim, to the base policy:
<ClaimType Id="extension_AzureADUserObjectId">
<DisplayName>Azure AD User Object ID</DisplayName>
<DataType>string</DataType>
</ClaimType>
2: Map the "oid" claim in the "SignInWithContoso" technical profile:
<OutputClaims>
...
<OutputClaim ClaimTypeReferenceId="extension_AzureADUserObjectId" PartnerClaimType="oid" />
</OutputClaims>
3: Add the application and object identifiers for the extensions app to the "AAD-Common" technical profile which is required to read and write the custom claim to the Azure AD B2C directory:
<TechnicalProfile Id="AAD-Common">
<DisplayName>Azure Active Directory</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AzureActiveDirectoryProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ApplicationObjectId">Insert the object identifier for the b2c-extensions-app application here</Item>
<Item Key="ClientId">Insert the application identifier for the b2c-extensions-app application here</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="TokenSigningKeyContainer" />
</CryptographicKeys>
...
</TechnicalProfile>
4: Write the custom claim in the "AAD-UserWriteUsingAlternativeSecurityId" technical profile:
<PersistedClaims>
...
<PersistedClaim ClaimTypeReferenceId="extension_AzureADUserObjectId" />
</PersistedClaims>
5: Read the custom claim in the "AAD-UserReadUsingAlternativeSecurityId" technical profile:
<OutputClaims>
...
<OutputClaim ClaimTypeReferenceId="extension_AzureADUserObjectId" />
</OutputClaims>
6: Issue the custom claim in any relying party policies or query it via the Azure AD Graph API.
UPDATED on 15 Feb 18
Since this announcement on 5 Feb 18, the external issuer (i.e., the Azure AD tenant) and the external user identifier (i.e., the object identifier of the Azure AD user) can be read from the "userIdentities" property of the user object in the Azure AD B2C directory, where the "issuerUserId" property contains the Base64-encoding of the external user identifier:
{
"userIdentities": [
{
"issuer": "contoso.com",
"issuerUserId": "Mjk2NzdlNTAtY2MwZS00MmU5LWJhNWMtZjFmMDdkZTUwMDhm"
}
]
}

Resources