Diferencias entre las aplicaciones de ADAL.NET y MSAL.NET

Migrar las aplicaciones del uso de ADAL al uso de MSAL incluye ventajas de seguridad y resistencia. En este artículo se describen las diferencias entre MSAL.NET y ADAL.NET. En la mayoría de los casos querrá usar MSAL.NET y la Plataforma de identidad de Microsoft, que es la última generación de bibliotecas de autenticación de Microsoft. Mediante MSAL.NET adquiere tokens para los usuarios que inician sesión en su aplicación con Azure AD (cuentas profesionales y educativas), cuentas (personales) Microsoft (MSA) o Azure AD B2C.

Si ya está familiarizado con ADAL.NET y el punto de conexión de Azure AD para desarrolladores (v1.0), descubra qué tiene de diferente la Plataforma de identidad de Microsoft. Aun así deberá usar ADAL.NET si en la aplicación van a iniciar sesión usuarios con versiones anteriores de Servicios de federación de Active Directory (ADFS). Para más información, consulte al soporte técnico de Azure.

ADAL NET MSAL NET
Espacios de nombres y paquetes NuGet ADAL se consumió desde el paquete NuGet Microsoft.IdentityModel.Clients.ActiveDirectory. El espacio de nombres era Microsoft.IdentityModel.Clients.ActiveDirectory. Agregue el paquete NuGet Microsoft.Identity.Client y use el espacio de nombres Microsoft.Identity.Client. Si va a compilar una aplicación cliente confidencial, consulte Microsoft.Identity.Web.
Ámbitos y recursos ADAL.NET adquiere tokens para los recursos. MSAL.NET adquiere tokens para los ámbitos. Algunas invalidaciones de AcquireTokenXXX de MSAL.NET requieren un parámetro denominado scopes (IEnumerable<string> scopes). Este parámetro no es más que una lista de cadenas que declaran los permisos y recursos que se solicitan. Los ámbitos de Microsoft Graph son muy conocidos. También puede acceder a los recursos de la versión 1.0 con MSAL.NET.
Clases principales ADAL.NET usó AuthenticationContext como representación de la conexión al servidor de autorización o al servicio de token de seguridad (STS), a través de una autoridad. MSAL.NET está diseñado en torno a aplicaciones cliente. Define interfaces IPublicClientApplication para aplicaciones cliente públicas e interfaces IConfidentialClientApplication para aplicaciones cliente confidenciales, así como una interfaz base IClientApplicationBase para el contrato común a ambos tipos de aplicaciones.
Obtención de tokens En los clientes públicos, ADAL usa AcquireTokenAsync y AcquireTokenSilentAsync para las llamadas de autenticación. En los clientes públicos, MSAL usa AcquireTokenInteractive y AcquireTokenSilent para las mismas llamadas de autenticación. Los parámetros son distintos de los usados en ADAL.

En las aplicaciones cliente confidenciales, hay métodos de adquisición de tokens con un nombre explícito en función del escenario. Otra diferencia es que, en MSAL.NET, no es preciso usar el elemento ClientID de la aplicación en todas las llamadas a AcquireTokenXX. El valor ClientID se establece una sola vez al compilar IPublicClientApplication o IConfidentialClientApplication.
IAccount e IUser ADAL define la noción de usuario a través de la interfaz IUser. Sin embargo, un usuario es una persona o un agente de software. Como tal, un usuario puede tener una o varias cuentas en la Plataforma de identidad de Microsoft (varias cuentas de Azure AD, Azure AD B2C, cuentas personales de Microsoft). El usuario también puede ser responsable de una o varias cuentas de la Plataforma de identidad de Microsoft. MSAL.NET define el concepto de cuenta (a través de la interfaz de IAccount). La interfaz IAccount representa información sobre una sola cuenta. El usuario puede tener varias cuentas en distintos inquilinos. MSAL.NET proporciona mejor información en escenarios de invitado, cuando se proporciona información de la cuenta doméstica. Lea más detalles sobre las diferencias entre IUser e IAccount.
Persistencia en la caché ADAL.NET le permite ampliar la clase TokenCache para implementar la funcionalidad de persistencia deseada en las plataformas sin un almacenamiento seguro (.NET Framework y .NET Core) mediante el uso de los métodos BeforeAccess y BeforeWrite. Para obtener más información, consulte la sección sobre la serialización de la memoria caché de tokens en ADAL.NET. MSAL.NET hace que la caché de tokens sea una clase sellada y elimina la posibilidad de ampliarla. De esta forma, la implementación de la persistencia en la caché de tokens debe ser en forma de clase auxiliar que interactúa con la caché de tokens sellada. Esta interacción se describe en el documento sobre la serialización de la memoria caché de tokens en MSAL.NET. La serialización para una aplicación cliente pública (consulte el apartado sobre la caché de tokens para una aplicación cliente pública) es distinta a la de una aplicación cliente confidencial (consulte el apartado sobre la caché de tokens para una aplicación web o API web).
Autoridad común ADAL usa Azure AD v1.0. La autoridad https://login.microsoftonline.com/common en Azure AD v1.0 (que usa ADAL) permite a los usuarios iniciar sesión con cualquier cuenta de organización de AAD (profesional o educativa). Azure AD v1.0 no permite el inicio de sesión con cuentas personales de Microsoft. Para obtener más información, consulte el documento sobre validación de autoridad en ADAL.NET. MSAL usa Azure AD v2.0. La autoridad https://login.microsoftonline.com/common de Azure AD v2.0 (que usa MSAL) permite a los usuarios iniciar sesión con cualquier cuenta de organización de AAD (profesional o educativa) o con una cuenta personal de Microsoft. Para restringir el inicio de sesión solo con cuentas de organización (cuentas profesionales o educativas) en MSAL, deberá usar el punto de conexión https://login.microsoftonline.com/organizations. Para más información, consulte el parámetro authority en la aplicación cliente pública.

