Migración de aplicaciones a MSAL para iOS y macOS

La biblioteca de autenticación de Azure Active Directory (ADAL Objective-C) se creó para trabajar con cuentas de Microsoft Entra a través del punto de conexión v1.0.

La biblioteca de autenticación de Microsoft para iOS y macOS (MSAL) está diseñada para funcionar con todas las identidades de Microsoft, como las cuentas de Microsoft Entra, las cuentas personales de Microsoft y las cuentas de Azure AD B2C, a través de la plataforma de identidades de Microsoft (anteriormente, el punto de conexión Azure AD v2.0).

El Plataforma de identidad de Microsoft tiene algunas diferencias clave con Azure AD v1.0. En este artículo se resaltan estas diferencias y se proporcionan instrucciones para migrar una aplicación de ADAL a MSAL.

Diferencias de funcionalidad de la aplicación ADAL y MSAL

Quién puede iniciar sesión

  • ADAL solo admite cuentas profesionales y educativas, también conocidas como cuentas de Microsoft Entra.
  • MSAL admite cuentas de Microsoft personales (cuentas de MSA), como Hotmail.com, Outlook.com y Live.com.
  • MSAL admite cuentas profesionales o educativas y cuentas de Azure AD B2C.

Cumplimiento normativo

  • El Plataforma de identidad de Microsoft sigue los estándares de OAuth 2.0 y OpenId Connect.
  • El Plataforma de identidad de Microsoft permite solicitar permisos dinámicamente. Las aplicaciones solo pueden solicitar permisos según sea necesario y solicitar más, ya que la aplicación las necesita. Para obtener más información, consulte permisos y consentimiento.

Diferencias entre la biblioteca ADAL y MSAL

La API pública de MSAL refleja algunas diferencias clave entre Azure AD v1.0 y la Plataforma de identidad de Microsoft.

MSALPublicClientApplication en lugar de ADAuthenticationContext

ADAuthenticationContext es el primer objeto que crea una aplicación de ADAL. Representa la creación de una instancia de ADAL. Las aplicaciones crean una nueva instancia de ADAuthenticationContext para cada combinación de nube e inquilino (entidad) de Microsoft Entra. Lo mismo ADAuthenticationContext se puede usar para obtener tokens para varias aplicaciones cliente públicas.

En MSAL, la interacción principal se realiza a través de un objeto MSALPublicClientApplication, que está modelado a partir de cliente público de OAuth 2.0. Se puede usar una instancia de MSALPublicClientApplication para interactuar con varias nubes de Microsoft Entra, e inquilinos, sin necesidad de crear una nueva instancia para cada entidad. Para la mayoría de las aplicaciones, una MSALPublicClientApplication instancia es suficiente.

Ámbitos en lugar de recursos

En ADAL, una aplicación tenía que proporcionar un identificador de recurso, como https://graph.microsoft.com, para obtener tokens del punto de conexión de Azure AD v1.0. Un recurso puede definir varios ámbitos, o oAuth2Permissions en el manifiesto de la aplicación, que comprende. Esto permitió a las aplicaciones cliente solicitar tokens de ese recurso para un determinado conjunto de ámbitos predefinidos durante el registro de aplicaciones.

En MSAL, en lugar de un único identificador de recurso, las aplicaciones proporcionan un conjunto de ámbitos por solicitud. Un ámbito es un identificador de recurso seguido de un nombre de permiso en el formulario resource/permission. Por ejemplo: https://graph.microsoft.com/user.read

Hay dos formas de proporcionar alcances en MSAL:

  • Proporcione una lista de todos los permisos que necesitan las aplicaciones. Por ejemplo:

    @[@"https://graph.microsoft.com/directory.read", @"https://graph.microsoft.com/directory.write"]

    En este caso, la aplicación solicita los permisos directory.read y directory.write. Se pedirá al usuario que dé su consentimiento a esos permisos si antes no ha dado su consentimiento a esos permisos para esta aplicación. La aplicación también puede recibir permisos adicionales a los que el usuario ya ha consentido para la aplicación. Solo se pedirá al usuario que dé su consentimiento para los nuevos permisos o permisos que no se hayan concedido.

  • El ámbito /.default.

