Azure Active Directory B2C でリソース所有者パスワード資格情報フローを設定する

"開始する前に"、[ポリシーの種類の選択] セレクターを使用して、設定するポリシーの種類を選択します。 Azure Active Directory B2C には、ユーザーがアプリケーションを操作する方法を定義する 2 つの方法 (定義済みのユーザー フローを使用する、または完全に構成可能なカスタム ポリシーを使用する) があります。 この記事で必要な手順は、方法ごとに異なります。

Azure Active Directory B2C (Azure AD B2C) では、リソース所有者パスワード資格情報 (ROPC) フローが OAuth の標準的な認証フローです。 このフローでは、アプリケーション (証明書利用者とも呼ばれます) によって有効な資格情報がトークンと交換されます。 資格情報には、ユーザー ID とパスワードが含まれます。 返されるトークンは、ID トークン、アクセス トークン、および更新トークンです。

ROPC フローの説明

Azure Active Directory B2C (Azure AD B2C) では、次のオプションがサポートされています。

  • ネイティブ クライアント:認証時のユーザー操作は、ユーザー側のデバイスでコードが実行されているときに発生します。 デバイスは、Android や iOS などのネイティブ オペレーティング システムで実行されているモバイル アプリケーションである可能性があります。
  • パブリック クライアント フロー:アプリケーションによって収集されたユーザーの資格情報のみが API 呼び出しで送信されます。 アプリケーションの資格情報は送信されません。
  • 新しい要求の追加:新しい要求を追加するために、ID トークンの内容を変更することができます。

次のフローはサポートされていません。

  • サーバー対サーバー:ID 保護システムは、対話の一環として、呼び出し元 (ネイティブ クライアント) から収集された信頼できる IP アドレスを必要とします。 サーバー側の API 呼び出しでは、サーバーの IP アドレスのみが使用されます。 失敗した認証の動的しきい値を超えた場合、ID 保護システムによって、繰り返される IP アドレスが攻撃者として特定される可能性があります。
  • 機密性の高いクライアント フロー:アプリケーション クライアント ID は検証されますが、アプリケーション シークレットは検証されません。

ROPC フローを使用する場合は、次の点を考慮してください。

  • ユーザーの操作が必要な認証フローが中断されている場合、ROPC は動作しません。 これは、パスワードの有効期限が切れたり変更が必要な場合、多要素認証が必要な場合、サインイン時に詳細情報を収集する必要がある場合 (ユーザーの同意など) などです。
  • ROPC ではローカル アカウントのみがサポートされています。 ユーザーは、Microsoft、Google +、Twitter、AD FS、Facebook などのフェデレーション ID プロバイダーを使用してサインインすることはできません。
  • [サインインしたままにする] (KMSI) を含むセッション管理 は適用されません。

アプリケーションを登録する

アプリケーションを Azure AD B2C テナントに登録するには、Microsoft の新しい統合アプリの登録エクスペリエンスまたは以前のアプリケーション (レガシ) エクスペリエンスを使用できます。 この新しいエクスペリエンスの詳細を参照してください

  1. Azure portal にサインインします。
  2. ご利用の Azure AD B2C テナントが含まれるディレクトリを必ず使用してください。
    1. ポータル ツールバーの [Directories + subscriptions](ディレクトリ + サブスクリプション) アイコンを選択します。
    2. [ポータルの設定] | [Directories + subscriptions]\(ディレクトリ + サブスクリプション\) ページで Azure AD B2C ディレクトリを [ディレクトリ名] リストで見つけ、 [Switch] を選択します。
  3. Azure portal で、 [Azure AD B2C] を検索して選択します
  4. [アプリの登録] を選択し、 [新規登録] を選択します。
  5. アプリケーションの名前を入力します。 たとえば、ROPC_Auth_app のようになります。
  6. その他の値はそのままにして、 [登録] を選択します。
  7. 後の手順で使用するために、アプリケーション (クライアント) ID を記録しておきます。
  8. [管理] で、 [認証] を選択します。
  9. [新しいエクスペリエンスを試す] (表示されている場合) を選択します。
  10. [詳細設定][次のモバイルとデスクトップのフローを有効にする] セクションで、 [はい] を選択することで、アプリケーションをパブリック クライアントとして処理します。 ROPC フローには、この設定が必要となります。
  11. [保存] を選択します。
  12. 左側のメニューで、 [マニフェスト] を選択してマニフェスト エディターを開きます。
  13. oauth2AllowImplicitFlow 属性を true に設定します。
    "oauth2AllowImplicitFlow": true,
    
  14. [保存] を選択します。

