4

I'm trying to build a B2C custom policy that makes use of Home-realm Discovery and Domain Hints.

We have 2 personas.

  1. Local User that authenticates in B2C with MFA
  2. External User that must to be redirected to their company's login page.

Use cases:

  1. User gets redirected to https://customdomain.b2clogin.com (no domain hint). User gets presented with a Login page asking for the email address and depending on type of user:

    • A local user to B2C authenticates in our B2C page (customdomain.b2clogin.com). First, user enters email address, then on Next user enters password and finally enters code (received on phone) for MFA.

    • An external user first enters their email then B2C must automatically redirect the user to the federated Identity provider to login.

  2. User gets redirected to https://customdomain.b2clogin.com/?domain_hint=xyz.com (with domain hint)

    • In this case we expect the user to be automatically redirected to xyz.com identity provider. The user should NOT see our login page for customdomain.b2clogin.com

What I have tried:

By taking the home-realm-discovery-modern sample (https://github.com/azure-ad-b2c/samples/tree/master/policies/home-realm-discovery-modern) I get HRD working properly (point 1)

By taking the SocialAndLocalAccountsWithMfa sample in the B2C starter pack I get the domain_hint redirection for free (point 2 above).

However, I'm failing at combining the two together to get both working (domain_hint and HRD).

Here is the User Journey:

    <UserJourneys>
       <UserJourney Id="SignIn">

        <OrchestrationSteps>

            <OrchestrationStep Order="1" Type="ClaimsExchange">
                <ClaimsExchanges>
                    <ClaimsExchange Id="ParseDomainHint" TechnicalProfileReferenceId="ParseDomainHint" />
                </ClaimsExchanges>
            </OrchestrationStep>

            <OrchestrationStep Order="2" Type="ClaimsExchange">
                <Preconditions>
                    <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
                        <Value>isKnownCustomer</Value>
                        <Value>True</Value>
                        <Action>SkipThisOrchestrationStep</Action>
                    </Precondition>
                </Preconditions>
                <ClaimsExchanges>
                    <ClaimsExchange Id="SigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-Signin-Email" />
                </ClaimsExchanges>
            </OrchestrationStep> 

            <OrchestrationStep Order="3" Type="ClaimsExchange">
                <Preconditions>
                    <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
                        <Value>isKnownCustomer</Value>
                        <Value>True</Value>
                        <Action>SkipThisOrchestrationStep</Action>
                    </Precondition>
                </Preconditions>
                <ClaimsExchanges>
                    <ClaimsExchange Id="ParseDomainHintLogic" TechnicalProfileReferenceId="HRDLogic" />
                </ClaimsExchanges>
            </OrchestrationStep>

            <!-- If the domain_hint did not match any known domain, then redirect to a default local account sign in-->
            <OrchestrationStep Order="4" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
                <Preconditions>
                    <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
                        <Value>isKnownCustomer</Value>
                        <Value>True</Value>
                        <Action>SkipThisOrchestrationStep</Action>
                    </Precondition>
                </Preconditions>
                <ClaimsProviderSelections>
                    <ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" />
                </ClaimsProviderSelections>
                <ClaimsExchanges>
                    <ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
                </ClaimsExchanges>
            </OrchestrationStep>

            <!-- dont run this step if the domain was known, or we have an objectid (local account sign in)-->
            <OrchestrationStep Order="5" Type="ClaimsExchange">
                <Preconditions>
                    <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
                        <Value>objectId</Value>
                        <Action>SkipThisOrchestrationStep</Action>
                    </Precondition>
                    <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
                        <Value>isKnownCustomer</Value>
                        <Value>true</Value>
                        <Action>SkipThisOrchestrationStep</Action>
                    </Precondition>
                </Preconditions>
                <ClaimsExchanges>
                    <ClaimsExchange Id="SignUpWithLogonEmailExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonEmail" />
                </ClaimsExchanges>
            </OrchestrationStep>

            <!-- If the domain matched any known domain, then this step will have a single IdP
                enabled due to each known IdP TP having an enablement flag via identityProviders claim -->
            <OrchestrationStep Order="6" Type="ClaimsProviderSelection" ContentDefinitionReferenceId="api.idpselections">
                <Preconditions>
                    <Precondition Type="ClaimEquals" ExecuteActionsIf="false">
                        <Value>isKnownCustomer</Value>
                        <Value>True</Value>
                        <Action>SkipThisOrchestrationStep</Action>
                    </Precondition>
                </Preconditions>
                <ClaimsProviderSelections>
                    <ClaimsProviderSelection TargetClaimsExchangeId="AADOIDC" />
                    <ClaimsProviderSelection TargetClaimsExchangeId="MSAOIDC" />
                </ClaimsProviderSelections>
            </OrchestrationStep>

            <OrchestrationStep Order="7" Type="ClaimsExchange">
                <Preconditions>
                    <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
                        <Value>objectId</Value>
                        <Action>SkipThisOrchestrationStep</Action>
                    </Precondition>
                    <Precondition Type="ClaimEquals" ExecuteActionsIf="false">
                        <Value>isKnownCustomer</Value>
                        <Value>true</Value>
                        <Action>SkipThisOrchestrationStep</Action>
                    </Precondition>
                </Preconditions>
                <ClaimsExchanges>
                    <ClaimsExchange Id="AADOIDC" TechnicalProfileReferenceId="AAD-OIDC" />
                    <ClaimsExchange Id="MSAOIDC" TechnicalProfileReferenceId="MSA-OIDC" />
                </ClaimsExchanges>
            </OrchestrationStep>

            <!-- For social IDP authentication, attempt to find the user account in the directory. -->
            <OrchestrationStep Order="8" Type="ClaimsExchange">
                <Preconditions>
                    <Precondition Type="ClaimEquals" ExecuteActionsIf="false">
                        <Value>isKnownCustomer</Value>
                        <Value>True</Value>
                        <Action>SkipThisOrchestrationStep</Action>
                    </Precondition>
                </Preconditions>
                <ClaimsExchanges>
                    <ClaimsExchange Id="AADUserReadUsingAlternativeSecurityId" TechnicalProfileReferenceId="AAD-UserReadUsingAlternativeSecurityId-NoError" />
                </ClaimsExchanges>
            </OrchestrationStep>

            <!-- Still dont have objectId (social idp user that doesnt yet exist) - write the account -->
            <OrchestrationStep Order="9" Type="ClaimsExchange">
                <Preconditions>
                    <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
                        <Value>objectId</Value>
                        <Action>SkipThisOrchestrationStep</Action>
                    </Precondition>
                </Preconditions>
                <ClaimsExchanges>
                    <ClaimsExchange Id="AADUserWrite" TechnicalProfileReferenceId="AAD-UserWriteUsingAlternativeSecurityId" />
                </ClaimsExchanges>
            </OrchestrationStep>

            <OrchestrationStep Order="10" Type="ClaimsExchange">
                <Preconditions>
                    <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
                        <Value>isKnownCustomer</Value>
                        <Value>True</Value>
                        <Action>SkipThisOrchestrationStep</Action>
                    </Precondition>
                </Preconditions>
                <ClaimsExchanges>
                    <ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
                </ClaimsExchanges>
            </OrchestrationStep>

            <OrchestrationStep Order="11" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
        </OrchestrationSteps>
        <ClientDefinition ReferenceId="DefaultWeb" />
    </UserJourney>
</UserJourneys>

What I'm I missing?

horus
  • 125
  • 1
  • 1
  • 7

1 Answers1

1

We managed to get Home Realm Discovery (HRD) and Domain Hints to work together in a custom policy. It's based on the HomeRealmDiscoveryModern sample.

Here is the solution/sample: https://github.com/AlbozDroid/b2c-hrd-domainhint-sample/blob/main/Alboz_susi_public.xml

The MFA part is not there but should be easy to add by following the LocalAndSocialWithMFA sample provided by Microsoft.

Alboz
  • 1,833
  • 20
  • 29
  • Can you pls help on below values, It seems I am using some wrong values. In my case I do have one AAD (xyz.com) and one B2C tenant(B2c.b2clogin.com). When user from xyz.com enter email address with xyz.com then it should redirect to AAD login page but its always redirecting to local signin page. – Jaydeep Suryawanshi Apr 01 '22 at 14:02