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
326 stars 386 forks source link

How do I integrate multiple signin policies on one page? #116

Open zmsoft opened 2 years ago

zmsoft commented 2 years ago

Hello,

How do I integrate multiple signin policies on one page? SignIn policies : 1、Phone + password 2、Phone + verificationCode 3、WeChat

I tried to integrate the above three strategies into one UserJourney. Here is my policy

<UserJourneys>
    <UserJourney Id="AccountLinkSignUpOrSignIn">
      <OrchestrationSteps>
        <OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
          <ClaimsProviderSelections>
            <ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninPhoneExchange" />
        <ClaimsProviderSelection TargetClaimsExchangeId="PhoneCodeExchange" />
            <ClaimsProviderSelection TargetClaimsExchangeId="WechatExchange"/>
          </ClaimsProviderSelections>
          <ClaimsExchanges>
            <ClaimsExchange Id="LocalAccountSigninPhoneExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Phone" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <!-- Check if the user has selected to sign in using one of the social providers -->
        <OrchestrationStep Order="2" Type="ClaimsExchange">
          <Preconditions>
            <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
              <Value>objectId</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="SignUpWithLogonPhoneExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonPhone" />
        <ClaimsExchange Id="PhoneCodeExchange" TechnicalProfileReferenceId="LocalAccountSignInWithPhoneCode" />
        <ClaimsExchange Id="WechatExchange" TechnicalProfileReferenceId="WeChat-OAuth2"/>
          </ClaimsExchanges>
        </OrchestrationStep>
        <!-- For social IDP authentication, attempt to find the user account in the directory. -->
        <OrchestrationStep Order="3" Type="ClaimsExchange">
          <Preconditions>
            <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
              <Value>authenticationSource</Value>
              <Value>localAccountAuthentication</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="AADUserReadUsingUserIdentity" TechnicalProfileReferenceId="AAD-UserReadUsingUserIdentity-NoError" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <!-- Show self-asserted page only if the directory does not have the user account already (i.e. we do not have an objectId). 
          This can only happen when authentication happened using a social IDP. If local account was created or authentication done
          using ESTS in step 2, then an user account must exist in the directory by this time. -->
        <OrchestrationStep Order="4" Type="ClaimsExchange">
          <Preconditions>
            <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
              <Value>objectId</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="SelfAsserted-Social" TechnicalProfileReferenceId="SelfAsserted-Social-v2" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <!-- This step reads any user attributes that we may not have received when authenticating using ESTS so they can be sent 
          in the token. -->
        <OrchestrationStep Order="5" Type="ClaimsExchange">
          <Preconditions>
            <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
              <Value>authenticationSource</Value>
              <Value>socialIdpAuthentication</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="6" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
      </OrchestrationSteps>
      <ClientDefinition ReferenceId="DefaultWeb" />
    </UserJourney>
  </UserJourneys>
  <RelyingParty>
    <DefaultUserJourney ReferenceId="AccountLinkSignUpOrSignIn" />
    <TechnicalProfile Id="PolicyProfile">
      <DisplayName>PolicyProfile</DisplayName>
      <Protocol Name="OpenIdConnect" />
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" />
        <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="oid" />
        <OutputClaim ClaimTypeReferenceId="displayName" />
        <OutputClaim ClaimTypeReferenceId="signInNames.phoneNumber" PartnerClaimType="phone_number" />
        <!-- add deparment -->
        <OutputClaim ClaimTypeReferenceId="jobTitle" />
        <OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email" />
        <OutputClaim ClaimTypeReferenceId="identityProvider" />
        <OutputClaim ClaimTypeReferenceId="tenantId" AlwaysUseDefaultValue="true" DefaultValue="{Policy:TenantObjectId}" />
      </OutputClaims>
      <SubjectNamingInfo ClaimType="sub" />
    </TechnicalProfile>
  </RelyingParty>

<!-- verification code  technicalProfile-->
<ClaimsProvider>
      <DisplayName>Local Account Sign Up With Phone</DisplayName>
      <TechnicalProfiles>
    <!-- Sign in with phone verification code -->
    <TechnicalProfile Id="LocalAccountSignInWithPhoneCode">
      <DisplayName>VerificationCode</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.selfasserted</Item>
            <Item Key="language.button_continue">continue</Item>
          </Metadata>
      <CryptographicKeys>
            <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
          </CryptographicKeys>
      <DisplayClaims>
        <!--<DisplayClaim ClaimTypeReferenceId="phone" Required="true" />
        <DisplayClaim ClaimTypeReferenceId="verificationCode" Required="true" />-->
            <DisplayClaim DisplayControlReferenceId="phoneControl"/>
            <DisplayClaim ClaimTypeReferenceId="extension_termsOfUseConsentChoice" Required="true" />
          </DisplayClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="objectId" />
            <OutputClaim ClaimTypeReferenceId="phone" PartnerClaimType="Verified.Phone" Required="true" />
            <OutputClaim ClaimTypeReferenceId="executed-SelfAsserted-Input" DefaultValue="true" />
            <!-- <OutputClaim ClaimTypeReferenceId="authenticationSource" /> -->
            <!-- <OutputClaim ClaimTypeReferenceId="extension_termsOfUseConsentChoice" Required="true" /> -->
            <!-- <OutputClaim ClaimTypeReferenceId="newUser" /> -->
            <!-- Optional claims, to be collected from the user -->
           <!-- <OutputClaim ClaimTypeReferenceId="displayName" /> -->
          </OutputClaims>
          <ValidationTechnicalProfiles>
            <ValidationTechnicalProfile ReferenceId="AzureMfa-VerifySms"></ValidationTechnicalProfile>
            <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingUserIdentity" />
          </ValidationTechnicalProfiles>
      <UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
    </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>