リソース所有者のユーザー フローを作成する

  1. ご利用の Azure AD B2C テナントのグローバル管理者として Azure portal にサインインします。
  2. ご利用の Azure AD B2C テナントが含まれるディレクトリを必ず使用してください。
    1. ポータル ツールバーの [Directories + subscriptions](ディレクトリ + サブスクリプション) アイコンを選択します。
    2. [ポータルの設定] | [Directories + subscriptions](ディレクトリ + サブスクリプション) ページの [ディレクトリ名] の一覧で自分の Azure AD B2C ディレクトリを見つけて、 [切り替え] を選択します。
  3. Azure portal で、 [Azure AD B2C] を検索して選択します。
  4. [ユーザー フロー] を選択し、 [新しいユーザー フロー] を選択します。
  5. [リソース所有者のパスワード資格情報 (ROPC) を使用してサインインする] を選択します。
  6. [バージョン][プレビュー] が選択されていることを確認してから、 [作成] を選択します。
  7. ROPC_Auth など、ユーザー フローの名前を入力します。
  8. [アプリケーション要求][さらに表示する] をクリックします。
  9. [表示名]、[メール アドレス]、[ID プロバイダー] など、アプリケーションに必要なアプリケーション要求を選択します。
  10. [OK] を選択し、 [作成] を選択します。

前提条件

まだ行っていない場合は、Active Directory B2C でのカスタム ポリシーの概要に関する記事で、カスタム ポリシー スターター パックの詳細を確認してください。

リソース所有者のポリシーを作成する

  1. TrustFrameworkExtensions.xml ファイルを開きます。

  2. まだ存在しない場合は、ClaimsSchema 要素とその子要素を、BuildingBlocks 要素の下の最初の要素として追加します。

    <ClaimsSchema>
      <ClaimType Id="logonIdentifier">
        <DisplayName>User name or email address that the user can use to sign in</DisplayName>
        <DataType>string</DataType>
      </ClaimType>
      <ClaimType Id="resource">
        <DisplayName>The resource parameter passes to the ROPC endpoint</DisplayName>
        <DataType>string</DataType>
      </ClaimType>
      <ClaimType Id="refreshTokenIssuedOnDateTime">
        <DisplayName>An internal parameter used to determine whether the user should be permitted to authenticate again using their existing refresh token.</DisplayName>
        <DataType>string</DataType>
      </ClaimType>
      <ClaimType Id="refreshTokensValidFromDateTime">
        <DisplayName>An internal parameter used to determine whether the user should be permitted to authenticate again using their existing refresh token.</DisplayName>
        <DataType>string</DataType>
      </ClaimType>
    </ClaimsSchema>
    
  3. BuildingBlocks 要素の ClaimsSchema 要素の後に、ClaimsTransformations 要素とその子要素を追加します。

    <ClaimsTransformations>
      <ClaimsTransformation Id="CreateSubjectClaimFromObjectID" TransformationMethod="CreateStringClaim">
        <InputParameters>
          <InputParameter Id="value" DataType="string" Value="Not supported currently. Use oid claim." />
        </InputParameters>
        <OutputClaims>
          <OutputClaim ClaimTypeReferenceId="sub" TransformationClaimType="createdClaim" />
        </OutputClaims>
      </ClaimsTransformation>
    
      <ClaimsTransformation Id="AssertRefreshTokenIssuedLaterThanValidFromDate" TransformationMethod="AssertDateTimeIsGreaterThan">
        <InputClaims>
          <InputClaim ClaimTypeReferenceId="refreshTokenIssuedOnDateTime" TransformationClaimType="leftOperand" />
          <InputClaim ClaimTypeReferenceId="refreshTokensValidFromDateTime" TransformationClaimType="rightOperand" />
        </InputClaims>
        <InputParameters>
          <InputParameter Id="AssertIfEqualTo" DataType="boolean" Value="false" />
          <InputParameter Id="AssertIfRightOperandIsNotPresent" DataType="boolean" Value="true" />
        </InputParameters>
      </ClaimsTransformation>
    </ClaimsTransformations>
    
  4. DisplayNameLocal Account SignIn である ClaimsProvider 要素を探して、次の技術プロファイルを追加します。

    <TechnicalProfile Id="ResourceOwnerPasswordCredentials-OAUTH2">
      <DisplayName>Local Account SignIn</DisplayName>
      <Protocol Name="OpenIdConnect" />
      <Metadata>
        <Item Key="UserMessageIfClaimsPrincipalDoesNotExist">We can't seem to find your account</Item>
        <Item Key="UserMessageIfInvalidPassword">Your password is incorrect</Item>
        <Item Key="UserMessageIfOldPasswordUsed">Looks like you used an old password</Item>
        <Item Key="DiscoverMetadataByTokenIssuer">true</Item>
        <Item Key="ValidTokenIssuerPrefixes">https://sts.windows.net/</Item>
        <Item Key="METADATA">https://login.microsoftonline.com/{tenant}/.well-known/openid-configuration</Item>
        <Item Key="authorization_endpoint">https://login.microsoftonline.com/{tenant}/oauth2/token</Item>
        <Item Key="response_types">id_token</Item>
        <Item Key="response_mode">query</Item>
        <Item Key="scope">email openid</Item>
        <Item Key="grant_type">password</Item>
      </Metadata>
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="logonIdentifier" PartnerClaimType="username" Required="true" DefaultValue="{OIDC:Username}"/>
        <InputClaim ClaimTypeReferenceId="password" Required="true" DefaultValue="{OIDC:Password}" />
        <InputClaim ClaimTypeReferenceId="grant_type" DefaultValue="password" />
        <InputClaim ClaimTypeReferenceId="scope" DefaultValue="openid" />
        <InputClaim ClaimTypeReferenceId="nca" PartnerClaimType="nca" DefaultValue="1" />
        <InputClaim ClaimTypeReferenceId="client_id" DefaultValue="ProxyIdentityExperienceFrameworkAppId" />
        <InputClaim ClaimTypeReferenceId="resource_id" PartnerClaimType="resource" DefaultValue="IdentityExperienceFrameworkAppId" />
      </InputClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="oid" />
        <OutputClaim ClaimTypeReferenceId="userPrincipalName" PartnerClaimType="upn" />
      </OutputClaims>
      <OutputClaimsTransformations>
        <OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromObjectID" />
      </OutputClaimsTransformations>
      <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
    </TechnicalProfile>
    

    client_idDefaultValue を、前提条件のチュートリアルで作成した ProxyIdentityExperienceFramework アプリケーションのアプリケーション ID に置き換えます。 resource_idDefaultValue も、前提条件のチュートリアルで作成した IdentityExperienceFramework アプリケーションのアプリケーション ID に置き換えます。

  5. 次の ClaimsProvider 要素とその技術プロファイルを、ClaimsProviders 要素に追加します。

    <ClaimsProvider>
      <DisplayName>Azure Active Directory</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="AAD-UserReadUsingObjectId-CheckRefreshTokenDate">
          <Metadata>
            <Item Key="Operation">Read</Item>
            <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
          </Metadata>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="objectId" Required="true" />
          </InputClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="objectId" />
            <OutputClaim ClaimTypeReferenceId="refreshTokensValidFromDateTime" />
          </OutputClaims>
          <OutputClaimsTransformations>
            <OutputClaimsTransformation ReferenceId="AssertRefreshTokenIssuedLaterThanValidFromDate" />
            <OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromObjectID" />
          </OutputClaimsTransformations>
          <IncludeTechnicalProfile ReferenceId="AAD-Common" />
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>
    
    <ClaimsProvider>
      <DisplayName>Session Management</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="SM-RefreshTokenReadAndSetup">
          <DisplayName>Trustframework Policy Engine Refresh Token Setup Technical Profile</DisplayName>
          <Protocol Name="None" />
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="objectId" />
            <OutputClaim ClaimTypeReferenceId="refreshTokenIssuedOnDateTime" />
          </OutputClaims>
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>
    
    <ClaimsProvider>
      <DisplayName>Token Issuer</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="JwtIssuer">
          <Metadata>
            <!-- Point to the redeem refresh token user journey-->
            <Item Key="RefreshTokenUserJourneyId">ResourceOwnerPasswordCredentials-RedeemRefreshToken</Item>
          </Metadata>
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>
    
  6. UserJourneys 要素とその子要素を、TrustFrameworkPolicy 要素に追加します。

    <UserJourney Id="ResourceOwnerPasswordCredentials">
      <PreserveOriginalAssertion>false</PreserveOriginalAssertion>
      <OrchestrationSteps>
        <OrchestrationStep Order="1" Type="ClaimsExchange">
          <ClaimsExchanges>
            <ClaimsExchange Id="ResourceOwnerFlow" TechnicalProfileReferenceId="ResourceOwnerPasswordCredentials-OAUTH2" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="2" Type="ClaimsExchange">
          <ClaimsExchanges>
            <ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="3" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
      </OrchestrationSteps>
    </UserJourney>
    <UserJourney Id="ResourceOwnerPasswordCredentials-RedeemRefreshToken">
      <PreserveOriginalAssertion>false</PreserveOriginalAssertion>
      <OrchestrationSteps>
        <OrchestrationStep Order="1" Type="ClaimsExchange">
          <ClaimsExchanges>
            <ClaimsExchange Id="RefreshTokenSetupExchange" TechnicalProfileReferenceId="SM-RefreshTokenReadAndSetup" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="2" Type="ClaimsExchange">
          <ClaimsExchanges>
            <ClaimsExchange Id="CheckRefreshTokenDateFromAadExchange" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId-CheckRefreshTokenDate" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="3" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
      </OrchestrationSteps>
    </UserJourney>
    
  7. Azure AD B2C テナントの [カスタム ポリシー] ページで、 [ポリシーのアップロード] を選択します。

  8. [ポリシーが存在する場合は上書きする] を有効にし、TrustFrameworkExtensions.xml ファイルを参照して選択します。

  9. [アップロード] をクリックします。

