Executar testes de integração automatizados

Como desenvolvedor, você deseja executar testes de integração automatizados nos aplicativos que desenvolve. Chamar sua API protegida pela plataforma de identidade da Microsoft (ou outras APIs protegidas, como Microsoft Graph) em testes de integração automatizada é um desafio. O Microsoft Entra ID geralmente requer um prompt de entrada de usuário interativo, o que é difícil de automatizar. Este artigo descreve como você pode usar um fluxo não interativo, chamado ROPC (Concessão de credenciais de senha do proprietário do recurso), para conectar automaticamente os usuários para testes.

Para se preparar para seus testes de integração automatizados, crie alguns usuários de teste, crie e configure um registro de aplicativo e, potencialmente, faça alterações de configuração em seu locatário. Algumas dessas etapas exigem privilégios de administrador. Além disso, a Microsoft recomenda que você não use o fluxo ROPC em um ambiente de produção. Crie um locatário de teste separado do qual você é um administrador para que você possa executar seus testes de integração automatizados com segurança e eficiência.

Aviso

A Microsoft recomenda que você não use o fluxo ROPC em um ambiente de produção. Na maioria dos cenários de produção, alternativas mais seguras estão disponíveis e são recomendadas. Esse fluxo ROPC requer um alto grau de confiança no aplicativo e carrega riscos que não estão presentes em outros fluxos de autenticação. Você só deve usar esse fluxo para fins de teste em um locatário de teste separadoe somente com usuários de teste.

