Migración de aplicaciones cliente confidenciales de ADAL.NET a MSAL.NET

En este artículo se describe cómo migrar una aplicación cliente confidencial de la Biblioteca de autenticación de Azure Active Directory para .NET (ADAL.NET) a la Biblioteca de autenticación de Microsoft para .NET (MSAL.NET). Las aplicaciones cliente confidenciales son aplicaciones web, API web y aplicaciones de demonio que llaman a otro servicio en su propio nombre. Para más información sobre las aplicaciones confidenciales, consulte Flujos de autenticación y escenarios de aplicaciones. Si la aplicación se basa en ASP.NET Core, use Microsoft.Identity.Web.

Para los registros de aplicaciones:

  • No es necesario crear un nuevo registro de aplicaciones (se mantiene el mismo identificador de cliente).
  • No es necesario cambiar las autorizaciones previas (permisos de API con consentimiento del administrador).

Pasos de migración

  1. Busque el código mediante ADAL.NET en la aplicación.

    El código que usa ADAL en una aplicación cliente confidencial crea instancias de AuthenticationContext y llama a AcquireTokenByAuthorizationCode o a una invalidación de AcquireTokenAsync con los parámetros siguientes:

    • Cadena de resourceId. Esta variable es el URI del identificador de la aplicación de la API web a la que desea llamar.
    • Instancia de IClientAssertionCertificate o ClientAssertion. Esta instancia proporciona las credenciales de cliente de la aplicación para demostrar la identidad de esta.
  2. Tras haber identificado que tiene aplicaciones que usan ADAL.NET, instale el paquete NuGet de MSAL.NET Microsoft.Identity.Client y actualice sus referencias de la biblioteca de proyectos. Para obtener más información, consulte cómo instalar un paquete NuGet. Si quiere usar serializadores de caché de tokens, instale también Microsoft.Identity.Web.TokenCache.

  3. Actualice el código según el escenario de cliente confidencial. Algunos pasos son comunes y se aplican en todos los escenarios de cliente confidenciales. Otros pasos son únicos para cada escenario.

    Los escenarios de cliente confidenciales son:

Podría haber proporcionado un contenedor en torno a ADAL.NET para controlar los certificados y el almacenamiento en caché. En este artículo se usa el mismo enfoque para mostrar el proceso de migración de ADAL.NET a MSAL.NET. Sin embargo, este código solo tiene fines de demostración. No copie ni pegue estos contenedores ni los integre en el código tal como están.

Migración de aplicaciones de demonio

Los escenarios de demonio usan el flujo de credenciales de cliente de OAuth2.0. También se denominan llamadas de servicio a servicio. La aplicación adquiere un token en su propio nombre, no en nombre de un usuario.

Averiguar si el código usa escenarios de demonio

El código ADAL de la aplicación usa escenarios de demonio si contiene una llamada a AuthenticationContext.AcquireTokenAsync con los parámetros siguientes:

  • Un recurso (URI del identificador de la aplicación) como primer parámetro
  • IClientAssertionCertificate o ClientAssertion como segundo parámetro

AuthenticationContext.AcquireTokenAsync no tiene un parámetro de tipo UserAssertion. Si lo tiene, entonces la aplicación es una API web y usa el escenario de API web que llama a las API web de nivel inferior.

Actualización del código de escenarios de demonio

Los pasos siguientes para actualizar el código se aplican en todos los escenarios de cliente confidenciales:

  1. Agregue el espacio de nombres MSAL.NET en el código fuente: using Microsoft.Identity.Client;.
  2. En lugar de crear instancias de AuthenticationContext, use ConfidentialClientApplicationBuilder.Create para crear instancias de IConfidentialClientApplication.
  3. En lugar de la cadena resourceId, MSAL.NET usa ámbitos. Dado que las aplicaciones que usan ADAL.NET están preautorizadas, siempre puede usar los siguientes ámbitos: new string[] { $"{resourceId}/.default" }.
  4. Reemplace la llamada a AuthenticationContext.AcquireTokenAsync por una llamada a IConfidentialClientApplication.AcquireTokenXXX, donde AuthenticationContext.AcquireTokenAsync depende de su escenario.

En este caso, reemplazamos la llamada a AuthenticationContext.AcquireTokenAsync por una llamada a IConfidentialClientApplication.AcquireTokenClient.

Esta es una comparación del código ADAL.NET y MSAL.NET de escenarios de demonio:

ADAL

MSAL

using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;

public partial class AuthWrapper
{
const string ClientId = "Guid (AppID)";
const string authority 
= "https://login.microsoftonline.com/{tenant}";
// App ID URI of web API to call
const string resourceId = "https://target-api.domain.com";
X509Certificate2 certificate = LoadCertificate();



public async Task<AuthenticationResult> GetAuthenticationResult()
{


var authContext = new AuthenticationContext(authority);
var clientAssertionCert = new ClientAssertionCertificate(
ClientId,
certificate);


var authResult = await authContext.AcquireTokenAsync(
resourceId,
clientAssertionCert,
);

return authResult;
}
}
using Microsoft.Identity.Client;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;

