Ejecución de pruebas de integración automatizadas

Como desarrollador, desea ejecutar pruebas de integración automatizadas en las aplicaciones que desarrolle. Llamar a la API protegida por Plataforma de identidad de Microsoft (u otras API protegidas como Microsoft Graph) en pruebas de integración automatizadas es un desafío. Microsoft Entra ID a menudo requiere un símbolo del sistema de inicio de sesión de usuario interactivo, que es difícil de automatizar. En este artículo se describe cómo puede usar un flujo no interactivo, denominado Concesión de credenciales de contraseña de propietario de recursos (ROPC), para iniciar automáticamente la sesión de los usuarios para realizar pruebas.

Para prepararse para las pruebas de integración automatizadas, cree algunos usuarios de prueba, cree y configure un registro de aplicaciones y, potencialmente, realice algunos cambios de configuración en el inquilino. Algunos de estos pasos requieren privilegios de administrador. Además, Microsoft recomienda no usar el flujo ROPC en un entorno de producción. Cree un inquilino de prueba independiente del que sea administrador para poder ejecutar de forma segura y eficaz las pruebas de integración automatizadas.

Advertencia

Además, Microsoft recomienda no usar el flujo ROPC en un entorno de producción. En la mayoría de los escenarios de producción, hay alternativas más seguras y recomendables. Este flujo de ROPC requiere un alto grado de confianza en la aplicación y conlleva riesgos que no están presentes en otros flujos de autenticación. Solo debe usar este flujo con fines de prueba en un inquilino de prueba independiente y solo con usuarios de prueba.

Importante

  • La plataforma de identidad de Microsoft solo admite ROPC para inquilinos de Microsoft Entra, no cuentas personales. Esto significa que debe usar un punto de conexión específico del inquilino (https://login.microsoftonline.com/{TenantId_or_Name}) o el punto de conexión organizations.
  • Las cuentas personales que se invitan a un inquilino de Microsoft Entra no pueden usar ROPC.
  • Las cuentas que no tienen contraseñas no pueden iniciar sesión con ROPC, lo que significa que características como el inicio de sesión por SMS, FIDO y la aplicación Authenticator no funcionarán con ese flujo.
  • Si los usuarios deben usar la autenticación multifactor (MFA) para iniciar sesión en la aplicación, se les bloqueará.
  • ROPC no se admite en escenarios de federación de identidades híbridas (por ejemplo, Microsoft Entra ID y Servicios de federación de Active Directory [AD FS] que se usan para autenticar cuentas locales). Si los usuarios se redirigen a página completa a un proveedor de identidades locales, Microsoft Entra ID no puede probar el nombre de usuario y la contraseña en el proveedor de identidades. Sin embargo, la autenticación transferida se admite con ROPC.
  • Una excepción a un escenario de federación de identidades híbrida sería la siguiente: la directiva de detección del dominio principal con el valor de AllowCloudPasswordValidation establecido en TRUE permitirá que el flujo de ROPC funcione para los usuarios federados cuando la contraseña local se sincronice con la nube. Para más información, consulte Habilitación de la autenticación de ROPC directa de los usuarios federados para aplicaciones heredadas.

Creación de un inquilino de prueba independiente

El uso del flujo de autenticación ROPC es arriesgado en un entorno de producción, por lo que debe crear un inquilino independiente para probar las aplicaciones. Puede usar un inquilino de prueba existente, pero debe ser administrador en el inquilino, ya que algunos de los pasos siguientes requieren privilegios de administrador.

Crear y configurar un almacén de claves

Se recomienda almacenar de forma segura los nombres de usuario y contraseñas de prueba como secretos en Azure Key Vault. Cuando se ejecutan las pruebas más adelante, las pruebas se ejecutan en el contexto de una entidad de seguridad. La entidad de seguridad es un usuario de Microsoft Entra si está ejecutando pruebas localmente (por ejemplo, en Visual Studio o Visual Studio Code), o una entidad de servicio o una identidad administrada si está ejecutando pruebas en Azure Pipelines u otro recurso de Azure. La entidad de seguridad debe tener permisos de lectura y enumeración de secretos para que el ejecutor de pruebas pueda obtener los nombres de usuario y contraseñas de prueba del almacén de claves. Para obtener más información, consulte Autenticación en Azure Key Vault.

  1. Cree un nuevo almacén de claves si aún no tiene uno.
  2. Tome nota del valor de la propiedad URI del almacén (similar a https://<your-unique-keyvault-name>.vault.azure.net/) que se usa en la prueba de ejemplo más adelante en este artículo.
  3. Asigne una directiva de acceso para la entidad de seguridad que ejecuta las pruebas. Conceda permisos para obtener y enumerar secretos al usuario, la entidad de servicio o la identidad administrada en el almacén de claves.

Creación de usuarios de prueba

Sugerencia

Los pasos de este artículo pueden variar ligeramente en función del portal desde donde comienza.

Cree algunos usuarios de prueba en el inquilino para realizar pruebas. Puesto que los usuarios de prueba no son humanos reales, se recomienda asignar contraseñas complejas y almacenar estas contraseñas de forma segura como secretos en Azure Key Vault.

  1. Inicie sesión en el Centro de administración de Microsoft Entra como Administrador de aplicaciones en la nube.
  2. Vaya aIdentidad>Usuarios>Todos los usuarios.
  3. Seleccione Nuevo usuario y cree una o varias cuentas de usuario de prueba en el directorio.
  4. En la prueba de ejemplo que se muestra más adelante en este artículo se usa un usuario de prueba único. Agregue el nombre de usuario y la contraseña de prueba como secretos en el almacén de claves que creó anteriormente. Agregue el nombre de usuario como un secreto denominado "TestUserName" y la contraseña como un secreto denominado "TestPassword".

Creación y configuración del registro de una aplicación

Registre una aplicación que actúe como aplicación cliente al llamar a las API durante las pruebas. Esta no debe ser la misma aplicación que tenga en producción. Debe tener una aplicación independiente para usarla solo con fines de prueba.

Registro de una aplicación

Crear un registro de aplicación. Puede seguir los pasos descritos en la guía de inicio rápido de registro de aplicaciones. No es necesario agregar un URI de redirección ni agregar credenciales, por lo que puede omitir esas secciones.

Tome nota del id. de la aplicación (cliente), que se usa en la prueba de ejemplo más adelante en este artículo.

Habilitación de la aplicación para flujos de cliente públicos

ROPC es un flujo de cliente público, por lo que debe habilitar la aplicación para los flujos de cliente públicos. Desde el registro de la aplicación del Centro de administración de Microsoft Entra, vaya a Autenticación>Configuración avanzada>Permitir flujos de cliente públicos. Establezca el botón de alternancia en .

Puesto que ROPC no es un flujo interactivo, no se le pedirá una pantalla de consentimiento para dar su consentimiento en tiempo de ejecución. Dar su consentimiento previo a los permisos para evitar errores al adquirir tokens.

Agregue permisos a la aplicación. No agregue ningún permiso confidencial o con privilegios elevados a la aplicación, se recomienda que los escenarios de pruebas se alejen de escenarios de integración básicos en torno a la integración con Microsoft Entra ID.

Desde el registro de la aplicación del Centro de administración de Microsoft Entra, vaya a Permisos de API>Agregar un permiso. Agregue los permisos necesarios para llamar a las API que va a usar. En un ejemplo de prueba más adelante en este artículo se usan los permisos https://graph.microsoft.com/User.Read y https://graph.microsoft.com/User.ReadBasic.All.

Una vez agregados los permisos, deberá dar su consentimiento. La forma de dar su consentimiento a los permisos depende de si la aplicación de prueba está en el mismo inquilino que el registro de la aplicación y de si es un administrador del inquilino.

La aplicación y el registro de la aplicación se encuentran en el mismo inquilino y usted es un administrador

Si planea probar la aplicación en el mismo inquilino en el que la registró y es administrador de ese inquilino, puede dar su consentimiento a los permisos del Centro de administración de Microsoft Entra. En el registro de la aplicación en el Azure Portal, vaya a Permisos de API y seleccione el botón Conceder consentimiento de administrador para<your_tenant_name> junto al botón Agregar un permiso y, después, para confirmar.

La aplicación y el registro de la aplicación se encuentran en inquilinos diferentes o no es un administrador

Si no planea probar la aplicación en el mismo inquilino en el que la registró o no es administrador de ese inquilino, no podrá dar su consentimiento a los permisos desde el Centro de administración de Microsoft Entra. Sin embargo, puede dar su consentimiento a algunos permisos mediante el desencadenamiento de un mensaje de inicio de sesión en un explorador web.

En el registro de la aplicación del Centro de administración de Microsoft Entra, vaya a Autenticación>Configuración de la plataforma>Agregar una plataforma>Web. Agregue el URI de redirección "https://localhost" y seleccione Configurar.

No hay ninguna manera de que los usuarios que no son administradores den su consentimiento previamente a través del Azure Portal, por lo que debe enviar la siguiente solicitud en un explorador. Cuando se aparezca la pantalla de inicio de sesión, inicie sesión con la cuenta de prueba que creó en un paso anterior. Dé su consentimiento a los permisos que le solicitan. Es posible que tenga que repetir este paso para cada API que quiera llamar y probar al usuario que quiera 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

Sustituya {tenant} por el id. del inquilino, {your_client_ID} por el id. de cliente de la aplicación, y {resource_you_want_to_call} por el URI identificador (por ejemplo, "https://graph.microsoft.com") o el id. de la aplicación de la API a la que intenta acceder.

Exclusión de aplicaciones y usuarios de prueba de la directiva de MFA

Es probable que el inquilino tenga una directiva de acceso condicional que requiera autenticación multifactor (MFA) para todos los usuarios, tal y como recomienda Microsoft. MFA no funcionará con ROPC, por lo que deberá excluir las aplicaciones de prueba y probar a los usuarios de este requisito.

Para excluir cuentas de usuario:

  1. Inicie sesión en el Centro de administración de Microsoft Entra como Administrador de aplicaciones en la nube.
  2. Vaya a Identidad>Security Center en el panel de navegación izquierdo y, a continuación, seleccione Acceso condicional.
  3. En Directivas, seleccione la directiva de acceso condicional que requiera MFA.
  4. Seleccione Usuarios o identidades de la carga de trabajo.
  5. Active la pestaña Excluir y, a continuación, la casilla Usuarios y grupos.
  6. Seleccione las cuentas de usuario que desea excluir en Seleccionar usuarios excluidos.
  7. Seleccione el botón Seleccionar y, a continuación, Guardar.

Para excluir una aplicación de prueba:

  1. En Directivas, seleccione la directiva de acceso condicional que requiera MFA.
  2. Seleccione Aplicaciones en la nube o acciones.
  3. Seleccione la pestaña Excluir y, a continuación, Seleccionar aplicaciones en la nube excluidas.
  4. Seleccione las aplicaciones que desea excluir en Seleccionar aplicaciones en la nube excluidas.
  5. Seleccione el botón Seleccionar y, a continuación, Guardar.

Escriba las pruebas de aplicación

Ahora que está configurado, puede escribir las pruebas automatizadas. A continuación se muestran las pruebas para:

  1. El código de ejemplo de .NET usa la Biblioteca de autenticación de Microsoft (MSAL) y xUnit, un marco de pruebas común.
  2. El código de ejemplo de JavaScript usa la Biblioteca de autenticación de Microsoft (MSAL) y Playwright, un marco de pruebas común.

Configuración del archivo appsettings.json

Agregue el identificador de cliente de la aplicación de prueba que creó anteriormente, los ámbitos necesarios y el URI del almacén de claves al archivo appsettings.json del proyecto de prueba.

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

Configuración del cliente para su uso en todas las clases de prueba

Use SecretClient() para obtener los secretos de nombre de usuario y contraseña de prueba de Azure Key Vault. El código utiliza el retroceso exponencial para los reintentos en el caso de que se limite el almacén de claves.

DefaultAzureCredential() se autentica con Azure Key Vault al obtener un token de acceso de una entidad de servicio configurada por variables de entorno o una identidad administrada (si el código se ejecuta en un recurso de Azure con una identidad administrada). Si el código se ejecuta localmente, DefaultAzureCredential usa las credenciales del usuario local. Obtenga más información en el contenido de la Biblioteca cliente de Azure Identity.

Use la Biblioteca de autenticación de Microsoft (MSAL) para autenticarse mediante el flujo ROPC y obtener un token de acceso. El token de acceso se pasa como un token de portador en la solicitud 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;
}

Uso en las clases de prueba

El ejemplo siguiente es una prueba que llama a Microsoft Graph. Reemplace esta prueba por lo que quiera probar en su propia aplicación o 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);
    }
}