Concesiones que se admiten

A continuación se muestra un resumen en el que se comparan las concesiones admitidas de MSAL.NET y ADAL.NET para las aplicaciones cliente tanto públicas como confidenciales.

Aplicaciones cliente públicas

La imagen siguiente resume algunas de las diferencias entre ADAL.NET y MSAL.NET para una aplicación cliente pública.

Captura de pantalla que muestra algunas de las diferencias entre ADAL.NET y MSAL.NET para una aplicación cliente pública.

Estas son las concesiones que se admiten en ADAL.NET y MSAL.NET para aplicaciones de escritorio y para dispositivos móviles.

Conceder MSAL.NET ADAL.NET
Interactive Adquisición de tokens de forma interactiva en MSAL.NET Autenticación interactiva
Autenticación integrada de Windows Autenticación integrada de Windows Autenticación integrada en Windows (Kerberos)
Nombre de usuario y contraseña Autenticación con nombre de usuario y contraseña Adquisición de tokens con nombre de usuario y contraseña
Flujo de código de dispositivo Flujo de código de dispositivo Perfil de dispositivo para dispositivos sin exploradores web

Aplicaciones cliente confidenciales

La imagen siguiente resume algunas de las diferencias entre ADAL.NET y MSAL.NET para una aplicación cliente confidencial.

Captura de pantalla que muestra algunas de las diferencias entre ADAL.NET y MSAL.NET para una aplicación cliente confidencial.

Estas son las concesiones que se admiten en ADAL.NET, MSAL.NET y Microsoft.Identity.Web para aplicaciones web, API web y aplicaciones de demonio.

Tipo de aplicación Conceder MSAL.NET ADAL.NET
Aplicación web, API web, demonio Credenciales de cliente Flujos de credenciales de cliente en MSAL.NET Flujos de credenciales de cliente en ADAL.NET
API Web En nombre de En nombre de MSAL.NET Llamadas de servicio a servicio en nombre del usuario con ADAL.NET
Aplicación web Código de autenticación Adquisición de tokens con códigos de autorización en aplicaciones web con MSAL.NET Adquisición de tokens con códigos de autorización en aplicaciones web con ADAL.NET

Migración desde ADAL 2.x con tokens de actualización

En ADAL.NET v2.X, se han expuesto los tokens de actualización, lo que le permite desarrollar soluciones en torno al uso de estos tokens mediante su almacenamiento en caché y el uso de los AcquireTokenByRefreshToken que proporciona ADAL 2.x.

Algunas de estas soluciones se han usado en escenarios como:

  • Servicios de larga duración que realizan acciones, incluida la actualización de paneles para los usuarios cuando estos ya no están conectados o no han iniciado sesión en la aplicación.
  • Escenarios de WebFarm que permiten al cliente llevar el token de actualización al servicio web (el almacenamiento en caché se realiza en el lado cliente, con la cookie cifrada, y no en el del servidor).

Por motivos de seguridad, MSAL.NET no expone los tokens de actualización. MSAL los administra automáticamente.

Afortunadamente, MSAL.NET tiene una API que permite migrar los tokens de actualización anteriores (adquiridos con ADAL) a IConfidentialClientApplication:

