azure-ad-b2c-custom-policy

In a custom B2C policy, how to you strip leading zeros from a signInName during login?


I'm creating a custom policy that authenticates a user against their signInName, not their email. The signInName is a number between 4 and 10 digits.

I need to be able to strip any leading zeros that a person enters before their username before performing the authentication. So when a user enters 1234 or 0000001234, I need to authenticate them using only 1234.

How can I strip these zeros from the entered signInName before it is used to authenticate the user?

Here is the technical profile where authenticate occurs.

<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Username">
  <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="SignUpTarget">SignUpWithLogonEmailExchange</Item>
    <Item Key="setting.operatingMode">Username</Item>
    <Item Key="setting.showSignupLink">false</Item>
    <Item Key="setting.forgotPasswordLinkLocation">None</Item>
    <Item Key="ContentDefinitionReferenceId">api.ctas-localaccountsignin</Item>
    <Item Key="IncludeClaimResolvingInClaimsHandling">true</Item>
  </Metadata>
  <IncludeInSso>false</IncludeInSso>
  <InputClaims>
    <InputClaim ClaimTypeReferenceId="signInName" DefaultValue="{OIDC:LoginHint}" AlwaysUseDefaultValue="true" PartnerClaimType="signInName" />
  </InputClaims>
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="signInName" Required="true" />
    <OutputClaim ClaimTypeReferenceId="password" Required="true" />
    <OutputClaim ClaimTypeReferenceId="objectId" />
    <OutputClaim ClaimTypeReferenceId="authenticationSource" />
    <OutputClaim ClaimTypeReferenceId="userPrincipalName" Required="true" />
  </OutputClaims>
  <ValidationTechnicalProfiles>
    <ValidationTechnicalProfile ReferenceId="login-NonInteractive" />
  </ValidationTechnicalProfiles>
  <UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
<TechnicalProfile Id="login-NonInteractive">
  <Metadata>
    <Item Key="client_id">xxx</Item>
    <Item Key="IdTokenAudience">xxx</Item>
  </Metadata>
  <InputClaims>
    <InputClaim ClaimTypeReferenceId="client_id" DefaultValue="xxx" />
    <InputClaim ClaimTypeReferenceId="resource_id" PartnerClaimType="resource" DefaultValue="xxx" />
  </InputClaims>
</TechnicalProfile>

Solution

  • The only way I found to do this was to create a new claims transformation that utilizes SetClaimsIfRegexMatch with extract groups.

    The calling technical profile:

    <TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Username">
      <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="SignUpTarget">SignUpWithLogonEmailExchange</Item>
        <Item Key="setting.operatingMode">Username</Item>
        <Item Key="setting.showSignupLink">false</Item>
        <Item Key="setting.forgotPasswordLinkLocation">None</Item>
        <Item Key="ContentDefinitionReferenceId">api.xxx-localaccountsignin</Item>
        <Item Key="IncludeClaimResolvingInClaimsHandling">true</Item>
      </Metadata>
      <IncludeInSso>false</IncludeInSso>
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="signInName" DefaultValue="{OIDC:LoginHint}" AlwaysUseDefaultValue="true" PartnerClaimType="signInName" />
        <InputClaim ClaimTypeReferenceId="signInNameWithoutZeroes" />
        <InputClaim ClaimTypeReferenceId="resultValue" />
        <InputClaim ClaimTypeReferenceId="resultMatch" />
      </InputClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="signInName" Required="true" />
        <OutputClaim ClaimTypeReferenceId="password" Required="true" />
        <OutputClaim ClaimTypeReferenceId="objectId" />
        <OutputClaim ClaimTypeReferenceId="authenticationSource" />
        <!--Added Claims-->
        <OutputClaim ClaimTypeReferenceId="version" />
        <OutputClaim ClaimTypeReferenceId="signInNameWithoutZeroes" />
        <OutputClaim ClaimTypeReferenceId="resultValue" />
        <OutputClaim ClaimTypeReferenceId="resultMatch" />
      </OutputClaims>
      <ValidationTechnicalProfiles>
        <ValidationTechnicalProfile ReferenceId="ExperimentalValidation-StripLeadingZeros" />
        <ValidationTechnicalProfile ReferenceId="login-NonInteractive" />
      </ValidationTechnicalProfiles>
      <UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
    </TechnicalProfile>
    

    Other profiles and transformation:

    <TechnicalProfile Id="ExperimentalValidation-StripLeadingZeros">
      <DisplayName>Strip zeroes from signin name</DisplayName>
      <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="signInNameWithoutZeroes" />
      </OutputClaims>
      <OutputClaimsTransformations>
        <OutputClaimsTransformation ReferenceId="StripLeadingZeros" />
      </OutputClaimsTransformations>
    </TechnicalProfile>
    
    <ClaimsTransformation Id="StripLeadingZeros" TransformationMethod="SetClaimsIfRegexMatch">
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="signInName" TransformationClaimType="claimToMatch"/>
      </InputClaims>
      <InputParameters>
        <InputParameter Id="matchTo" DataType="string" Value="^0*(?&lt;signInNameWithoutZeroes&gt;.+)$" />
        <InputParameter Id="outputClaimIfMatched" DataType="string" Value="You entered a femasid with leading zeroes" />
        <InputParameter Id="extractGroups" DataType="boolean" Value="true" />
      </InputParameters>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="resultValue" TransformationClaimType="outputClaim" />
        <OutputClaim ClaimTypeReferenceId="resultMatch" TransformationClaimType="regexCompareResultClaim" />
        <OutputClaim ClaimTypeReferenceId="signInNameWithoutZeroes" />
      </OutputClaims>
    </ClaimsTransformation>