Este es el ámbito predeterminado de cada aplicación. Hace referencia a la lista estática de permisos configurados cuando se registró la aplicación. Su comportamiento es similar al de resource. Esto puede ser útil al migrar para asegurarse de que se mantiene un conjunto similar de ámbitos y experiencia del usuario.

Para usar el /.default ámbito, anexe /.default al identificador de recurso. Por ejemplo: https://graph.microsoft.com/.default. Aunque el recurso termine con una barra diagonal (/), hay que anexar /.default, incluida la barra diagonal inicial, lo que da lugar a un ámbito que tiene una doble barra diagonal (//).

Puede leer más información sobre el uso del ámbito "/.default" en permisos y ámbitos.

Compatibilidad con diferentes tipos y exploradores de WebView

ADAL solo admite UIWebView/WKWebView para iOS y WebView para macOS. MSAL para iOS admite más opciones para mostrar contenido web al solicitar un código de autorización y ya no admite UIWebView; lo que puede mejorar la experiencia del usuario y la seguridad.

De forma predeterminada, MSAL en iOS usa ASWebAuthenticationSession, que es el componente web que Apple recomienda para la autenticación en dispositivos iOS 12+. Proporciona ventajas de inicio de sesión único (SSO) mediante el uso compartido de cookies entre aplicaciones y el explorador Safari.

Puede optar por usar un componente web diferente en función de los requisitos de la aplicación y la experiencia del usuario final que desee. Consulte los tipos de vista web admitidos para obtener más opciones.

Al migrar de ADAL a MSAL, WKWebView proporciona la experiencia del usuario más similar a ADAL en iOS y macOS. Le recomendamos que migre a ASWebAuthenticationSession en iOS, si es posible. Para macOS, le recomendamos que use WKWebView.

Diferencias de api de administración de cuentas

Cuando se llaman los métodos de ADAL acquireToken() o acquireTokenSilent(), se recibe un objeto ADUserInformation que contiene una lista de declaraciones del id_token, que representa la cuenta que se está autenticando. Además, ADUserInformation devuelve un userId basado en la reclamación upn. Después de la adquisición interactiva inicial de tokens, ADAL espera que el desarrollador proporcione userId en todas las llamadas silenciosas.

ADAL no proporciona una API para recuperar identidades de usuario conocidas. Se basa en la aplicación para guardar y administrar esas cuentas.

MSAL proporciona un conjunto de API para enumerar todas las cuentas conocidas para MSAL sin tener que adquirir un token.

Como ADAL, MSAL devuelve información de la cuenta que contiene una lista de notificaciones del id_token. Forma parte del MSALAccount objeto dentro del MSALResult objeto .

MSAL proporciona un conjunto de API para quitar cuentas, lo que hace que las cuentas eliminadas no sean accesibles para la aplicación. Después de eliminar la cuenta, las llamadas posteriores de adquisición de tokens solicitarán al usuario que realice una adquisición interactiva de tokens. La eliminación de cuentas solo se aplica a la aplicación cliente que la inició y no quita la cuenta de las demás aplicaciones que se ejecutan en el dispositivo o desde el explorador del sistema. Esto garantiza que el usuario sigue teniendo una experiencia de inicio de sesión único en el dispositivo incluso después de cerrar la sesión de una aplicación individual.

Además, MSAL también devuelve un identificador de cuenta que se puede usar para solicitar un token de forma silenciosa más adelante. Sin embargo, el identificador de la cuenta (accesible a través de la propiedad identifier del objeto MSALAccount) no se puede mostrar, y no puede asumir en qué formato está ni debe intentar interpretarlo o analizarlo.

Migración de la caché de cuentas

Al migrar de ADAL, las aplicaciones normalmente almacenan el userId de ADAL, que no tiene el identifier requerido por MSAL. Como paso de migración único, una aplicación puede consultar una cuenta de MSAL mediante userId de ADAL con la API siguiente:

- (nullable MSALAccount *)accountForUsername:(nonnull NSString *)username error:(NSError * _Nullable __autoreleasing * _Nullable)error;

