開発者は、開発したアプリに対して自動統合テストを実行する必要があります。 自動化された統合テストで、Microsoft ID プラットフォーム (または Microsoft Graph などの他の保護された API) によって保護された API を呼び出すことは困難です。 Microsoft Entra ID では、多くの場合、対話型ユーザー サインイン プロンプトが必要になりますが、これは自動化するのが困難です。 この記事では、 リソース所有者パスワード資格情報付与 (ROPC) と呼ばれる非対話型フローを使用して、テストのためにユーザーを自動的にサインインさせる方法について説明します。
自動統合テストを準備するには、テスト ユーザーを作成し、アプリの登録を作成して構成します。また、テナントに対していくつかの構成変更を加える可能性があります。 これらの手順の一部では、管理特権が必要です。 自動化された統合テストを安全かつ効果的に実行できるように、管理者である別のテスト テナントを作成します。
警告
運用環境では ROPC フローを使用 しないことを お勧めします。 承認コード フローなど、より信頼できる方法を使用します。 ほとんどの運用シナリオでは、より安全な代替手段を利用でき、推奨されます。 ROPC フローでは、アプリケーションに非常に高い信頼が必要であり、他の認証フローには存在しないリスクが伴います。 このフローは、 別のテスト テナントのテスト目的でのみ使用し、テスト ユーザーでのみ使用する必要があります。
重要
- Microsoft ID プラットフォームでは、Microsoft Entra テナント内での ROPC をサポートしています。個人アカウントは対象外です。 そのため、テナント固有のエンドポイント (
https://login.microsoftonline.com/{TenantId_or_Name}
) またはorganizations
エンドポイントを使用する必要があります。 - Microsoft Entra テナントに招待された個人アカウントでは、ROPC を使用できません。
- パスワードがないアカウントは ROPC でサインインできません。つまり、SMS サインイン、FIDO、および Authenticator アプリなどの機能は、そのフローでは動作しません。
- ユーザーが 多要素認証 (MFA) を使用してアプリケーションにサインインする必要がある場合は、代わりにブロックされます。
- ROPC は、ハイブリッド ID フェデレーション シナリオ (オンプレミス アカウントの認証に使用される Microsoft Entra ID や Active Directory フェデレーション サービス (AD FS) など) ではサポートされていません。 ユーザーがフルページでオンプレミスの ID プロバイダーにリダイレクトされた場合、Microsoft Entra ID は、その ID プロバイダーに対してユーザー名とパスワードをテストできません。 ただし、ROPC ではパススルー認証がサポートされています。
- ハイブリッド ID フェデレーション シナリオの例外は次のようになります。 AllowCloudPasswordValidation を TRUE に設定したホーム領域検出ポリシーでは、オンプレミスのパスワードがクラウドに同期されるときに、フェデレーション ユーザーに対して ROPC フローを機能させることができます。 詳細については、「 レガシ アプリケーションのフェデレーション ユーザーの直接 ROPC 認証を有効にする」を参照してください。
別のテスト テナントを作成する
運用環境では ROPC 認証フローの使用は危険であるため、アプリケーションをテストする 別のテナントを作成 します。 既存のテスト テナントを使用できますが、次の手順の一部では管理特権が必要になるため、テナントの管理者である必要があります。
キー コンテナーを作成して構成する
テストユーザー名とパスワードを シークレット として Azure Key Vault に安全に格納することをお勧めします。 後でテストを実行すると、テストはセキュリティ プリンシパルのコンテキストで実行されます。 セキュリティ プリンシパルは、テストをローカルで (たとえば、Visual Studio または Visual Studio Code で) 実行している場合は、Microsoft Entra ユーザーです。テストを Azure Pipelines または別の Azure リソースで実行している場合は、サービス プリンシパルまたはマネージド ID です。 テスト ランナーがキー コンテナーからテスト ユーザー名とパスワードを取得できるようにするには、セキュリティ プリンシパルに シークレットの読み取 りと 一覧表示 のアクセス許可が必要です。 詳細については、「 Azure Key Vault での認証」を参照してください。
- まだキー コンテナーがない場合は、新しいキー コンテナーを作成します。
- この記事の後半のテスト例で使用される コンテナー URI プロパティ値 (
https://<your-unique-keyvault-name>.vault.azure.net/
と同様) をメモしておきます。 - テストを実行するセキュリティ プリンシパルのアクセス ポリシーを割り当てます。 ユーザー、サービス プリンシパル、またはマネージド ID に、キー コンテナー内のシークレットの 取得 と 一覧表示 のアクセス許可を付与します。
テスト ユーザーの作成
テスト用のテナントにいくつかのテスト ユーザーを作成します。 テスト ユーザーは実際の人間ではないため、複雑なパスワードを割り当て、これらのパスワードを シークレット として Azure Key Vault に安全に格納することをお勧めします。
- Microsoft Entra 管理センターに、少なくともクラウド アプリケーション管理者としてサインインします。
- Entra ID>Users に移動します。
- [ 新しいユーザー ] を選択し、ディレクトリに 1 つ以上のテスト ユーザー アカウントを作成します。
- この記事の後半のテストの例では、単一のテスト ユーザーを使用します。 テスト ユーザー名とパスワードを、前に作成したキー コンテナーにシークレットとして追加します。 "TestUserName" という名前のシークレットとしてユーザー名を、"TestPassword" という名前のシークレットとしてパスワードを追加します。
アプリの登録を作成して構成する
テスト中に API を呼び出すときにクライアント アプリとして機能するアプリケーションを登録します。 これは、運用環境に既に存在する可能性があるアプリケーションと同じアプリケーションにすることはできません。 テスト目的でのみ使用する別のアプリを用意する必要があります。
アプリケーションを登録する
アプリの登録を作成する。 アプリ登録のクイックスタートの手順に従って、アプリケーション (クライアント) ID を書き留めることができます。この ID は、この記事の後半のテスト例で使用します。
パブリック クライアント フローに対してアプリを有効にする
ROPC はパブリック クライアント フローであるため、パブリック クライアント フローに対してアプリを有効にする必要があります。 Microsoft Entra 管理センターでアプリの登録から、認証>高度な設定>パブリック クライアント フローを許可するに移動します。 トグルを [はい] に設定します。
テスト中に使用するアクセス許可に同意する
ROPC は対話型フローではないので、実行時に同意する同意画面は表示されません。 トークンの取得時にエラーが発生しないように、アクセス許可を事前に確認します。
アプリにアクセス許可を追加します。 アプリに機密性の高いアクセス許可や高い特権のアクセス許可を追加しないでください。テスト シナリオは、Microsoft Entra ID との統合に関する基本的な統合シナリオにスコープを設定することをお勧めします。
Microsoft Entra 管理センターでアプリの登録から、[API のアクセス許可] に移動します>アクセス許可を追加します。 使用している API を呼び出すために必要なアクセス許可を追加します。 この記事の以降のテストの例では、https://graph.microsoft.com/User.Read
と https://graph.microsoft.com/User.ReadBasic.All
のアクセス許可を使用します。
アクセス許可が追加されたら、アクセス許可に同意する必要があります。 アクセス許可に同意する方法は、テスト アプリがアプリの登録と同じテナントにあるかどうかと、テナントの管理者であるかどうかによって異なります。
アプリとアプリの登録が同じテナントにあり、管理者である場合
アプリを登録したのと同じテナントでアプリのテストを計画していて、そのテナントの管理者である場合は、 Microsoft Entra 管理センターからのアクセス許可に同意できます。 Azure portal でアプリの登録で、[API のアクセス許可] に移動し、[アクセス許可の<] ボタンの横にある [>your_tenant_nameの管理者の同意を付与する] ボタンを選択し、[はい] を選択して確認します。
アプリとアプリの登録が異なるテナントにあるか、管理者でない場合
アプリを登録したのと同じテナントでアプリのテストを計画していない場合、またはテナントの管理者でない場合は、 Microsoft Entra 管理センターからのアクセス許可に同意できません。 ただし、Web ブラウザーでサインイン プロンプトをトリガーすると、一部のアクセス許可に同意できます。
Microsoft Entra 管理センターに移動し、[Identity>Applications>App registrations> 一覧からアプリケーションを選択します。 > 認証>プラットフォーム構成>プラットフォームの追加>Web に移動します。 リダイレクト URI "https://localhost"" を追加し、構成 を選択します。
管理者以外のユーザーが Azure portal を通じて事前承認を行う方法はないため、ブラウザーで次のリクエストを送信してください。 ログイン画面が表示されたら、前の手順で作成したテスト アカウントでサインインします。 プロンプトで表示されたアクセス許可に同意します。 呼び出す API や使用するテスト ユーザーごとに、この手順を繰り返す必要がある場合があります。
// Line breaks for legibility only
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
client_id={your_client_ID}
&response_type=code
&redirect_uri=https://localhost
&response_mode=query
&scope={resource_you_want_to_call}/.default
&state=12345
{tenant} をテナント ID に、{your_client_ID} をアプリケーションのクライアント ID に置き換え、{resource_you_want_to_call} を識別子 URI (例: "https://graph.microsoft.com")アクセスしようとしている API のアプリ ID。
MFA ポリシーからテスト アプリとユーザーを除外する
テナントには、Microsoft が推奨するように、 すべてのユーザーに多要素認証 (MFA) を必要とする条件付きアクセス ポリシーがある可能性があります。 MFA は ROPC では機能しないため、テスト アプリケーションとテスト ユーザーをこの要件から除外する必要があります。
ユーザー アカウントを除外するには:
- Microsoft Entra 管理センターに、少なくともクラウド アプリケーション管理者としてサインインします。
- [保護]>[条件付きアクセス]>[ポリシー] に移動します。
- MFA を必要とする条件付きアクセス ポリシーを選択します。
- [ユーザーまたはワークロード ID] を選択します。
- [ 除外 ] タブを選択し、[ ユーザーとグループ ] チェック ボックスをオンにします。
- [除外するユーザーの選択] で除外する ユーザー アカウントを選択します。
- [選択] ボタンを 選択 し、[ 保存] を選択します。
テスト アプリケーションを除外するには:
- [ポリシー] で、MFA を必要とする条件付きアクセス ポリシーを選択します。
- [クラウド アプリ] または [アクション] を選択します。
- [ 除外 ] タブを選択し、[ 除外されたクラウド アプリを選択] を選択します。
- [除外するクラウド アプリの選択] で除外する アプリを選択します。
- [選択] ボタンを 選択 し、[ 保存] を選択します。
アプリケーション テストの作成
設定が完了したので、自動テストを作成できます。 次のテストについて示します。
- .NET サンプル コードでは、 Microsoft Authentication Library (MSAL) と xUnit (一般的なテスト フレームワーク) を使用します。
- JavaScript サンプル コードでは、 Microsoft Authentication Library (MSAL) と Playwright (一般的なテスト フレームワーク) を使用します。
appsettings.json ファイルを設定する
前に作成したテスト アプリのクライアント ID、必要なスコープ、キー コンテナー URI をテスト プロジェクトの appsettings.json ファイルに追加します。
{
"Authentication": {
"AzureCloudInstance": "AzurePublic", //Will be different for different Azure clouds, like US Gov
"AadAuthorityAudience": "AzureAdMultipleOrgs",
"ClientId": <your_client_ID>
},
"WebAPI": {
"Scopes": [
//For this Microsoft Graph example. Your value(s) will be different depending on the API you're calling
"https://graph.microsoft.com/User.Read",
//For this Microsoft Graph example. Your value(s) will be different depending on the API you're calling
"https://graph.microsoft.com/User.ReadBasic.All"
]
},
"KeyVault": {
"KeyVaultUri": "https://<your-unique-keyvault-name>.vault.azure.net//"
}
}
すべてのテスト クラスで使用するようにクライアントを設定する
SecretClient() を使用して、Azure Key Vault からテスト ユーザー名とパスワード のシークレットを取得します。 このコードでは、Key Vault がスロットルされている場合の再試行にはエクスポネンシャル バックオフが使用されています。
DefaultAzureCredential() は、環境変数またはマネージド ID によって構成されたサービス プリンシパルからアクセス トークンを取得することによって Azure Key Vault で認証されます (コードがマネージド ID を持つ Azure リソースで実行されている場合)。 コードがローカルで実行されている場合、DefaultAzureCredential
はローカル ユーザーの資格情報を使用します。 詳細については、 Azure ID クライアント ライブラリ のコンテンツを参照してください。
Microsoft Authentication Library (MSAL) を使用して、ROPC フローを使用して認証し、アクセス トークンを取得します。 アクセス トークンは、HTTP 要求でベアラー トークンとして渡されます。
using Xunit;
using System.Threading.Tasks;
using Microsoft.Identity.Client;
using System.Security;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using Microsoft.Extensions.Configuration;
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using Azure.Core;
using System;
public class ClientFixture : IAsyncLifetime
{
public HttpClient httpClient;
public async Task InitializeAsync()
{
var builder = new ConfigurationBuilder().AddJsonFile("<path-to-json-file>");
IConfigurationRoot Configuration = builder.Build();
var PublicClientApplicationOptions = new PublicClientApplicationOptions();
Configuration.Bind("Authentication", PublicClientApplicationOptions);
var app = PublicClientApplicationBuilder.CreateWithApplicationOptions(PublicClientApplicationOptions)
.Build();
SecretClientOptions options = new SecretClientOptions()
{
Retry =
{
Delay= TimeSpan.FromSeconds(2),
MaxDelay = TimeSpan.FromSeconds(16),
MaxRetries = 5,
Mode = RetryMode.Exponential
}
};
string keyVaultUri = Configuration.GetValue<string>("KeyVault:KeyVaultUri");
var client = new SecretClient(new Uri(keyVaultUri), new DefaultAzureCredential(), options);
KeyVaultSecret userNameSecret = client.GetSecret("TestUserName");
KeyVaultSecret passwordSecret = client.GetSecret("TestPassword");
string password = passwordSecret.Value;
string username = userNameSecret.Value;
string[] scopes = Configuration.GetSection("WebAPI:Scopes").Get<string[]>();
SecureString securePassword = new NetworkCredential("", password).SecurePassword;
AuthenticationResult result = null;
httpClient = new HttpClient();
try
{
result = await app.AcquireTokenByUsernamePassword(scopes, username, securePassword)
.ExecuteAsync();
}
catch (MsalException) { }
string accessToken = result.AccessToken;
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
}
public Task DisposeAsync() => Task.CompletedTask;
}
テスト クラスでの使用
次の例は、Microsoft Graph を呼び出すテストです。 このテストを、独自のアプリケーションまたは API でテストする内容に置き換えます。
public class ApiTests : IClassFixture<ClientFixture>
{
ClientFixture clientFixture;
public ApiTests(ClientFixture clientFixture)
{
this.clientFixture = clientFixture;
}
[Fact]
public async Task GetRequestTest()
{
var testClient = clientFixture.httpClient;
HttpResponseMessage response = await testClient.GetAsync("https://graph.microsoft.com/v1.0/me");
var responseCode = response.StatusCode.ToString();
Assert.Equal("OK", responseCode);
}
}