<!-- wechat  technicalProfile-->
<ClaimsProvider>
      <Domain>wechat.com</Domain>
      <DisplayName>WeChat (Preview)</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="WeChat-OAuth2">
          <DisplayName>WeChat</DisplayName>
          <Protocol Name="OAuth2" />
          <Metadata>
            <Item Key="ProviderName">wechat</Item>
            <Item Key="authorization_endpoint">https://open.weixin.qq.com/connect/qrconnect</Item>
            <Item Key="AccessTokenEndpoint">https://api.weixin.qq.com/sns/oauth2/access_token</Item>
            <Item Key="ClaimsEndpoint">https://api.weixin.qq.com/sns/userinfo</Item>
            <Item Key="scope">snsapi_login</Item>
            <Item Key="HttpBinding">GET</Item>
            <Item Key="AccessTokenResponseFormat">json</Item>
            <Item Key="ClientIdParamName">appid</Item>
            <Item Key="ClientSecretParamName">secret</Item>
            <Item Key="ExtraParamsInAccessTokenEndpointResponse">openid</Item>
            <Item Key="ExtraParamsInClaimsEndpointRequest">openid</Item>
            <Item Key="ResponseErrorCodeParamName">errcode</Item>
            <Item Key="external_user_identity_claim_id">unionid</Item>
            <Item Key="client_id">wxxxxxxxxxxxxxxxxxx</Item>
          </Metadata>
          <CryptographicKeys>
            <Key Id="client_secret" StorageReferenceId="B2C_1A_WeChatSecret" />
          </CryptographicKeys>
          <OutputClaims>
        <!-- The unionid claim is the user id in WeChat claims response, this value will be same in all applications of the same wechat developer account.-->
            <OutputClaim ClaimTypeReferenceId="socialIdpUserId" PartnerClaimType="unionid" />
            <OutputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="unionid" />
            <OutputClaim ClaimTypeReferenceId="extension_wuid" PartnerClaimType="unionid" />
            <OutputClaim ClaimTypeReferenceId="extension_woid" PartnerClaimType="openid" />
            <OutputClaim ClaimTypeReferenceId="extension_waid" DefaultValue="wxxxxxxxxxxxxxx" AlwaysUseDefaultValue="true" />
            <OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="nickname" />
            <OutputClaim ClaimTypeReferenceId="extension_headimgurl" PartnerClaimType="headimgurl" />
            <OutputClaim ClaimTypeReferenceId="city" PartnerClaimType="city" />
            <OutputClaim ClaimTypeReferenceId="extension_province" PartnerClaimType="province" />
            <OutputClaim ClaimTypeReferenceId="country" PartnerClaimType="country" />
            <OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="wechat.com" AlwaysUseDefaultValue="true" />
            <!-- The WeChat response doesn't contain UserName/EmailAddress.-->
            <OutputClaim ClaimTypeReferenceId="email" DefaultValue="" AlwaysUseDefaultValue="true" />
            <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="socialIdpAuthentication" AlwaysUseDefaultValue="true" />
          </OutputClaims>
          <OutputClaimsTransformations>
            <OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName" />
            <OutputClaimsTransformation ReferenceId="CreateUserPrincipalName" />
            <OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId" />
            <OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromAlternativeSecurityId" />
        <OutputClaimsTransformation ReferenceId="CreateUserIdentity" />
            <OutputClaimsTransformation ReferenceId="AppendUserIdentity" />
          </OutputClaimsTransformations>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-SocialLogin" />
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>

The phone number + password can be used to successfully signin and obtain the token. But, the mobile phone number and verification code cannot signin and obtain the token. After passing the verification code, the user does not sign in directly and redirect to changes the mobile phone number. And, after the wechat login is scanned successfully using the mobile phone and the login is confirmed in wechat, the page for resetting the password is redirected instead of directly logging in to obtain the token.

Could you give me some guidance? Many thanks.