証明書利用者ファイルを作成する

次に、作成したユーザー体験を開始する証明書利用者ファイルを更新します。

  1. 作業ディレクトリに SignUpOrSignin.xml ファイルのコピーを作成し、名前を ROPC_Auth.xml に変更します。

  2. 新しいファイルを開き、TrustFrameworkPolicyPolicyId 属性の値を一意の値に変更します。 ポリシー ID がポリシーの名前になります。 たとえば、B2C_1A_ROPC_Auth などとします。

  3. DefaultUserJourneyReferenceId 属性の値を ResourceOwnerPasswordCredentials に変更します。

  4. OutputClaims 要素を、次の要求だけを含むように変更します。

    <OutputClaim ClaimTypeReferenceId="sub" />
    <OutputClaim ClaimTypeReferenceId="objectId" />
    <OutputClaim ClaimTypeReferenceId="displayName" DefaultValue="" />
    <OutputClaim ClaimTypeReferenceId="givenName" DefaultValue="" />
    <OutputClaim ClaimTypeReferenceId="surname" DefaultValue="" />
    
  5. Azure AD B2C テナントの [カスタム ポリシー] ページで、 [ポリシーのアップロード] を選択します。

  6. [ポリシーが存在する場合は上書きする] を有効にし、ROPC_Auth.xml ファイルを参照して選択します。

  7. [アップロード] をクリックします。

ROPC フローをテストする

お気に入りの API 開発アプリケーションを使用して API 呼び出しを生成し、応答を確認して、ポリシーをデバッグします。 POST 要求の本文として以下の情報を使用し、次の例のような呼び出しを作成します。

https://<tenant-name>.b2clogin.com/<tenant-name>.onmicrosoft.com/B2C_1A_ROPC_Auth/oauth2/v2.0/token

  • <tenant-name>を Azure AD B2C テナントの名前に置き換えます。
  • B2C_1A_ROPC_Auth は実際のリソース所有者のパスワード資格情報ポリシーのフル ネームに置き換えます。
Key
username user-account
password password1
grant_type password
scope openid application-id offline_access
client_id application-id
response_type token id_token
  • user-account は、テナント内のユーザー アカウントの名前に置き換えます。
  • password1 は、ユーザー アカウントのパスワードに置き換えます。
  • application-id は、ROPC_Auth_app 登録のアプリケーション ID に置き換えます。
  • 更新トークンを受信する場合、Offline_access は省略可能です。

実際の POST 要求は次の例のようになります。

POST /<tenant-name>.onmicrosoft.com/B2C_1A_ROPC_Auth/oauth2/v2.0/token HTTP/1.1
Host: <tenant-name>.b2clogin.com
Content-Type: application/x-www-form-urlencoded