Importante

  • A plataforma de identidade da Microsoft dá suporte apenas ao ROPC em locatários do Microsoft Entra, não a contas pessoais. Isso significa que você deve usar um terminal específico do locatário (https://login.microsoftonline.com/{TenantId_or_Name}) ou o terminal organizations.
  • Contas pessoais são convidadas a um locatário do Microsoft Entra não é possível usar ROPC.
  • Contas sem senhas não podem entrar com ROPC, ou seja, recursos como conexão por SMS, FIDO e o aplicativo Authenticator não funcionarão com esse fluxo.
  • Se os usuários precisarem usar a MFA (autenticação multifator) para fazer logon no aplicativo, eles serão bloqueados em vez disso.
  • Não há suporte para ROPC em cenários de federação de identidade híbrida, por exemplo, Microsoft Entra ID e Serviços de Federação do Active Directory (AD FS) usados para autenticar contas locais. Se os usuários forem redirecionados em página inteira para um provedor de identidade local, o Microsoft Entra ID não poderá testar o nome de usuário e a senha nesse provedor de identidade. No entanto, há suporte para a autenticação de passagem com o ROPC.
  • Uma exceção a um cenário de federação de identidade híbrida seria o seguinte: a política de Descoberta de Realm Inicial com AllowCloudPasswordValidation definido como TRUE permitirá que o fluxo ROPC funcione para usuários federados quando a senha local for sincronizada com a nuvem. Para obter mais informações, consulte Habilitar a autenticação ROPC direta de usuários federados para aplicativos herdados.

Criar um locatário de teste separado

Usar o fluxo de autenticação ROPC é arriscado em um ambiente de produção, portanto, crie um locatário separado para testar seus aplicativos. Você pode usar um locatário de teste existente, mas precisa ser um administrador no locatário, uma vez que algumas das etapas a seguir exigem privilégios de administrador.

Criar e configurar um cofre de chaves

Recomendamos que você armazene com segurança os nomes de usuário e as senhas de teste como segredos no Azure Key Vault. Quando você executar os testes posteriormente, os testes serão executados no contexto de uma entidade de segurança. A entidade de segurança é um usuário do Microsoft Entra se você estiver executando testes localmente (por exemplo, em Visual Studio ou Visual Studio Code) ou uma entidade de serviço ou identidade gerenciada se estiver executando testes em Azure Pipelines ou outro recurso do Azure. A entidade de segurança deve ter permissões de segredo Ler e Listar para que o executor de teste possa obter os nomes de usuário e as senhas de teste do cofre de chaves. Para saber mais, leia Autenticação no Azure Key Vault.

  1. Crie um novo cofre de chaves se você ainda não tiver um.
  2. Anote o valor da propriedade do URI do cofre (semelhante a https://<your-unique-keyvault-name>.vault.azure.net/), que é usado no exemplo de teste mais adiante neste artigo.
  3. Atribua uma política de acesso para a entidade de segurança que está executando os testes. Conceda permissões de segredo Obter e Listar ao usuário, à entidade de serviço ou à identidade gerenciada no cofre de chaves.

Criar usuários de teste

Dica

As etapas neste artigo podem variar ligeiramente com base no portal do qual você começa.

Crie alguns usuários de teste em seu locatário para testes. Como os usuários de teste não são humanos reais, recomendamos que você atribua senhas complexas e armazene essas senhas com segurança como segredos no Azure Key Vault.

  1. Entre no Centro de administração do Microsoft Entra como pelo menos Administrador de Aplicativo de nuvem.
  2. Navegue até Identidade>Usuários>Todos os usuários.
  3. Selecione Novo usuário e crie uma ou mais contas de usuário de teste em seu diretório.
  4. O exemplo de teste mais adiante neste artigo usa um único usuário de teste. Adicione o nome de usuário e a senha de teste como segredos no cofre de chaves que você criou anteriormente. Adicione o nome de usuário como um segredo chamado "TestUserName" e a senha como um segredo chamado "TestPassword".

Criar e configurar um registo de aplicação

Registre um aplicativo que atue como seu aplicativo cliente ao chamar APIs durante o teste. Ele não deve ser o mesmo aplicativo que talvez já esteja na produção. Você deve ter um aplicativo separado para usar apenas para fins de teste.

Registrar um aplicativo

Criar um registro de aplicativo. Você pode seguir as etapas no início rápido do registro do aplicativo. Você não precisa adicionar um URI de redirecionamento ou adicionar credenciais, então pode ignorar essas seções.

Anote a ID do aplicativo (cliente), que é usado no exemplo de teste mais adiante neste artigo.

Habilitar seu aplicativo para fluxos de cliente público

O ROPC é um fluxo de cliente público, portanto, você precisa habilitar seu aplicativo para fluxos de cliente público. No registro do seu aplicativo, no Centro de Administração do Microsoft Entra, vá para Autenticação>Configurações avançadas>Permitir fluxos de clientes públicos. Defina o botão de alternância como Sim.

Como o ROPC não é um fluxo interativo, não aparecerá uma tela de consentimento para você concordar no runtime. Pré-concorde com as permissões para evitar erros ao adquirir tokens.

Adicione as permissões ao aplicativo. Não adicione nenhuma permissão confidencial ou de alto privilégio ao aplicativo, recomendamos que você defina o escopo dos cenários de teste como cenários de integração básica em relação à integração com o Microsoft Entra ID.

No registro do seu aplicativo no Centro de Administração do Microsoft Entra, vá para Permissões da API>Adicionar uma permissão. Adicione as permissões necessárias para chamar as APIs que você usará. Um exemplo de teste mais adiante neste artigo usa as permissões https://graph.microsoft.com/User.Read e https://graph.microsoft.com/User.ReadBasic.All.

Depois que as permissões forem adicionadas, você precisará concordar com elas. A maneira como você concorda com as permissões depende de se o aplicativo de teste está no mesmo locatário que o registro do aplicativo e se você é um administrador no locatário.

O aplicativo e o registro de aplicativo estão no mesmo locatário e você é um administrador

Se você planeja testar seu aplicativo no mesmo locatário em que o registrou e se for um administrador desse locatário, você pode conceder as permissões a partir do Centro de administração do Microsoft Entra. Em seu registro de aplicativo no portal do Azure, acesse Permissões de API e selecione o botão Conceder consentimento de administrador para <your_tenant_name> ao lado do botão Adicionar uma permissão e, em seguida, Sim para confirmar.

O aplicativo e o registro de aplicativo estão em locatários diferentes, ou você não é um administrador

Se você não planeja testar seu aplicativo no mesmo locatário em que o registrou, ou se não é um administrador no seu locatário, você não pode conceder as permissões a partir do Centro Administrativo da Microsoft Entra. No entanto, você ainda pode concordar com algumas permissões disparando um prompt de entrada em um navegador da Web.

No registro do seu aplicativo, no Centro de Administração do Microsoft Entra, vá para Autenticação>Configurações de plataforma>Adicionar uma plataforma>Web. Adicionar o URI de redirecionamento "https://localhost" e selecione Configurar.

Não há como os usuários não administradores concordarem previamente com o portal do Azure, portanto, envie a solicitação a seguir em um navegador. Quando a tela de logon for solicitada, entre com uma conta de teste criada em uma etapa anterior. Concorde com as permissões solicitadas. Talvez seja necessário repetir esta etapa para cada API que você deseja chamar e testar o usuário que deseja usar.

// 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

Substitua {tenant} pela sua ID de locatário, {your_client_ID} pela ID do cliente do seu aplicativo e {resource_you_want_to_call} pelo URI do identificador (por exemplo, "https://graph.microsoft.com") ou a ID do aplicativo da API que você está tentando acessar.

Excluir aplicativos de teste e usuários da sua política de MFA

Provavelmente, seu locatário tem uma política de acesso condicional que requer MFA (autenticação multifator) para todos os usuários, conforme recomendado pela Microsoft. A MFA não funcionará com ROPC, portanto, você precisará isentar seus aplicativos de teste e testar os usuários com esse requisito.

Para excluir contas de usuário:

  1. Entre no Centro de administração do Microsoft Entra como pelo menos Administrador de Aplicativo de nuvem.
  2. Navegue até Identidade>Central de Segurança no painel de navegação esquerdo e selecione Acesso Condicional.
  3. Em Políticas, selecione a política de acesso condicional que exige MFA.
  4. Selecione Identidades dos usuários ou carga de trabalho.
  5. Selecione a guia Excluir e, em seguida, a caixa de seleção Usuários e grupos.
  6. Selecione as contas de usuário a serem excluídas em Selecionar usuários excluídos.
  7. Selecione o botão Selecionar e, em seguida, Salvar.

Para excluir um aplicativo de teste:

  1. Em Políticas, selecione a política de acesso condicional que exige MFA.
  2. Selecione Aplicativos na nuvem ou ações.
  3. Selecione a guia Excluir e, em seguida, Selecione aplicativos de nuvem excluídos.
  4. Selecione os aplicativos que deseja excluir em Selecionar aplicativos de nuvem excluídos.
  5. Selecione o botão Selecionar e, em seguida, Salvar.

Grave seus testes de aplicativo

Agora que a configuração está pronta, você pode gravar os testes automatizados. Os testes a seguir são para:

  1. O código de exemplo .NET usa a Biblioteca de Autenticação da Microsoft (MSAL) e xUnit, uma estrutura de teste comum.
  2. O código de exemplo JavaScript usa a Biblioteca de Autenticação da Microsoft (MSAL) e Playwright, uma estrutura de teste comum.

Configure o arquivo appsettings.json

Adicione a ID do cliente do aplicativo de teste criado anteriormente, os escopos necessários e o URI do cofre de chaves ao arquivo appsettings.json do seu projeto de teste.

{
  "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//"
  }
}

Configurar seu cliente para uso em todas as suas classes de teste

Use SecretClient() para obter os segredos de nome de usuário e senha de teste do Azure Key Vault. O código usa a retirada exponencial para novas tentativas, caso o Key Vault esteja sendo limitado.

DefaultAzureCredential() autentica-se com o Azure Key Vault ao obter um token de acesso de uma entidade de serviço configurada por variáveis de ambiente ou uma identidade gerenciada (se o código estiver em execução em um recurso do Azure com uma identidade gerenciada). Se o código estiver em execução localmente, DefaultAzureCredential usará as credenciais do usuário local. Leia mais no conteúdo Biblioteca de clientes da Identidade do Azure.

Use a MSAL (Biblioteca de Autenticação da Microsoft) para autenticar usando o fluxo ROPC e obter um token de acesso. O token de acesso é passado como um token de portador na solicitação 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;
}

Usar em suas classes de teste

O exemplo a seguir é um teste que chama o Microsoft Graph. Substitua esse teste por qualquer coisa que você gostaria de testar em seu próprio aplicativo ou 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);
    }
}