Выполнение автоматизированных тестов интеграции

Как разработчик вы хотите выполнять автоматические тесты интеграции в разрабатываемых приложениях. Вызов API, защищенного платформой удостоверений Майкрософт (или другими защищенными API, такими как Microsoft Graph), в автоматизированных тестах интеграции является сложной задачей. Для идентификатора Microsoft Entra часто требуется интерактивный запрос на вход пользователя, который сложно автоматизировать. В этой статье описывается, как можно использовать неинтерактивный поток предоставления учетных данных владельца ресурса (ROPC) для автоматического входа пользователей в целях тестирования.

Чтобы подготовиться к автоматизированным тестам интеграции, создайте тестовых пользователей, создайте и настройте регистрацию приложения и при необходимости внесите некоторые изменения в конфигурацию клиента. Для выполнения некоторых из этих действий требуются права администратора. Кроме того, Майкрософт не рекомендует использовать поток ROPC в рабочей среде. Создайте отдельный тестовый клиент, администратором которого вы являетесь, чтобы можно было безопасно и эффективно выполнять автоматизированные тесты интеграции.

Предупреждение

Майкрософт не рекомендует использовать поток ROPC в рабочей среде. В большинстве случаев в рабочей среде доступны и рекомендуются более безопасные альтернативы. Для потока ROPC нужен очень высокий уровень доверия в приложении, и он связан с рисками, которых нет в других потоках проверки подлинности. Используйте этот поток только в целях тестирования в отдельном тестовом клиенте и только с тестовыми пользователями.