/// <summary>
/// Acquires an access token from an existing refresh token and stores it and the refresh token into
/// the application user token cache, where it will be available for further AcquireTokenSilent calls.
/// This method can be used in migration to MSAL from ADAL v2 and in various integration
/// scenarios where you have a RefreshToken available.
/// (see https://aka.ms/msal-net-migration-adal2-msal2)
/// </summary>
/// <param name="scopes">Scope to request from the token endpoint.
/// Setting this to null or empty will request an access token, refresh token and ID token with default scopes</param>
/// <param name="refreshToken">The refresh token from ADAL 2.x</param>
IByRefreshToken.AcquireTokenByRefreshToken(IEnumerable<string> scopes, string refreshToken);

Con este método puede proporcionar el token de actualización que ha usado anteriormente junto con todos los ámbitos (recursos) que quiera. El token de actualización se intercambiará por otro nuevo y se almacenará en caché en la aplicación.

Como este método está pensado para escenarios que no son habituales, no se puede acceder a él de inmediato con IConfidentialClientApplication sin convertirlo primero en IByRefreshToken.

El fragmento de código a continuación muestra código de migración en una aplicación cliente confidencial.

TokenCache userCache = GetTokenCacheForSignedInUser();
string rt = GetCachedRefreshTokenForSignedInUser();

IConfidentialClientApplication app;
app = ConfidentialClientApplicationBuilder.Create(clientId)
 .WithAuthority(Authority)
 .WithRedirectUri(RedirectUri)
 .WithClientSecret(ClientSecret)
 .Build();
IByRefreshToken appRt = app as IByRefreshToken;

AuthenticationResult result = await appRt.AcquireTokenByRefreshToken(null, rt)
                                         .ExecuteAsync()
                                         .ConfigureAwait(false);

GetCachedRefreshTokenForSignedInUser recupera el token de actualización que almacenó de alguna forma una versión anterior de la aplicación que utilizaba ADAL 2.x. GetTokenCacheForSignedInUser deserializa una cache para el usuario que ha iniciado sesión (ya que las aplicaciones cliente confidenciales deben tener una sola caché por usuario).

Un token de acceso y un token de identificador se devuelven en el valor AuthenticationResult mientras que el nuevo token de actualización se almacena en la memoria caché. Este método también se puede usar para diversos escenarios de integración en los que hay un token de actualización disponible.

Tokens de las versiones 1.0 y 2.0

Hay dos versiones de los tokens: v1.0 y v2.0. El punto de conexión de v1.0 (que usa ADAL) emite tokens de identificador de v1.0, mientras que el punto de conexión de v2.0 (que usa MSAL) emite tokens de identificador de v2.0. Sin embargo, ambos puntos de conexión emiten tokens de acceso de la versión del token que la API web acepta. Una propiedad del manifiesto de aplicación de la API web permite a los desarrolladores elegir la versión del token que se acepta. Consulte accessTokenAcceptedVersion en la documentación de referencia del manifiesto de aplicación.

Para obtener más información sobre los tokens de acceso de las versiones 1.0 y 2.0, consulte el documento sobre tokens de acceso de Azure Active Directory.

Excepciones

Excepciones requeridas en la interacción

Mediante MSAL.NET se detecta MsalUiRequiredException, como se describe en AcquireTokenSilent.

catch(MsalUiRequiredException exception)
{
 try {"try to authenticate interactively"}
}

Para obtener más detalles, consulte Control de errores y excepciones en MSAL.NET

ADAL.NET tiene excepciones menos explícitas. Por ejemplo, cuando se produce un error de autenticación en modo silencioso en ADAL, el procedimiento es detectar la excepción y buscar el código de error user_interaction_required:

catch(AdalException exception)
{
 if (exception.ErrorCode == "user_interaction_required")
 {
  try
  {“try to authenticate interactively”}}
 }
}

Para obtener más detalles, consulte el patrón recomendado para adquirir un token en aplicaciones cliente públicas con ADAL.NET.

Comportamiento de la petición

El comportamiento de la petición en MSAL.NET es equivalente al comportamiento de la petición ADAL.NET:

ADAL.NET MSAL.NET Descripción
PromptBehavior.Auto NoPrompt Azure AD elige el mejor comportamiento (usuarios que inician sesión de manera silenciosa si inician sesión solo con una cuenta, o mostrar el selector de cuentas si inician sesión con varias cuentas).
PromptBehavior.Always ForceLogin Restablece el cuadro de inicio de sesión y obliga al usuario a volver a escribir sus credenciales.
PromptBehavior.RefreshSession Consent Obliga al usuario a dar nuevamente su consentimiento a todos los permisos.
PromptBehavior.Never Never No lo use; en su lugar, utilice el patrón recomendado para aplicaciones cliente públicas.
PromptBehavior.SelectAccount SelectAccount Muestra el selector de cuentas y obliga al usuario a seleccionar una cuenta.

Controlar las excepciones en los desafíos de notificaciones

