0
votes

I have a some custom policies in B2C that are working and I'm not trying to get the Reset Password to work. One of the issues I have is that I call a Restful API to check if the email address provided is a local user or if we are signing them in from a Microsoft AAD. This works fine, so the user is signed in via a Microsoft Organisation Identity if they are an SSO user, if not they are signed in locally via the B2C.

My issue is that I'm trying to do something similar with reset password. I use the following Technical Profile to get the email address

<TechnicalProfile Id="SelfAsserted-Signin-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="DisplayName">Signin To Tax Systems</Item>
        <Item Key="setting.operatingMode">Email</Item>
        <Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>
    </Metadata>
    <IncludeInSso>false</IncludeInSso>
    <InputClaims>
        <InputClaim ClaimTypeReferenceId="signInName" />
    </InputClaims>
    <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="signInName" Required="true" />
    </OutputClaims>
    <UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>

Once the email address is obtained, we call a rest api to check the email address. This check tells us if the user is a federated user, or a local user. If they are a federated user I want to error as they can't reset their password via B2C.

If they are a local user then we want to do the reset password. This is done via the following Technical Profile. The problem is that they have to enter their email address again, I want the email address to be pre-populated with the email address obtained previously.

<TechnicalProfile Id="LocalAccountDiscoveryUsingEmailAddress">
  <DisplayName>Reset password using email address</DisplayName>
  <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  <Metadata>
    <Item Key="IpAddressClaimReferenceId">IpAddress</Item>
    <Item Key="ContentDefinitionReferenceId">api.localaccountpasswordreset</Item>
    <Item Key="UserMessageIfClaimsTransformationBooleanValueIsNotEqual">Your account has been locked. Contact your support person to unlock it, then try again.</Item>
  </Metadata>
  <CryptographicKeys>
    <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
  </CryptographicKeys>
  <IncludeInSso>false</IncludeInSso>
  <InputClaims>
      <InputClaim ClaimTypeReferenceId="signInName" />
  </InputClaims>
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />
    <OutputClaim ClaimTypeReferenceId="objectId" />
    <OutputClaim ClaimTypeReferenceId="userPrincipalName" />
    <OutputClaim ClaimTypeReferenceId="authenticationSource" />

  </OutputClaims>
  <ValidationTechnicalProfiles>
    <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingEmailAddress" />
  </ValidationTechnicalProfiles>
</TechnicalProfile>

Any idea how I can do this? I can't seem to find much detail about api.localaccountpasswordreset in regards to the metadata etc.

3
Taking information from @alfredo-r-msft-identity, I have taken this a step further and managed to get the email address prepopulated. However, it does not then verify the email addressTanzy

3 Answers

0
votes

You need to add these:

<Metadata>
            <Item Key="IncludeClaimResolvingInClaimsHandling">True</Item>
</Metadata>
<InputClaims>
            <InputClaim ClaimTypeReferenceId="email" DefaultValue="{OAUTH-KV:email}" AlwaysUseDefaultValue="true"></InputClaim>
</InputClaims>

So you can set the email calling the policy authorize URL appending an email query param (&[email protected])

0
votes

Since you obtained the email in the claim signInName at step 1, in step 2, you can pre-populate it as follows:

  <InputClaims>
      <InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="email"/>
  </InputClaims>

For the Email Verification buttons to appear, you must have the email claim as readOnly. Otherwise, AAD B2C will pre-populate the field assuming its already validated, and only show the Verify button if the email address is changed.

So a true solution would be:

    <ClaimsSchema>
      <!-- Sample: Read only email address to present to the user-->
      <ClaimType Id="readonlyEmail">
        <DisplayName>E-mail Address</DisplayName>
        <DataType>string</DataType>
        <UserInputType>Readonly</UserInputType>
      </ClaimType>
    </ClaimsSchema>
<TechnicalProfile Id="LocalAccountDiscoveryUsingEmailAddress">
  <DisplayName>Reset password using email address</DisplayName>
  <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  <Metadata>
    <Item Key="IpAddressClaimReferenceId">IpAddress</Item>
    <Item Key="ContentDefinitionReferenceId">api.localaccountpasswordreset</Item>
    <Item Key="UserMessageIfClaimsTransformationBooleanValueIsNotEqual">Your account has been locked. Contact your support person to unlock it, then try again.</Item>
  </Metadata>
  <CryptographicKeys>
    <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
  </CryptographicKeys>
  <IncludeInSso>false</IncludeInSso>
  <InputClaims>
      <InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="readonlyEmail"/>
  </InputClaims>
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="readonlyEmail" PartnerClaimType="Verified.Email" Required="true" />
    <OutputClaim ClaimTypeReferenceId="objectId" />
    <OutputClaim ClaimTypeReferenceId="userPrincipalName" />
    <OutputClaim ClaimTypeReferenceId="authenticationSource" />
  </OutputClaims>
  <ValidationTechnicalProfiles>
    <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingEmailAddress" />
  </ValidationTechnicalProfiles>
</TechnicalProfile>

You'd need to modify AAD-UserReadUsingEmailAddress such that its input claim is

<InputClaims>
  <InputClaim ClaimTypeReferenceId="readonlyEmail" PartnerClaimType="signInNames.emailAddress" Required="true" />
</InputClaims>

I would copy the whole technical profile and give it a new Id with above modification.

And any further references to email in the joruney should be replaced with readOnlyEmail in the same way.

0
votes

Did you get this working? I had a similar setup for one of my customers and fixed this issue by adding 2 validation profiles (https://docs.microsoft.com/en-us/azure/active-directory-b2c/validation-technical-profile) and changed the input claim:

  1. Call the REST API as a Validation Technical Profile (https://docs.microsoft.com/en-us/azure/active-directory-b2c/restful-technical-profile) in your SelfAsserted-Signin-Email Technical Profile to check the Email address, display an error on the screen if the email address is not federated;
  2. Call a ClaimsTransformation Validation Technical Profile (https://docs.microsoft.com/en-us/azure/active-directory-b2c/claims-transformation-technical-profile) that references a ClaimsTransformation to copy signInName to email (https://docs.microsoft.com/en-us/azure/active-directory-b2c/general-transformations#copyclaim);
  3. Change the Input Claim in your LocalAccountDiscoveryUsingEmailAddress Technical Profile to email.

This provides a clean UI - an error is displayed on the first form if the user is federated and the second screen pre-populates the email field using the default claim.