Esta API lee tanto la memoria caché de MSAL como la de ADAL para buscar la cuenta por userId (UPN) de ADAL.

Si se encuentra la cuenta, el desarrollador debe usar la cuenta para realizar la adquisición silenciosa de tokens. La primera adquisición silenciosa de tokens actualizará eficazmente la cuenta y el desarrollador obtendrá un identificador de cuenta compatible con MSAL en el resultado de MSAL (identifier). Después de eso, solo identifier se debe usar para las búsquedas de cuentas mediante la SIGUIENTE API:

- (nullable MSALAccount *)accountForIdentifier:(nonnull NSString *)identifier error:(NSError * _Nullable __autoreleasing * _Nullable)error;

Aunque es posible seguir usando ADAL userId para todas las operaciones de MSAL, ya que userId se basa en UPN, está sujeto a varias limitaciones que dan lugar a una mala experiencia de usuario. Por ejemplo, si cambia el UPN, el usuario debe volver a iniciar sesión. Se recomienda que todas las aplicaciones usen la cuenta identifier no visible para todas las operaciones.

Obtenga más información sobre la migración de estado de caché.

Cambios en la adquisición de tokens

MSAL introduce algunos cambios en las llamadas de adquisición de tokens:

  • Al igual que ADAL, acquireTokenSilent siempre da como resultado una solicitud silenciosa.
  • A diferencia de ADAL, acquireToken siempre da como resultado una interfaz de usuario accionable por parte del usuario a través de la vista web o la aplicación Microsoft Authenticator. Según el estado de SSO dentro de webview/Microsoft Authenticator, se puede solicitar al usuario que escriba sus credenciales.
  • En ADAL, acquireToken con AD_PROMPT_AUTO primero intenta adquirir un token de forma silenciosa y solo muestra la interfaz de usuario si la solicitud silenciosa falla. En MSAL, esta lógica se puede lograr llamando primero acquireTokenSilent y llamando solo acquireToken si se produce un error en la adquisición silenciosa. Esto permite a los desarrolladores personalizar la experiencia del usuario antes de iniciar la adquisición interactiva de tokens.

Diferencias de control de errores

MSAL proporciona más claridad entre los errores que puede controlar la aplicación y los que requieren la intervención del usuario. Hay un número limitado de errores que el desarrollador debe controlar:

  • MSALErrorInteractionRequired: el usuario debe realizar una solicitud interactiva. Esto puede deberse a varios motivos, como una sesión de autenticación expirada, una directiva de acceso condicional ha cambiado, un token de actualización expirado o se revoca, no hay tokens válidos en la memoria caché, etc.
  • MSALErrorServerDeclinedScopes: La solicitud no se completó totalmente y a algunos ámbitos no se les concedió acceso. Esto puede deberse a que un usuario rechaza el consentimiento de uno o varios ámbitos.

Controlar todos los demás errores de la MSALError lista es opcional. Puede usar la información de esos errores para mejorar la experiencia del usuario.

Consulte Control de excepciones y errores mediante MSAL para obtener más información sobre el control de errores de MSAL.

Compatibilidad con el bróker

MSAL, a partir de la versión 0.3.0, admite la autenticación intermediada mediante la aplicación Microsoft Authenticator. Microsoft Authenticator también permite la compatibilidad con escenarios de acceso condicional. Algunos ejemplos de escenarios de acceso condicional incluyen directivas de cumplimiento de dispositivos que requieren que el usuario inscriba el dispositivo a través de Intune o regístrese con Microsoft Entra ID para obtener un token. Y las directivas de acceso condicional de administración de aplicaciones móviles (MAM), que requieren prueba de cumplimiento antes de que la aplicación pueda obtener un token.

