Ayush Singh
Ayush Singh

Reputation: 51

Persisting strongAuthenticationEmailAddress, resets strongAuthenticationPhoneNumber and vice-versa in Azure B2C custom policy

I was able to edit the ‘strongAuthenticationEmailAddress’ by modifying the 'ProfileEditWithUsername' user journey defined in the extension file of the policy(https://github.com/azure-ad-b2c/samples/tree/master/policies/username-signup-or-signin). I persisted the strongAuthenticationEmailAddress in the 'AAD-UserWriteProfileUsingObjectId' technical profile which was used by the above user journey as a validation profile in Orchestration Step 4.

However, I noticed that if I run the policy to change the strongAuthenticationEmailAddress, the email is changed successfully but the strongAuthenticationPhoneNumber & Alternate phone(used for authentication) is being set to blank. Similarly I implemented the edit-MFA phone number policy (https://github.com/azure-ad-b2c/samples/tree/master/policies/edit-mfa-phone-number), and using this I am able to edit the strongAuthenticationPhoneNumber, but it sets the strongAuthenticationEmailAddress to blank.

<UserJourney Id="ProfileEditWithUsername">
    <OrchestrationSteps>
        <OrchestrationStep Order="1" Type="ClaimsProviderSelection" ContentDefinitionReferenceId="api.idpselections">
            <ClaimsProviderSelections>
                <ClaimsProviderSelection TargetClaimsExchangeId="LocalAccountSigninUsernameExchange" />
            </ClaimsProviderSelections>
        </OrchestrationStep>
        <OrchestrationStep Order="2" Type="ClaimsExchange">
            <ClaimsExchanges>
                <ClaimsExchange Id="LocalAccountSigninUsernameExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Username" />
            </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="3" Type="ClaimsExchange">
            <ClaimsExchanges>
                <ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
            </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="4" Type="ClaimsExchange">
            <ClaimsExchanges>
                <ClaimsExchange Id="B2CUserProfileUpdateExchange" TechnicalProfileReferenceId="SelfAsserted-ProfileUpdate" />
            </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="5" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
    </OrchestrationSteps>
    <ClientDefinition ReferenceId="DefaultWeb" />
</UserJourney>

--------------------------------------------------
<TechnicalProfile Id="AAD-UserReadUsingObjectId">
    <Metadata>
        <Item Key="Operation">Read</Item>
        <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
    </Metadata>
    <IncludeInSso>false</IncludeInSso>
    <InputClaims>
        <InputClaim ClaimTypeReferenceId="objectId" Required="true" />
    </InputClaims>
    <OutputClaims>
        <!-- Required claims -->
        <OutputClaim ClaimTypeReferenceId="strongAuthenticationPhoneNumber" />
        <OutputClaim ClaimTypeReferenceId="strongAuthenticationEmailAddress" />

        <!-- Optional claims -->
        <OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
        <OutputClaim ClaimTypeReferenceId="displayName" />
        <OutputClaim ClaimTypeReferenceId="otherMails" />
        <OutputClaim ClaimTypeReferenceId="givenName" />
        <OutputClaim ClaimTypeReferenceId="surname" />

    </OutputClaims>
    <IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>
-------------------------------------------------
<TechnicalProfile Id="SelfAsserted-ProfileUpdate">
    <DisplayName>User ID signup</DisplayName>
    <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    <Metadata>
        <Item Key="ContentDefinitionReferenceId">api.selfasserted.profileupdate</Item>
    </Metadata>
    <IncludeInSso>false</IncludeInSso>
    <InputClaims>
        <InputClaim ClaimTypeReferenceId="alternativeSecurityId" />
        <InputClaim ClaimTypeReferenceId="userPrincipalName" />
        <!-- Optional claims. These claims are collected from the user and can be modified. Any claim added here should be updated in the
                 ValidationTechnicalProfile referenced below so it can be written to directory after being updateed by the user, i.e. AAD-UserWriteProfileUsingObjectId. -->
        <InputClaim ClaimTypeReferenceId="givenName" />
        <InputClaim ClaimTypeReferenceId="surname" />
        <InputClaim ClaimTypeReferenceId="strongAuthenticationEmailAddress" />


    </InputClaims>
    <OutputClaims>
        <!-- Required claims -->
        <OutputClaim ClaimTypeReferenceId="executed-SelfAsserted-Input" DefaultValue="true" />
        <!-- Optional claims. These claims are collected from the user and can be modified. Any claim added here should be updated in the
                 ValidationTechnicalProfile referenced below so it can be written to directory after being updateed by the user, i.e. AAD-UserWriteProfileUsingObjectId. -->
        <OutputClaim ClaimTypeReferenceId="givenName" />
        <OutputClaim ClaimTypeReferenceId="surname" />
        <OutputClaim ClaimTypeReferenceId="strongAuthenticationEmailAddress" />


    </OutputClaims>
    <ValidationTechnicalProfiles>
        <ValidationTechnicalProfile ReferenceId="AAD-UserWriteProfileUsingObjectId" />
    </ValidationTechnicalProfiles>
</TechnicalProfile>
---------------------------------------------------------------------------
<TechnicalProfile Id="AAD-UserWriteProfileUsingObjectId">
    <Metadata>
        <Item Key="Operation">Write</Item>
        <Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">false</Item>
        <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
    </Metadata>
    <IncludeInSso>false</IncludeInSso>
    <InputClaims>
        <InputClaim ClaimTypeReferenceId="objectId" Required="true" />
    </InputClaims>
    <PersistedClaims>
        <!-- Required claims -->
        <PersistedClaim ClaimTypeReferenceId="objectId" />

        <!-- Optional claims -->
        <PersistedClaim ClaimTypeReferenceId="givenName" />
        <PersistedClaim ClaimTypeReferenceId="surname" />
        <PersistedClaim ClaimTypeReferenceId="strongAuthenticationEmailAddress" />

    </PersistedClaims>
    <IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>

Upvotes: 1

Views: 778

Answers (1)

Justin Willoughby
Justin Willoughby

Reputation: 151

I remember going through the same frustrating problem.

If you persist one of the strongAuthentication fields within a TechnicalProfile, it will wipe out any of the other strongAuthentication fields unless you also persist those.

So wherever you are persisting one strongAuthentication field, persist them all instead. In your example, your technical profile "AAD-UserWriteProfileUsingObjectId" should look something like this:

<TechnicalProfile Id="AAD-UserWriteProfileUsingObjectId">
<Metadata>
    <Item Key="Operation">Write</Item>
    <Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">false</Item>
    <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
    <InputClaim ClaimTypeReferenceId="objectId" Required="true" />
</InputClaims>
<PersistedClaims>
    <!-- Required claims -->
    <PersistedClaim ClaimTypeReferenceId="objectId" />

    <!-- Optional claims -->
    <PersistedClaim ClaimTypeReferenceId="givenName" />
    <PersistedClaim ClaimTypeReferenceId="surname" />
    <PersistedClaim ClaimTypeReferenceId="strongAuthenticationEmailAddress" />
    
    <!-- *** NEW LINE *** -->
    <PersistedClaim ClaimTypeReferenceId="strongAuthenticationPhoneNumber" />
</PersistedClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />

Note the new line added in the PersistedClaims for strongAuthenticationPhoneNumber.

There is another place in the schema this occurs and it's with the signInNames collection. If you persist something like signInNames.username it will wipe out any other signInNames (like a signInNames.emailaddress) unless you also persist the signInNames.emailaddress, so just be aware of that too.

Upvotes: 2

Related Questions