Azure-Samples / active-directory-b2c-custom-policy-starterpack

Azure AD B2C now allows uploading of a Custom Policy which allows full control and customization of the Identity Experience Framework
http://aka.ms/aadb2ccustom
MIT License
334 stars 394 forks source link

Validation error on BuildingBlocks for UserInfo according to Azure Docs #150

Open cburatto opened 1 year ago

cburatto commented 1 year ago

This issue might not be related to this repo, but to the Azure Docs -- my apologies in advance if so:

I am following these instructions to add a UserInfo endpoint to my OID custom policy https://learn.microsoft.com/en-us/azure/active-directory-b2c/userinfo-endpoint?pivots=b2c-custom-policy

Specifically

Add the Token Issuer technical profile Open the TrustFrameworkExtensions.xml file.

If it doesn't exist already, add a ClaimsProvider element and its child elements as the first element under the BuildingBlocks element.

Add the following claims provider:

<!-- 
<ClaimsProviders> -->
  <ClaimsProvider>
    <DisplayName>Token Issuer</DisplayName>
    <TechnicalProfiles>
      <TechnicalProfile Id="UserInfoIssuer">
        <DisplayName>JSON Issuer</DisplayName>
        <Protocol Name="None" />
        <OutputTokenFormat>JSON</OutputTokenFormat>
        <CryptographicKeys>
          <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
        </CryptographicKeys>
        <!-- The Below claims are what will be returned on the UserInfo Endpoint if in the Claims Bag-->
        <InputClaims>
          <InputClaim ClaimTypeReferenceId="objectId"/>
          <InputClaim ClaimTypeReferenceId="givenName"/>
          <InputClaim ClaimTypeReferenceId="surname"/>
          <InputClaim ClaimTypeReferenceId="displayName"/>
          <InputClaim ClaimTypeReferenceId="signInNames.emailAddress"/>
        </InputClaims>
      </TechnicalProfile>
      <TechnicalProfile Id="UserInfoAuthorization">
        <DisplayName>UserInfo authorization</DisplayName>
        <Protocol Name="None" />
        <InputTokenFormat>JWT</InputTokenFormat>
        <Metadata>
          <!-- Update the Issuer and Audience below -->
          <!-- Audience is optional, Issuer is required-->
          <Item Key="issuer">https://yourtenant.b2clogin.com/11111111-1111-1111-1111-111111111111/v2.0/</Item>
          <Item Key="audience">[ "22222222-2222-2222-2222-222222222222", "33333333-3333-3333-3333-333333333333" ]</Item>
          <Item Key="client_assertion_type">urn:ietf:params:oauth:client-assertion-type:jwt-bearer</Item>
        </Metadata>
        <CryptographicKeys>
          <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
        </CryptographicKeys>
        <OutputClaims>
          <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
          <OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email"/>
          <!-- Optional claims to read from the access token. -->
          <!-- <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name"/>
             <OutputClaim ClaimTypeReferenceId="surname" PartnerClaimType="family_name"/>
             <OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name"/> -->
        </OutputClaims>
      </TechnicalProfile>
    </TechnicalProfiles>
  </ClaimsProvider>
<!-- 
</ClaimsProviders> -->