Para habilitar el agente en la aplicación:

  1. Registre un formato de URI de redirección compatible con el intermediario para la aplicación. El formato de URI de redirección compatible con el intermediario es msauth.<app.bundle.id>://auth. Sustituya <app.bundle.id> por el identificador del paquete de su aplicación. Si migra de ADAL y su aplicación ya era compatible con broker, no tiene que hacer nada más. El URI de redirección anterior es totalmente compatible con MSAL, por lo que puede ir directamente al paso 3.

  2. Agregue el esquema de URI de redirección de la aplicación al archivo info.plist. Para el URI de redirección de MSAL predeterminado, el formato es msauth.<app.bundle.id>. Por ejemplo:

    <key>CFBundleURLSchemes</key>
    <array>
        <string>msauth.<app.bundle.id></string>
    </array>
    
  3. Agregue los siguientes esquemas al archivo Info.plist de su aplicación, en el apartado LSApplicationQueriesSchemes:

    <key>LSApplicationQueriesSchemes</key>
    <array>
         <string>msauthv2</string>
         <string>msauthv3</string>
    </array>
    
  4. Añada lo siguiente al archivo AppDelegate.m para gestionar las llamadas de retorno: Objective-C:

    - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options`
    {
        return [MSALPublicClientApplication handleMSALResponse:url sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey]];
    }
    

    Swift:

    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        return MSALPublicClientApplication.handleMSALResponse(url, sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String)
    }
    

Colaboración entre negocios (B2B)

En ADAL, se crean instancias independientes de ADAuthenticationContext para cada inquilino para el que la aplicación solicita tokens. Esto ya no es un requisito en MSAL. En MSAL, puedes crear una única instancia de MSALPublicClientApplication y usarla para cualquier nube y organización de Microsoft Entra al especificar una autoridad diferente para las llamadas a acquireToken y acquireTokenSilent.

SSO en asociación con otros SDK

MSAL para iOS puede lograr SSO a través de una caché unificada con ADAL Objective-C 2.7.x+.

El SSO se consigue mediante el uso compartido del llavero de iOS y solo está disponible entre aplicaciones publicadas con la misma cuenta de Apple Developer.

El SSO mediante el uso compartido del Llavero de iOS es el único tipo de SSO silencioso.

En macOS, MSAL puede ofrecer SSO con otras aplicaciones para iOS y macOS basadas en MSAL y con aplicaciones basadas en ADAL Objective-C.

MSAL en iOS también admite otros dos tipos de SSO:

  • SSO mediante el navegador web. MSAL para iOS admite ASWebAuthenticationSession, que proporciona SSO a través de cookies compartidas entre otras aplicaciones en el dispositivo y específicamente el explorador Safari.
  • SSO a través de un intermediario de autenticación. En un dispositivo iOS, Microsoft Authenticator actúa como agente de autenticación. Puede seguir las directivas de acceso condicional, como requerir un dispositivo compatible, y proporcionar SSO para dispositivos registrados. Los SDK de MSAL a partir de la versión 0.3.0 admiten un broker de forma predeterminada.

Intune MAM SDK

El SDK de MAM de Intune admite MSAL para iOS a partir de la versión 11.1.2

MSAL y ADAL en la misma aplicación

La versión 2.7.0 y posteriores de ADAL no pueden coexistir con MSAL en la misma aplicación. La razón principal es debido al código común del submódulo compartido. Dado que Objective-C no admite espacios de nombres, si agrega marcos de ADAL y MSAL a la aplicación, habrá dos instancias de la misma clase. No hay garantía de cuál se seleccionará en tiempo de ejecución. Si ambos SDK usan la misma versión de la clase en conflicto, es posible que la aplicación siga funcionando. Sin embargo, si es una versión diferente, la aplicación podría experimentar bloqueos inesperados que son difíciles de diagnosticar.

No se admite la ejecución de ADAL y MSAL en la misma aplicación de producción. Sin embargo, si solo está probando y migrando los usuarios de ADAL Objective-C a MSAL para iOS y macOS, puede seguir usando ADAL Objective-C 2.6.10. Es la única versión que funciona con MSAL en la misma aplicación. No habrá nuevas actualizaciones de características para esta versión de ADAL, por lo que solo se debe usar con fines de migración y pruebas. La aplicación no debe depender de la coexistencia de ADAL y MSAL a largo plazo.

No se admite la coexistencia de ADAL y MSAL en la misma aplicación. La coexistencia de ADAL y MSAL entre varias aplicaciones es totalmente compatible.

Pasos prácticos de migración

Migración del registro de aplicaciones

No es necesario cambiar la aplicación de Microsoft Entra existente para cambiar a MSAL y habilitar Microsoft Entra cuentas. Sin embargo, si su aplicación basada en ADAL no admite la autenticación con agente, deberá registrar un nuevo URI de redirección para la aplicación antes de poder cambiar a MSAL.

El URI de redirección debe estar en este formato: msauth.<app.bundle.id>://auth. Sustituya <app.bundle.id> por el identificador del paquete de su aplicación. Especifique el URI de redirección en el Centro de administración Microsoft Entra.

Solo para iOS, para admitir la autenticación basada en certificados, es necesario registrar un URI de redirección adicional en la aplicación y el Centro de administración Microsoft Entra en el siguiente formato: msauth://code/<broker-redirect-uri-in-url-encoded-form>. Por ejemplo: msauth://code/msauth.com.microsoft.mybundleId%3A%2F%2Fauth

Se recomienda que todas las aplicaciones registren ambos URI de redirección.

Si quiere agregar compatibilidad con el consentimiento incremental, seleccione las API y los permisos a los que está configurada la aplicación para solicitar acceso en el registro de la aplicación en la pestaña Permisos de API .

Si va a migrar desde ADAL y quiere admitir cuentas de Microsoft Entra ID y MSA, el registro de la aplicación existente debe actualizarse para admitir ambos. No se recomienda actualizar la aplicación de producción existente para admitir Microsoft Entra ID y MSA inmediatamente. En su lugar, cree otro identificador de cliente que admita tanto Microsoft Entra ID como MSA para pruebas, y después de comprobar que todos los escenarios funcionan, actualice la aplicación existente.

Adición de MSAL a la aplicación

Puede agregar el SDK de MSAL a la aplicación mediante la herramienta de administración de paquetes preferida. Consulte las instrucciones detalladas aquí.

Actualizar el archivo Info.plist de la aplicación

Solo para iOS, agregue el esquema de URI de redireccionamiento de la aplicación al archivo info.plist. En el caso de las aplicaciones compatibles con el intermediario de ADAL, ya debería estar. El esquema de URI de redirección de MSAL predeterminado tendrá el formato : msauth.<app.bundle.id>.

<key>CFBundleURLSchemes</key>
<array>
    <string>msauth.<app.bundle.id></string>
</array>

Añada los siguientes esquemas al archivo Info.plist de su aplicación debajo de LSApplicationQueriesSchemes.

<key>LSApplicationQueriesSchemes</key>
<array>
     <string>msauthv2</string>
     <string>msauthv3</string>
</array>

Actualización del código de AppDelegate

Solo para iOS, agregue lo siguiente al archivo AppDelegate.m:

Objective-C:

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options`
{
    return [MSALPublicClientApplication handleMSALResponse:url sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey]];
}