public partial class AuthWrapper
{
const string ClientId = "Guid (Application ID)";
const string authority 
= "https://login.microsoftonline.com/{tenant}";
// App ID URI of web API to call
const string resourceId = "https://target-api.domain.com";
X509Certificate2 certificate = LoadCertificate();

IConfidentialClientApplication app;

public async Task<AuthenticationResult> GetAuthenticationResult()
{
if (app == null)
{
app = ConfidentialClientApplicationBuilder.Create(ClientId)
.WithCertificate(certificate)
.WithAuthority(authority)
.Build();
}

var authResult = await app.AcquireTokenForClient(
new [] { $"{resourceId}/.default" })
// .WithTenantId(specificTenant)
// See https://aka.ms/msal.net/withTenantId
.ExecuteAsync()
.ConfigureAwait(false);

return authResult;
}
}

Beneficiarse del almacenamiento en caché de tokens

Para beneficiarse de la caché en memoria, la instancia de IConfidentialClientApplication debe mantenerse en una variable de miembro. Si vuelve a crear la aplicación cliente confidencial cada vez que solicite un token, no se beneficiará de la caché de tokens.

Tendrá que serializar AppTokenCache si decide no usar la caché de tokens de aplicación en memoria predeterminada. Del mismo modo, si desea implementar una caché de tokens distribuida, deberá serializar AppTokenCache. Para obtener detalles, consulte el artículo sobre la caché de tokens para una aplicación web o API web (aplicación cliente confidencial) y el ejemplo active-directory-dotnet-v1-to-v2/ConfidentialClientTokenCache.

Obtenga más información sobre el escenario de demonio y cómo se implementa con MSAL.NET o Microsoft.Identity.Web en las aplicaciones nuevas.

Ventajas de MSAL

Entre las principales ventajas de MSAL.NET para la aplicación se incluyen las siguientes:

  • Resistencia. MSAL.NET ayuda a que la aplicación sea resistente a través de lo siguiente:

    • Ventajas del servicio de credenciales almacenadas en caché (CCS) de Azure AD. CCS funciona como una copia de seguridad de Azure AD.
    • Renovación proactiva de tokens si la API a la que llama habilita tokens de larga duración a través de Evaluación continua de acceso.
  • Seguridad. Puede adquirir tokens de prueba de posesión (PoP) si la API web a la que desea llamar así lo requiere. Para obtener detalles, consulte Tokens de prueba de posesión en MSAL.NET

  • Rendimiento y escalabilidad. Si no necesita compartir la caché con ADAL.NET, deshabilite la compatibilidad de la memoria caché heredada al crear la aplicación cliente confidencial (.WithLegacyCacheCompatibility(false)). Esto aumenta significativamente el rendimiento.

    app = ConfidentialClientApplicationBuilder.Create(ClientId)
            .WithCertificate(certificate)
            .WithAuthority(authority)
            .WithLegacyCacheCompatibility(false)
            .Build();
    

Solución de problemas

MsalServiceException

La siguiente información de solución de problemas hace dos suposiciones:

  • El código ADAL.NET estaba funcionando.
  • Migró a MSAL manteniendo el mismo identificador de cliente.

Si recibe una excepción con cualquiera de los mensajes siguientes:

AADSTS700027: Client assertion contains an invalid signature. [Reason - The key was not found.]

AADSTS90002: Tenant 'cf61953b-e41a-46b3-b500-663d279ea744' not found. This may happen if there are no active subscriptions for the tenant. Check to make sure you have the correct tenant ID. Check with your subscription administrator.

Puede solucionar problemas de la excepción mediante estos pasos:

  1. Confirme que usa la versión más reciente de MSAL.NET.
  2. Confirme que el host de autoridad que estableció al compilar la aplicación cliente confidencial y el host de autoridad que usó con ADAL son similares. En concreto, ¿es la misma nube (Azure Government, Azure China 21Vianet o Azure Alemania)?

MsalClientException

En las aplicaciones multiinquilino, puede tener escenarios en los que especifique una autoridad común al compilar la aplicación, pero luego quiera tener como destino un inquilino específico (por ejemplo, el del usuario) al llamar a una API web. Desde MSAL.NET 4.37.0, al especificar .WithAzureRegion al crear la aplicación, ya no puede especificar la autoridad mediante .WithAuthority durante las solicitudes de token. Si lo hace, se producirá el siguiente error al actualizar desde versiones anteriores de MSAL.NET:

MsalClientException - "You configured WithAuthority at the request level, and also WithAzureRegion. This is not supported when the environment changes from application to request. Use WithTenantId at the request level instead."

Para corregir este problema, reemplace .WithAuthority en la expresión AcquireTokenXXX por .WithTenantId. Especifique el inquilino mediante un GUID o un nombre de dominio.

Pasos siguientes

Más información sobre: