Eseguire test di integrazione automatizzati

Gli sviluppatori vogliono eseguire test di integrazione automatizzati nelle app sviluppate. La chiamata dell'API protetta da Microsoft Identity Platform (o altre API protette, ad esempio Microsoft Graph) nei test di integrazione automatizzati è una sfida. Microsoft Entra ID richiede spesso un prompt interattivo di accesso utente, che è difficile da automatizzare. Questo articolo descrive come usare un flusso non interattivo, denominato Concessione credenziali password del proprietario della risorsa (ROPC) per consentire l'accesso automatico degli utenti per i test.

Per preparare i test di integrazione automatizzati, creare alcuni utenti di test, creare e configurare una registrazione dell'app e apportare potenzialmente alcune modifiche di configurazione al tenant. Alcuni di questi passaggi richiedono privilegi di amministratore. Inoltre, Microsoft consiglia di non usare il flusso ROPC in un ambiente di produzione. Creare un tenant di test separato di cui si è amministratori in modo da poter eseguire in modo sicuro ed efficace i test di integrazione automatizzati.

Avviso

Microsoft consiglia di non usare il flusso ROPC in un ambiente di produzione. Nella maggior parte degli scenari di produzione sono disponibili e consigliate alternative più sicure. Il flusso ROPC richiede un livello di attendibilità molto elevato nell'applicazione e comporta rischi che non sono presenti in altri flussi di autenticazione. È consigliabile usare questo flusso solo a scopo di test in un tenant di test separato e solo con utenti di test.