Swift:

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    return MSALPublicClientApplication.handleMSALResponse(url, sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String)
}

Si utilizas Xcode 11, debes colocar la llamada de retorno de MSAL en el archivo SceneDelegate en su lugar. Si admite tanto UISceneDelegate como UIApplicationDelegate para lograr compatibilidad con sistemas operativos iOS anteriores, la devolución de llamada de MSAL debe colocarse en ambos archivos.

Objective-C:

 - (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts
 {
     UIOpenURLContext *context = URLContexts.anyObject;
     NSURL *url = context.URL;
     NSString *sourceApplication = context.options.sourceApplication;
     
     [MSALPublicClientApplication handleMSALResponse:url sourceApplication:sourceApplication];
 }

Swift:

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
        
        guard let urlContext = URLContexts.first else {
            return
        }
        
        let url = urlContext.url
        let sourceApp = urlContext.options.sourceApplication
        
        MSALPublicClientApplication.handleMSALResponse(url, sourceApplication: sourceApp)
    }

Esto permite que MSAL gestione las respuestas del broker y del componente web. Esto no era necesario en ADAL, ya que referenciaba los métodos de delegación de la aplicación automáticamente. Agregarlo manualmente es menos propenso a errores y proporciona a la aplicación más control.

Habilitación del almacenamiento en caché de tokens