Важно!

  • Платформа удостоверений Майкрософт поддерживает только ROPC в клиентах Microsoft Entra, а не личная учетная запись. Это означает, что придется использовать конечную точку клиента (https://login.microsoftonline.com/{TenantId_or_Name}) или конечную точку organizations.
  • Пользователи личных учетных записей, приглашенные в клиент Microsoft Entra, не могут использовать ROPC.
  • Учетные записи без паролей не могут войти в систему с помощью учетных данных владельца ресурса. То есть, такие функции, как вход по SMS, FIDO, а также приложение Authenticator не будут работать для этого потока.
  • Если пользователи должны использовать для входа в приложение многофакторную проверку подлинности (MFA), они будут заблокированы.
  • ROPC не поддерживается в сценариях федерации гибридных удостоверений (например, идентификатор Microsoft Entra и службы федерации Active Directory (AD FS) (AD FS), используемые для проверки подлинности локальных учетных записей. Если пользователи полностью перенаправляются на страницу локального поставщика удостоверений, Microsoft Entra ID не сможет проверить имя пользователя и пароль для этого поставщика удостоверений. Но ROPC поддерживается в сценариях сквозной проверки подлинности.
  • Существует следующее исключение из сценария гибридной федерации удостоверений: политика обнаружения домашней области со свойством AllowCloudPasswordValidation, для которого задано значение TRUE, позволит использовать поток учетных данных владельца ресурса для федеративных пользователей, если локальный пароль синхронизируется с облаком. Дополнительные сведения см. в разделе Включение прямой проверки подлинности ROPC для федеративных пользователей в устаревших приложениях.

Создайте отдельный тестовый клиент

Использовать поток проверки подлинности ROPC в рабочей среде рискованно, поэтому создайте отдельный клиент для тестирования приложений. Можно использовать существующий тестовый клиент, но необходимо быть администратором в клиенте, так как для выполнения некоторых действий требуются права администратора.

создавать и настраивать хранилище ключей;

Рекомендуем безопасно хранить имена и пароли тестовых пользователей в качестве секретов в Azure Key Vault. Когда вы будете выполнять тесты, они будут запускаться в контексте субъекта безопасности. Субъект безопасности — это пользователь Microsoft Entra, если вы выполняете тесты локально (например, в Visual Studio или Visual Studio Code), или субъект-служба или управляемое удостоверение, если выполняете тесты в Azure Pipelines или другом ресурсе Azure. У субъекта-службы должны быть разрешения на чтение и вывод списка секретов, чтобы средство выполнения теста могло получать имена и пароли тестовых пользователей из хранилища ключей. Дополнительные сведения см. в статье Проверка подлинности в Azure Key Vault.

  1. Создайте новое хранилище ключей, если у вас его нет.
  2. Запишите значение свойства URI хранилища (в формате https://<your-unique-keyvault-name>.vault.azure.net/), так как оно будет использоваться в примере теста позже в этой статье.
  3. Назначьте политику доступа для субъекта безопасности, выполняющего тесты. Предоставьте пользователю, субъекту-службе или управляемому удостоверению разрешение на получение и вывод списка секретов в хранилище ключей.

Создание тестовых пользователей

Совет

Действия, описанные в этой статье, могут немного отличаться на портале, с который вы начинаете работу.

Создайте тестовых пользователей в клиенте для тестирования. Так как тестовые пользователи не являются реальными людьми, рекомендуется назначать сложные пароли и безопасно хранить их в качестве секретов в Azure Key Vault.

  1. Войдите в Центр администрирования Microsoft Entra как минимум облачные приложения Администратор istrator.
  2. Перейдите ко всем пользователям удостоверений>>.
  3. Нажмите Создать пользователя и создайте одну или несколько учетных записей тестовых пользователей в каталоге.
  4. В примере теста далее в этой статье используется один тестовый пользователь. Добавьте имя и пароль тестового пользователя в качестве секретов в созданном ранее хранилище ключей. Добавьте имя пользователя в качестве секрета с именем TestUserName и паролем в качестве секрета с именем TestPassword.

Создание и настройка регистрации приложения

Зарегистрируйте приложение, которое выступает в качестве клиентского приложения при вызове API во время тестирования. Это не должно быть приложение, выполняемое в рабочей среде. У вас должно быть отдельное приложение для использования только в целях тестирования.

Регистрация приложения

Создайте регистрацию приложения. Вы можете выполнить действия, описанные в кратком руководстве по регистрации приложений. Вам не нужно добавлять URI перенаправления или учетные данные, поэтому вы можете пропустить эти разделы.

Запишите значение свойства Идентификатор приложения (клиента), так как оно будет использоваться в примере теста позже в этой статье.

Включение в приложении общедоступных потоков клиентов

ROPC — это общедоступный поток клиента, поэтому необходимо включить приложение для общедоступных потоков клиентов. Из регистрации приложения в Центре администрирования Microsoft Entra перейдите в раздел "Дополнительные параметры проверки подлинности>", чтобы разрешить общедоступные потоки> клиентов. Переведите переключатель в положение Да.

Так как ROPC не является интерактивным потоком, вы не увидите экран запроса согласия во время выполнения. Заранее дайте согласие на разрешения, чтобы избежать ошибок при получении маркеров.

Добавьте разрешения в приложение. Не добавляйте в приложение конфиденциальные или высоко привилегированные разрешения, мы рекомендуем область сценарии тестирования в базовые сценарии интеграции вокруг интеграции с идентификатором Microsoft Entra.

Из регистрации приложения в Центре администрирования Microsoft Entra перейдите к разрешениям API Add a permissions>. Добавьте разрешения, необходимые для вызова интерфейсов API, которые вы будете использовать. В тестовом примере в этой статье используются разрешения https://graph.microsoft.com/User.Read и https://graph.microsoft.com/User.ReadBasic.All.

После добавления разрешений необходимо согласиться с ними. Способ предоставления согласия на разрешения зависит от того, находится ли тестовое приложение в том же клиенте, что и регистрация приложения, и являетесь ли вы администратором в клиенте.

Регистрация приложения и само приложение находятся в одном клиенте, и вы являетесь его администратором

Если вы планируете протестировать приложение в том же клиенте, в который вы зарегистрировали его, и вы являетесь администратором этого клиента, вы можете предоставить согласие на разрешения из Центра администрирования Microsoft Entra. В регистрации приложений на портале Azure перейдите к разделу Разрешения API и нажмите кнопку Предоставить согласие администратора для <your_tenant_name> рядом с кнопкой Добавить разрешение, а затем нажмите Да для подтверждения.

Регистрация приложения и само приложение находятся в разных клиентах или вы не являетесь администратором

Если вы не планируете тестировать приложение в том же клиенте, в который вы зарегистрировали его, или вы не являетесь администратором в клиенте, вы не можете согласиться с разрешениями в Центре администрирования Microsoft Entra. Однако вы по-прежнему можете дать согласие на некоторые разрешения, запустив запрос на вход в веб-браузере.

В регистрации приложения в Центре администрирования Microsoft Entra перейдите к конфигурациям>платформы проверки подлинности>, чтобы добавить веб-сайт платформы.> Добавьте URI перенаправления "https://localhost" и нажмите Настроить.

Не существует способа дать предварительное согласие на портале Azure, если вы не являетесь администратором, поэтому отправьте следующий запрос в браузере. При появлении запроса на экране входа выполните вход с помощью тестовой учетной записи, созданной на предыдущем шаге. Дайте согласие на запрошенные разрешения. Этот шаг нужно повторить для каждого 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} идентификатором вашего клиента, {your_client_ID} — идентификатором клиента приложения, а {resource_you_want_to_call} — URI идентификатора (например, "https://graph.microsoft.com") или идентификатором приложения API, доступ к которому вы хотите получить.

Исключение тестовых приложений и пользователей из политики MFA

Скорее всего, у вашего клиента есть политика условного доступа, требующая многофакторной проверки подлинности (MFA) для всех пользователей, как рекомендуется корпорацией Майкрософт. MFA не будет работать с ROPC, поэтому необходимо исключить тестовые приложения и тестовых пользователей из этой политики.

Чтобы исключить учетные записи пользователей, выполните следующие действия:

  1. Войдите в Центр администрирования Microsoft Entra как минимум облачные приложения Администратор istrator.
  2. Перейдите в Центр безопасности удостоверений>в области навигации слева и выберите условный доступ.
  3. В политиках выберите политику условного доступа, требующую MFA.
  4. Выберите Идентификаторы пользователей или рабочих нагрузок.
  5. Откройте вкладку Исключить и поставьте флажок для пункта Пользователи и группы.
  6. Выберите учетные записи пользователей, которые следует исключить, в разделе Выбор исключенных пользователей.
  7. Нажмите Выбрать, а затем Сохранить.

Чтобы исключить тестовое приложение, выполните следующие действия:

  1. В политиках выберите политику условного доступа, требующую MFA.
  2. Выберите Облачные приложения или действия.
  3. Откройте вкладку Исключить и выберите Выбор исключенных облачных приложений.
  4. Выберите приложения, которые необходимо исключить, в списке Выбор исключенных облачных приложений.
  5. Нажмите Выбрать, а затем Сохранить.

Написание тестов для приложения

После настройки можно приступить к написанию автоматических тестов. Ниже приведены тесты:

  1. Пример кода .NET использует библиотеку проверки подлинности Майкрософт (MSAL) и xUnit, общую платформу тестирования.
  2. Пример кода JavaScript использует библиотеку проверки подлинности Майкрософт (MSAL) и Playwright, общую платформу тестирования.

Настройка файла appsettings.json

Добавьте идентификатор клиента для созданного ранее тестового приложения, необходимые области и универсальный код ресурса (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() выполняет проверку подлинности с помощью Azure Key Vault, получая маркер доступа из субъекта-службы, настроенного с помощью переменных среды, или управляемое удостоверение (если код выполняется в ресурсе Azure с управляемым удостоверением). Если код выполняется локально, DefaultAzureCredential использует учетные данные локального пользователя. Дополнительные сведения см. в разделе о клиентской библиотеке удостоверений Azure.

Используйте библиотеку проверки подлинности Майкрософт (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);
    }
}