Importante

  • Microsoft Identity Platform supporta solo ROPC nei tenant di Microsoft Entra, non gli account personali. Questo significa che è necessario usare un endpoint specifico del tenant (https://login.microsoftonline.com/{TenantId_or_Name}) o l'endpoint organizations.
  • Gli account personali che sono invitati in un tenant di Microsoft Entra non possono usare ROPC.
  • Gli account che non dispongono di password non possono accedere con ROPC, ovvero funzionalità come l'accesso TRAMITE SMS, FIDO e l'app Authenticator non funzioneranno con tale flusso.
  • Se gli utenti devono usare Multi-Factor Authentication (MFA) per accedere all'applicazione, saranno invece bloccati.
  • ROPC non è supportato negli scenari di federazione delle identità ibride(ad esempio, MICROSOFT Entra ID e Active Directory Federation Services (AD FS) usati per autenticare gli account locali. Se gli utenti vengono reindirizzati con l'intera pagina a un provider di identità locale, Microsoft Entra ID non riesce a verificare il nome utente e la password con tale provider di identità. L'autenticazione pass-through è tuttavia supportata con ROPC.
  • Un'eccezione a uno scenario di federazione di identità ibrida è la seguente: criteri di individuazione dell'area di autenticazione principale con AllowCloudPasswordValidation impostato su TRUE consentirà al flusso ROPC di lavorare per gli utenti federati quando la password locale viene sincronizzata nel cloud. Per altre informazioni, vedere Abilitare l'autenticazione ROPC diretta degli utenti federati per le applicazioni legacy.

Creare un tenant di test separato

L'uso del flusso di autenticazione ROPC è rischioso in un ambiente di produzione, quindi creare un tenant separato per testare le applicazioni. È possibile usare un tenant di test esistente, ma è necessario essere un amministratore nel tenant perché alcuni dei passaggi seguenti richiedono privilegi di amministratore.

Creare e configurare un insieme di credenziali delle chiavi

È consigliabile archiviare in modo sicuro i nomi utente e le password di test come segreti in Azure Key Vault. Quando si eseguono i test in un secondo momento, i test vengono eseguiti nel contesto di un'entità di sicurezza. L'entità di sicurezza è un utente di Microsoft Entra se si eseguono test in locale ,ad esempio in Visual Studio o Visual Studio Code, oppure un'entità servizio o un'identità gestita se si eseguono test in Azure Pipelines o in un'altra risorsa di Azure. L'entità di sicurezza deve disporre delle autorizzazioni Lettura ed Elenco dei segreti in modo che il test runner possa ottenere i nomi utente e le password di test dall'insieme di credenziali delle chiavi. Per altre informazioni, vedere Autenticazione in Azure Key Vault.

  1. Creare un nuovo insieme di credenziali delle chiavi se non ne è già disponibile uno.
  2. Prendere nota del valore della proprietà URI dell'insieme di credenziali (simile a https://<your-unique-keyvault-name>.vault.azure.net/) usato nel test di esempio più avanti in questo articolo.
  3. Assegnare un criterio di accesso per l'entità di sicurezza che esegue i test. Concedere all'utente, all'entità servizio o all'identità gestita le autorizzazioni Get and List secrets nell'insieme di credenziali delle chiavi.

Creare utenti di test

Suggerimento

I passaggi descritti in questo articolo possono variare leggermente in base al portale da cui si inizia.

Creare alcuni utenti di test nel tenant per il test. Poiché gli utenti di test non sono esseri umani effettivi, è consigliabile assegnare password complesse e archiviare queste password in modo sicuro come segreti in Azure Key Vault.

  1. Accedere all'interfaccia di amministrazione di Microsoft Entra come almeno un'applicazione cloud Amministrazione istrator.
  2. Passare a Utenti>identità>Tutti gli utenti.
  3. Selezionare Nuovo utente e creare uno o più account utente di test nella directory.
  4. Il test di esempio più avanti in questo articolo usa un singolo utente di test. Aggiungere il nome utente e la password di test come segreti nell'insieme di credenziali delle chiavi creato in precedenza. Aggiungere il nome utente come segreto denominato "TestUserName" e la password come segreto denominato "TestPassword".

Creare e configurare una registrazione app

Registrare un'applicazione che funge da app client quando si chiamano le API durante i test. Questa non deve essere la stessa applicazione già presente nell'ambiente di produzione. Devi avere un'app separata da usare solo a scopo di test.

Registrare un'applicazione

Crea una registrazione dell'app. È possibile seguire la procedura descritta nella guida introduttiva alla registrazione dell'app. Non è necessario aggiungere un URI di reindirizzamento o aggiungere credenziali, quindi è possibile ignorare tali sezioni.

Prendere nota dell'ID applicazione (client) usato nel test di esempio più avanti in questo articolo.

Abilitare l'app per i flussi client pubblici

ROPC è un flusso client pubblico, quindi è necessario abilitare l'app per i flussi client pubblici. Dalla registrazione dell'app nell'interfaccia di amministrazione di Microsoft Entra passare a Authentication>Advanced settings>Allow public client flows (Consenti flussi client pubblici). Impostare l'interruttore su .

Poiché ROPC non è un flusso interattivo, non verrà visualizzata una schermata di consenso per fornire il consenso a tali elementi in fase di esecuzione. Pre-consenso alle autorizzazioni per evitare errori durante l'acquisizione di token.

Aggiungere le autorizzazioni all'app. Non aggiungere autorizzazioni sensibili o con privilegi elevati all'app, è consigliabile definire l'ambito degli scenari di test in scenari di integrazione di base relativi all'integrazione con Microsoft Entra ID.

Dalla registrazione dell'app nell'interfaccia di amministrazione di Microsoft Entra passare a Autorizzazioni>API Aggiungere un'autorizzazione. Aggiungere le autorizzazioni necessarie per chiamare le API che si useranno. Un esempio di test più avanti in questo articolo usa le https://graph.microsoft.com/User.Read autorizzazioni e https://graph.microsoft.com/User.ReadBasic.All .

Dopo aver aggiunto le autorizzazioni, sarà necessario fornire il consenso. Il modo in cui si concede il consenso alle autorizzazioni dipende dal fatto che l'app di test si trovi nello stesso tenant della registrazione dell'app e se si è un amministratore nel tenant.

La registrazione di app e app si trova nello stesso tenant e si è un amministratore

Se si prevede di testare l'app nello stesso tenant in cui è stata registrata e si è un amministratore in tale tenant, è possibile fornire il consenso alle autorizzazioni dall'interfaccia di amministrazione di Microsoft Entra. Nella registrazione dell'app nel portale di Azure passare a Autorizzazioni API e selezionare il pulsante Concedi consenso amministratore per <your_tenant_name> accanto al pulsante Aggiungi un'autorizzazione e quindi per confermare.

La registrazione di app e app si trova in tenant diversi o non si è amministratori

Se non si prevede di testare l'app nello stesso tenant in cui è stata registrata o non si è un amministratore nel tenant, non è possibile concedere il consenso alle autorizzazioni dall'interfaccia di amministrazione di Microsoft Entra. È comunque possibile fornire il consenso ad alcune autorizzazioni attivando una richiesta di accesso in un Web browser.

Nella registrazione dell'app nell'interfaccia di amministrazione di Microsoft Entra passare a Configurazioni>della piattaforma di autenticazione>Aggiungi un Web della piattaforma.> Aggiungere l'URI di reindirizzamento "https://localhost" e selezionare Configura.

Non esiste alcun modo per gli utenti non amministratori di pre-consenso tramite il portale di Azure, quindi inviare la richiesta seguente in un browser. Quando viene visualizzata la schermata di accesso, accedere con un account di test creato in un passaggio precedente. Consenso alle autorizzazioni richieste. Potrebbe essere necessario ripetere questo passaggio per ogni API che si vuole chiamare e testare l'utente che si vuole usare.

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

Sostituire {tenant} con l'ID tenant, {your_client_ID} con l'ID client dell'applicazione e {resource_you_want_to_call} con l'URI dell'identificatore ,ad esempio "https://graph.microsoft.com") o ID app dell'API a cui si sta provando ad accedere.

Escludere app di test e utenti dai criteri di autenticazione a più fattori

Il tenant ha probabilmente un criterio di accesso condizionale che richiede l'autenticazione a più fattori (MFA) per tutti gli utenti, come consigliato da Microsoft. L'autenticazione a più fattori non funzionerà con ROPC, quindi sarà necessario esentare le applicazioni di test e gli utenti di test da questo requisito.

Per escludere gli account utente:

  1. Accedere all'interfaccia di amministrazione di Microsoft Entra come almeno un'applicazione cloud Amministrazione istrator.
  2. Passare al Centro sicurezza delle identità>nel riquadro di spostamento a sinistra e quindi selezionare Accesso condizionale.
  3. In Criteri selezionare i criteri di accesso condizionale che richiedono l'autenticazione a più fattori.
  4. Selezionare Utenti o identità del carico di lavoro.
  5. Selezionare la scheda Escludi e quindi la casella di controllo Utenti e gruppi .
  6. Selezionare gli account utente da escludere in Seleziona utenti esclusi.
  7. Selezionare il pulsante Seleziona e quindi Salva.

Per escludere un'applicazione di test:

  1. In Criteri selezionare i criteri di accesso condizionale che richiedono l'autenticazione a più fattori.
  2. Selezionare Applicazioni cloud o azioni.
  3. Selezionare la scheda Escludi e quindi Selezionare le app cloud escluse.
  4. Selezionare le app da escludere in Selezionare le app cloud escluse.
  5. Selezionare il pulsante Seleziona e quindi Salva.

Scrivere i test dell'applicazione

Dopo aver configurato, è possibile scrivere i test automatizzati. Di seguito sono riportati i test per:

  1. Il codice di esempio .NET usa Microsoft Authentication Library (MSAL) e xUnit, un framework di test comune.
  2. Il codice di esempio JavaScript usa Microsoft Authentication Library (MSAL) e Playwright, un framework di test comune.

Configurare il file appsettings.json

Aggiungere l'ID client dell'app di test creata in precedenza, gli ambiti necessari e l'URI dell'insieme di credenziali delle chiavi al file appsettings.json del progetto di test.

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

Configurare il client per l'uso in tutte le classi di test

Usare SecretClient() per ottenere i segreti del nome utente e della password di test da Azure Key Vault. Il codice usa il back-off esponenziale per i tentativi nel caso in cui Key Vault sia limitato.

DefaultAzureCredential() esegue l'autenticazione con Azure Key Vault ottenendo un token di accesso da un'entità servizio configurata dalle variabili di ambiente o da un'identità gestita (se il codice è in esecuzione in una risorsa di Azure con un'identità gestita). Se il codice è in esecuzione in locale, DefaultAzureCredential usa le credenziali dell'utente locale. Per altre informazioni, vedere il contenuto della libreria client di Azure Identity.

Usare Microsoft Authentication Library (MSAL) per eseguire l'autenticazione usando il flusso ROPC e ottenere un token di accesso. Il token di accesso viene passato come token di connessione nella richiesta 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;
}

Usare nelle classi di test

L'esempio seguente è un test che chiama Microsoft Graph. Sostituire questo test con quello che si vuole testare nell'applicazione o nell'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);
    }
}