En ocasiones, al adquirir un token, Azure AD produce una excepción en caso de que un recurso requiera más notificaciones del usuario (por ejemplo, la autenticación en dos fases).

En MSAL.NET, las excepciones en los desafíos de notificaciones se controlan de la siguiente forma:

  • Claims se exponen en MsalServiceException.
  • Hay un método .WithClaim(claims) que puede aplicarse a los generadores AcquireTokenXXX.

Para obtener más detalles, consulte cómo controlar MsalUiRequiredException.

En ADAL.NET, las excepciones en los desafíos de notificaciones se controlaron de la siguiente forma:

  • AdalClaimChallengeException es una excepción (que se deriva de AdalServiceException). El miembro Claims contiene algún fragmento de JSON con las notificaciones, que se esperan.
  • La aplicación cliente pública que recibe esta excepción debía llamar a la invalidación AcquireTokenInteractive con un parámetro de notificaciones. Esta invalidación de AcquireTokenInteractive ni siquiera intenta llegar a la memoria caché porque no es necesario. La razón es que el token de la memoria caché no tiene las notificaciones correctas (de lo contrario, no se habría producido AdalClaimChallengeException). Por lo tanto, no es necesario examinar la memoria caché. Tenga en cuenta que ClaimChallengeException se puede recibir en una WebAPI que aplique OBO, pero AcquireTokenInteractive debe llamarse en una aplicación cliente pública que llama a esta API web.

Para obtener más detalles, incluidos ejemplos, consulte la sección sobre cómo controlar AdalClaimChallengeException.

Ámbitos

ADAL usa el concepto de recursos con la cadena resourceId; sin embargo, MSAL.NET usa ámbitos. La lógica que usa Azure AD es la siguiente:

  • Para el punto de conexión de ADAL (v1.0) con un token de acceso de la versión 1.0 (el único posible), aud=resource.
  • Si MSAL (punto de conexión de la versión 2.0) pide un token de acceso para un recurso que acepta tokens de la versión 2.0, aud=resource.AppId.
  • Si MSAL (punto de conexión de la versión 2.0) pide un token de acceso para un recurso que acepta tokens de la versión 1.0, Azure AD analiza la audiencia deseada desde el ámbito solicitado. Para ello, se toma todo el contenido antes de la última barra diagonal y se usa como identificador de recurso. De esta forma, si https://database.windows.net espera una audiencia de https://database.windows.net/, deberá solicitar un ámbito de https://database.windows.net//.default (observe la barra diagonal doble antes de ./default). Esto se ilustra en los ejemplos 1 y 2 siguientes.

Ejemplo 1

Si quiere adquirir tokens para una aplicación que acepte tokens de la versión 1.0 (por ejemplo, Microsoft Graph API, que es https://graph.microsoft.com), debe crear scopes mediante la concatenación de un identificador de recurso deseado con un permiso de OAuth2 deseado para dicho recurso.

Por ejemplo, para acceder al nombre del usuario a través de una API web v1.0 que tiene un URI de identificador de aplicación ResourceId, es probable que quiera usar lo siguiente:

var scopes = new [] { ResourceId+"/user_impersonation" };

Si quiere leer y escribir con MSAL.NET Azure Active Directory mediante Microsoft Graph API (https://graph.microsoft.com/), debería crear una lista de ámbitos, como en el fragmento de código siguiente:

string ResourceId = "https://graph.microsoft.com/"; 
string[] scopes = { ResourceId + "Directory.Read", ResourceId + "Directory.Write" }

Ejemplo 2

Si resourceId termina con "/", deberá tener un carácter "/" doble al escribir el valor del ámbito. Por ejemplo, si quiere escribir el ámbito correspondiente a la API de Azure Resource Manager (https://management.core.windows.net/), solicite el ámbito siguiente (observe las dos barras diagonales).

var resource = "https://management.core.windows.net/"
var scopes = new[] {"https://management.core.windows.net//user_impersonation"};
var result = await app.AcquireTokenInteractive(scopes).ExecuteAsync();

// then call the API: https://management.azure.com/subscriptions?api-version=2016-09-01

Esto se debe a que la API de Resource Manager espera una barra diagonal en su notificación de la audiencia (aud) y, después, hay una barra diagonal para separar el nombre de la API del ámbito.

Si quiere adquirir un token para todos los ámbitos estáticos de una aplicación v1.0, la lista de ámbitos se crearía como se muestra en el fragmento de código siguiente:

ResourceId = "someAppIDURI";
var scopes = new [] { ResourceId+"/.default" };

Para un flujo de credenciales de cliente, el ámbito que se pasa también sería /.default. Este ámbito indica a Azure AD: "todos los permisos de nivel de aplicación a los que el administrador ha dado su consentimiento para el registro de la aplicación".

Pasos siguientes

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