username=contosouser.outlook.com.ws&password=Passxword1&grant_type=password&scope=openid+bef22d56-552f-4a5b-b90a-1988a7d634ce+offline_access&client_id=bef22d56-552f-4a5b-b90a-1988a7d634ce&response_type=token+id_token

オフライン アクセスで成功した応答は、次の例のようになります。

{
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik9YQjNhdTNScWhUQWN6R0RWZDM5djNpTmlyTWhqN2wxMjIySnh6TmgwRlki...",
    "token_type": "Bearer",
    "expires_in": "3600",
    "refresh_token": "eyJraWQiOiJacW9pQlp2TW5pYVc2MUY0TnlfR3REVk1EVFBLbUJLb0FUcWQ1ZWFja1hBIiwidmVyIjoiMS4wIiwiemlwIjoiRGVmbGF0ZSIsInNlciI6Ij...",
    "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik9YQjNhdTNScWhUQWN6R0RWZDM5djNpTmlyTWhqN2wxMjIySnh6TmgwRlki..."
}

更新トークンを利用する

ここで示すような POST 呼び出しを作成します。 要求の本文として、次の表の情報を使用します。

https://<tenant-name>.b2clogin.com/<tenant-name>.onmicrosoft.com/B2C_1A_ROPC_Auth/oauth2/v2.0/token

  • <tenant-name>を Azure AD B2C テナントの名前に置き換えます。
  • B2C_1A_ROPC_Auth は実際のリソース所有者のパスワード資格情報ポリシーのフル ネームに置き換えます。
Key
grant_type refresh_token
response_type id_token
client_id application-id
resource application-id
refresh_token refresh-token
  • application-id は、ROPC_Auth_app 登録のアプリケーション ID に置き換えます。
  • refresh-token は、前の応答で返送された refresh_token に置き換えます。

成功した応答は、次の例のようになります。

{
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ilg1ZVhrNHh5b2pORnVtMWtsMll0djhkbE5QNC1jNTdkTzZRR1RWQndhT...",
    "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ilg1ZVhrNHh5b2pORnVtMWtsMll0djhkbE5QNC1jNTdkTzZRR1RWQn...",
    "token_type": "Bearer",
    "not_before": 1533672990,
    "expires_in": 3600,
    "expires_on": 1533676590,
    "resource": "bef2222d56-552f-4a5b-b90a-1988a7d634c3",
    "id_token_expires_in": 3600,
    "profile_info": "eyJ2ZXIiOiIxLjAiLCJ0aWQiOiI1MTZmYzA2NS1mZjM2LTRiOTMtYWE1YS1kNmVlZGE3Y2JhYzgiLCJzdWIiOm51bGwsIm5hbWUiOiJEYXZpZE11IiwicHJlZmVycmVkX3VzZXJuYW1lIjpudWxsLCJpZHAiOiJMb2NhbEFjY291bnQifQ",
    "refresh_token": "eyJraWQiOiJjcGltY29yZV8wOTI1MjAxNSIsInZlciI6IjEuMCIsInppcCI6IkRlZmxhdGUiLCJzZXIiOiIxLjAi...",
    "refresh_token_expires_in": 1209600
}

トラブルシューティング

指定されたアプリケーションは、OAuth 暗黙的フローを許可するように構成されていません

  • 現象 - ROPC フローを実行すると、次のメッセージが表示されます: AADB2C90057: 指定されたアプリケーションは、OAuth 暗黙的フローを許可するように構成されていません
  • 考えられる原因 - アプリケーションで暗黙のフローが許可されていません。
  • 解決方法: Azure AD B2C でアプリケーションの登録を作成するときは、アプリケーションマニフェストを手動で編集し、oauth2AllowImplicitFlow プロパティの値を true に設定する必要があります。 oauth2AllowImplicitFlow プロパティを構成した後、変更が有効になるまで数分間かかる場合があります (通常は 5 分以下)。

ネイティブ SDK または App-Auth を使用する

Azure AD B2C は、パブリック クライアント リソース所有者のパスワード認証情報に関する OAuth 2.0 標準を満たしており、ほとんどのクライアント SDK と互換性があります。 最新情報については、最新のベスト プラクティスを実装する OAuth 2.0 と OpenID Connect のネイティブ App SDK に関するページを参照してください。

次のステップ

Azure AD B2C で使用するように構成された作業サンプル (Android 用iOS 用) を GitHub からダウンロードしてください。