De forma predeterminada, MSAL almacena en caché los tokens de la aplicación en la cadena de claves de iOS o macOS.

Para habilitar el almacenamiento en caché de tokens:

  1. Asegúrese de que la aplicación está firmada correctamente
  2. Vaya a la configuración del proyecto de Xcode >Pestaña Capabilities (Funcionalidades)>Enable Keychain Sharing (Habilitar uso compartido de la cadena de claves)
  3. Haga clic + y escriba una entrada de grupos de cadenas de claves siguiente: 3.a Para iOS, escriba com.microsoft.adalcache 3.b Para macOS, escriba com.microsoft.identity.universalstorage

Creación de MSALPublicClientApplication y cambio a sus llamadas acquireToken y acquireTokeSilent

Puede crear MSALPublicClientApplication con el código siguiente:

Objective-C:

NSError *error = nil;
MSALPublicClientApplicationConfig *configuration = [[MSALPublicClientApplicationConfig alloc] initWithClientId:@"<your-client-id-here>"];
    
MSALPublicClientApplication *application =
[[MSALPublicClientApplication alloc] initWithConfiguration:configuration
                                                     error:&error];

Swift:

let config = MSALPublicClientApplicationConfig(clientId: "<your-client-id-here>")
do {
  let application = try MSALPublicClientApplication(configuration: config)
  // continue on with application
            
} catch let error as NSError {
  // handle error here
}

A continuación, llame a la API de administración de cuentas para ver si hay alguna cuenta en la memoria caché:

Objective-C:

NSString *accountIdentifier = nil /*previously saved MSAL account identifier */;
NSError *error = nil;
MSALAccount *account = [application accountForIdentifier:accountIdentifier error:&error];

Swift:

// definitions that need to be initialized
let application: MSALPublicClientApplication!
let accountIdentifier: String! /*previously saved MSAL account identifier */

do {
  let account = try application.account(forIdentifier: accountIdentifier)
  // continue with account usage
} catch let error as NSError {
  // handle error here
}

o lea todos los relatos:

Objective-C:

NSError *error = nil;
NSArray<MSALAccount *> *accounts = [application allAccounts:&error];

Swift:

let application: MSALPublicClientApplication!
do {
  let accounts = try application.allAccounts()
  // continue with account usage
} catch let error as NSError {
  // handle error here
}

Si se encuentra una cuenta, llame a la API de MSAL acquireTokenSilent :

Objective-C:

MSALSilentTokenParameters *silentParameters = [[MSALSilentTokenParameters alloc] initWithScopes:@[@"<your-resource-here>/.default"] account:account];
    
[application acquireTokenSilentWithParameters:silentParameters
                              completionBlock:^(MSALResult *result, NSError *error)
{
    if (result)
    {
        NSString *accessToken = result.accessToken;
        // Use your token
    }
    else
    {
        // Check the error
        if ([error.domain isEqual:MSALErrorDomain] && error.code == MSALErrorInteractionRequired)
        {
            // Interactive auth will be required
        }
            
        // Other errors may require trying again later, or reporting authentication problems to the user
    }
}];

Swift:

let application: MSALPublicClientApplication!
let account: MSALAccount!
        
let silentParameters = MSALSilentTokenParameters(scopes: ["<your-resource-here>/.default"], 
                                                 account: account)
application.acquireTokenSilent(with: silentParameters) {
  (result: MSALResult?, error: Error?) in
  if let accessToken = result?.accessToken {
     // use accessToken
  }
  else {
    // Check the error
    guard let error = error else {
      assert(true, "callback should contain a valid result or error")
      return
    }
    
    let nsError = error as NSError
    if (nsError.domain == MSALErrorDomain
        && nsError.code == MSALError.interactionRequired.rawValue) {
      // Interactive auth will be required
    }
                
    // Other errors may require trying again later, or reporting authentication problems to the user
  }
}

Pasos siguientes

Más información sobre los flujos de autenticación y los escenarios de aplicaciones