My final BuildingBlocks looks like this:

 <BuildingBlocks>
    <ClaimsProviders>
      <ClaimsProvider>
        <DisplayName>Token Issuer</DisplayName>
        <TechnicalProfiles>
          <TechnicalProfile Id="UserInfoIssuer">
            <DisplayName>JSON Issuer</DisplayName>
            <Protocol Name="None" />
            <OutputTokenFormat>JSON</OutputTokenFormat>
            <CryptographicKeys>
              <Key Id="issuer_secret" StorageReferenceId="B2C_1A_XXXXX" />
            </CryptographicKeys>
            <!-- The Below claims are what will be returned on the UserInfo Endpoint if in the Claims Bag-->
            <InputClaims>
              <InputClaim ClaimTypeReferenceId="objectId"/>
              <InputClaim ClaimTypeReferenceId="givenName"/>
              <InputClaim ClaimTypeReferenceId="surname"/>
              <InputClaim ClaimTypeReferenceId="displayName"/>
              <InputClaim ClaimTypeReferenceId="signInNames.emailAddress"/>
            </InputClaims>
          </TechnicalProfile>
          <TechnicalProfile Id="UserInfoAuthorization">
            <DisplayName>UserInfo authorization</DisplayName>
            <Protocol Name="None" />
            <InputTokenFormat>JWT</InputTokenFormat>
            <Metadata>
              <!-- Update the Issuer and Audience below -->
              <!-- Audience is optional, Issuer is required-->
              <Item Key="issuer">https://xxxxx.b2clogin.com/xxx-xxx-xxx-xxx/v2.0/</Item>
  <!--            <Item Key="audience">[ "22222222-2222-2222-2222-222222222222", "33333333-3333-3333-3333-333333333333" ]</Item>-->
              <Item Key="client_assertion_type">urn:ietf:params:oauth:client-assertion-type:jwt-bearer</Item>
            </Metadata>
            <CryptographicKeys>
              <Key Id="issuer_secret" StorageReferenceId="B2C_1A_XXXXX" />
            </CryptographicKeys>
            <OutputClaims>
              <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
              <OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email"/>
              <!-- Optional claims to read from the access token. -->
              <!-- <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name"/>
                 <OutputClaim ClaimTypeReferenceId="surname" PartnerClaimType="family_name"/>
                 <OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name"/> -->
            </OutputClaims>
          </TechnicalProfile>
        </TechnicalProfiles>
      </ClaimsProvider>
    </ClaimsProviders>
  </BuildingBlocks>

I upload the Base and Localization XML without problems, but this one fails with error:

Validation failed: 1 validation error(s) found in policy "B2C_1A_TRUSTFRAMEWORKEXTENSIONS" of tenant "xxx.onmicrosoft.com".Schema validation error found at line 7 col 6 in policy "B2C_1A_TRUSTFRAMEWORKEXTENSIONS" of tenant "xxx.onmicrosoft.com": The element 'BuildingBlocks' in namespace 'http://schemas.microsoft.com/online/cpim/schemas/2013/06' has invalid child element 'ClaimsProviders' in namespace 'http://schemas.microsoft.com/online/cpim/schemas/2013/06'. List of possible elements expected: 'ClaimsSchema, Predicates, InputValidations, PredicateValidations, ClaimsTransformations, ClientDefinitions, ContentDefinitions, Localization, DisplayControls' in namespace 'http://schemas.microsoft.com/online/cpim/schemas/2013/06'.Schema validation error found at line 7 col 6 in policy "B2C_1A_TRUSTFRAMEWORKEXTENSIONS" of tenant "xxx.onmicrosoft.com": The element 'BuildingBlocks' in namespace 'http://schemas.microsoft.com/online/cpim/schemas/2013/06' has invalid child element 'ClaimsProviders' in namespace 'http://schemas.microsoft.com/online/cpim/schemas/2013/06'. List of possible elements expected: 'ClaimsSchema, Predicates, InputValidations, PredicateValidations, ClaimsTransformations, ClientDefinitions, ContentDefinitions, Localization, DisplayControls' in namespace 'http://schemas.microsoft.com/online/cpim/schemas/2013/06'.

This fails with ClaimsProviders or ClaimsProvider as child of BuildingBlocks.

So it seems the Azure Docs are outdated? If so, can anyone point me to the documentation and steps to add a UserInfo endpoint?

cburatto commented 1 year ago

Note:

If you move the ClaimsProvider from the BuildingBlocks element to the sibling ClaimsProviders element , the policy is uploaded without errors. You must make sure ClaimTypeReferenceId="signInNames.emailAddress" matches the ClaimType defined in the Base (in my case and probably others, this is email)

<InputClaim ClaimTypeReferenceId="signInNames.emailAddress"/>
...
<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email"/>

must be

<InputClaim ClaimTypeReferenceId="email"/>
...
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="email"/>

However, I am still not sure this change will work and create the UserInfo endpoint corrrectly. I will update this issue accordingly.