Guida alla migrazione da ADAL a MSAL per Android

Questo articolo evidenzia le modifiche necessarie per eseguire la migrazione di un'app che usa Azure Active Directory Authentication Library (ADAL) a un'app che usa Microsoft Authentication Library (MSAL).

Differenze in evidenza

ADAL funziona con l'endpoint di Azure AD v1.0. Microsoft Authentication Library (MSAL) funziona con Microsoft Identity Platform, nota in precedenza come l'endpoint di Azure AD v2.0. Microsoft Identity Platform differisce da Azure AD v1.0 in quanto:

Supporta:

  • Identità organizzativa (Microsoft Entra ID)

  • Identità non aziendali, ad esempio Outlook.com, Xbox Live e così via

  • (Solo per Azure AD B2C) Accesso federato con Google, Facebook, Twitter e Amazon

  • Gli standard sono compatibili con:

    • OAuth v2.0
    • OpenID Connect (OIDC)

L'API pubblica MSAL introduce importanti modifiche, tra cui:

  • Un nuovo modello per l'accesso ai token:
    • ADAL fornisce l'accesso ai token tramite AuthenticationContext, che rappresenta il server. MSAL fornisce l'accesso ai token tramite PublicClientApplication, che rappresenta il client. Gli sviluppatori client non devono creare una nuova istanza di PublicClientApplication per ogni autorità con cui devono interagire. È richiesta solo una configurazione PublicClientApplication.
    • Supporto per la richiesta di token di accesso tramite ambiti aggiuntivi agli identificatori di risorsa.
    • Supporto per il consenso incrementale. Gli sviluppatori possono richiedere ambiti man mano che l'utente accede a più funzionalità nell'app, tra cui quelle non incluse durante la registrazione app.
    • Le autorità non sono più convalidate in fase di esecuzione. Lo sviluppatore dichiara invece un elenco di "autorità note" durante lo sviluppo.
  • Modifiche dei token API:
    • In ADAL, AcquireToken() effettua prima una richiesta automatica. Se non fosse possibile, effettua una richiesta interattiva. A causa di questo comportamento, alcuni sviluppatori si basano solo su AcquireToken, con la possibilità che talvolta all'utente venga richiesto di immettere le credenziali. In MSAL, gli sviluppatori devono sapere in che momento l'utente riceve un prompt dell'interfaccia utente.
      • AcquireTokenSilent genera sempre una richiesta automatica che ha esito positivo o negativo.
      • AcquireToken genera sempre una richiesta presentata all'utente tramite l'interfaccia utente.
  • MSAL supporta l'accesso da un browser predefinito o da una visualizzazione Web incorporata:
    • Per impostazione predefinita, il dispositivo usa il browser predefinito. Ciò consente a MSAL di usare lo stato di autenticazione (cookie) che potrebbe essere già presente per uno o più account registrati. Se non è presente alcuno stato di autenticazione, l'autenticazione durante l'autorizzazione tramite MSAL comporta la creazione dello stato di autenticazione (cookie) a beneficio di altre applicazioni Web che verranno usate nello stesso browser.
  • Nuovo modello di eccezioni:
    • Le eccezioni definiscono in maniera più chiara il tipo di errore che si è verificato e le azioni che lo sviluppatore deve intraprendere per risolverlo.
  • MSAL supporta gli oggetti parametro per le chiamate AcquireToken e AcquireTokenSilent.
  • MSAL supporta la configurazione dichiarativa per:
    • ID client, URI di reindirizzamento.
    • Browser incorporato e predefinito a confronto
    • Autorità
    • Impostazioni HTTP, come timeout di lettura e connessione

Registrazione e migrazione dell'app a MSAL

Per usare MSAL, non è necessario modificare la registrazione app esistente. Per sfruttare i vantaggi del consenso incrementale/progressivo, potrebbe essere necessario rivedere la registrazione per identificare gli ambiti specifici da richiedere in modo incrementale. DI seguito sono riportate ulteriori informazioni sugli ambiti e sul consenso incrementale.

Durante la registrazione app nel portale, verrà visualizzata una scheda Autorizzazioni API. In questo modo si ottiene un elenco delle API e delle autorizzazioni (ambiti) per cui l'app è attualmente configurata per le richieste di accesso. Viene inoltre visualizzato un elenco dei nomi degli ambiti associati a ogni autorizzazione API.

Con ADAL e l'endpoint di Azure AD v1.0, il consenso utente alle risorse possedute è concesso al primo utilizzo. Con MSAL e Microsoft Identity Platform, il consenso può essere richiesto in modo incrementale. Il consenso incrementale è utile per le autorizzazioni che un utente potrebbe considerare un privilegio elevato o che al contrario potrebbe contestare qualora non ricevesse una spiegazione chiara del motivo per cui l'autorizzazione è necessaria. In ADAL, l'utente potrebbe rinunciare all'accesso all'app a causa di tali autorizzazioni.

Suggerimento

Usare il consenso incrementale per fornire agli utenti un contesto aggiuntivo sul motivo per cui l'app richiede un'autorizzazione.

Gli amministratori dell'organizzazione possono fornire il consenso per le autorizzazioni richieste dall'applicazione per conto di tutti i membri dell'organizzazione. Alcune organizzazioni consentono solo agli amministratori di fornire il consenso alle applicazioni. Il consenso amministratore richiede l'inclusione di tutte le autorizzazioni API e gli ambiti usati dall'applicazione nella registrazione app.

Suggerimento

Sebbene sia possibile richiedere un ambito tramite MSAL per un elemento non incluso nella registrazione app, consigliamo di aggiornare la registrazione app in modo da includere tutte le risorse e gli ambiti a cui un utente potrebbe mai concedere l'autorizzazione.

Migrazione dagli ID delle risorse agli ambiti

Autenticare e richiedere l'autorizzazione per tutte le autorizzazioni al primo utilizzo

Se attualmente si usa ADAL e non è richiesto il consenso incrementale, il modo più semplice per iniziare a usare MSAL consiste nell'effettuare una richiesta acquireToken usando il nuovo oggetto AcquireTokenParameter e impostando il valore ID della risorsa.

Attenzione

Non è possibile impostare sia gli ambiti sia un ID della risorsa. Se si tenta di impostare entrambi, verrà generato un oggetto IllegalArgumentException.

Ciò determinerà lo stesso comportamento v1 riscontrato in precedenza. L'utente deve fornire tutte le autorizzazioni richieste nella registrazione app durante la prima interazione.

Autenticare e richiedere le autorizzazioni solo se necessario

Per sfruttare i vantaggi del consenso incrementale, creare un elenco di autorizzazioni (ambiti) usate dall'app dalla registrazione app e organizzarle in due elenchi in base a:

  • Gli ambiti che si intende richiedere durante la prima interazione dell'utente con l'app al momento dell'accesso.
  • Le autorizzazioni associate a una funzionalità importante dell'app che sarà inoltre necessario spiegare all'utente.

Dopo aver impostato gli ambiti, organizzare ogni elenco in base alla risorsa (API) per cui si intende richiedere un token, insieme a qualsiasi altro ambito che si desidera che venga autorizzato contemporaneamente dall'utente.

L'oggetto parametri usato per effettuare la richiesta a MSAL supporta:

  • Scope: l'elenco degli ambiti per cui si intende richiedere l'autorizzazione e ricevere un token di accesso.
  • ExtraScopesToConsent: un elenco aggiuntivo degli ambiti per cui si intende richiedere l'autorizzazione congiuntamente alla richiesta di un token di accesso per un'altra risorsa. Questo elenco di ambiti consente di ridurre al minimo il numero di volte in cui è necessario richiedere l'autorizzazione utente. Ciò si traduce in un minor numero di richieste di autorizzazione o consenso all'utente.

Eseguire la migrazione da AuthenticationContext a PublicClientApplications

Creazione di PublicClientApplication

Quando si usa MSAL, si crea un'istanza di PublicClientApplication. Questo oggetto modella l'identità dell'app e viene usato per effettuare richieste a una o più autorità. Questo oggetto consentirà di configurare l'identità client, l'URI di reindirizzamento, l'autorità predefinita, se usare il browser del dispositivo o la visualizzazione Web incorporata, il livello di log e altro ancora.

Questo oggetto può essere configurato in modo dichiarativo con JSON e fornito come file o archiviato come risorsa all'interno dell'APK.

Sebbene non si tratti di un singleton, usa internamente Executors condivisi per le richieste interattive e automatiche.

Business to Business

In ADAL, ogni organizzazione da cui si richiedono token di accesso richiede un'istanza separata di AuthenticationContext. In MSAL, questo requisito è stato eliminato. È possibile specificare l'autorità da cui si intende richiedere un token come parte della richiesta automatica o interattiva.

Eseguire la migrazione dalla convalida dell'autorità alle autorità note

MSAL non dispone di un contrassegno per abilitare o disabilitare la convalida dell'autorità. La convalida dell'autorità è una funzionalità di ADAL e delle versioni anticipate di MSAL, che impedisce al codice di richiedere token da un'autorità potenzialmente dannosa. MSAL ora recupera un elenco di autorità note a Microsoft e unisce l'elenco con le autorità specificate nella configurazione.

Suggerimento

Ciò significa che gli utenti di Azure Business to Consumer (B2C) non dovranno più disabilitare la convalida dell'autorità. Ognuno dei criteri di Azure AD B2C supportati sarà invece incluso come autorità nella configurazione MSAL.

Se si tenta di usare un'autorità che non è nota a Microsoft né inclusa nella configurazione, si otterrà un oggetto UnknownAuthorityException.

Registrazione

La registrazione può ora essere configurata in modo dichiarativo come parte della configurazione, come descritto di seguito:

"logging": {
  "pii_enabled": false,
  "log_level": "WARNING",
  "logcat_enabled": true
}

Eseguire la migrazione da UserInfo all'account

In ADAL, AuthenticationResult fornisce un oggetto UserInfo utilizzato per recuperare informazioni sull'account autenticato. Il termine "utente", per il quale si intendeva un agente umano o software, è stato applicato in un modo che rendeva difficile comunicare che alcune app supportano un singolo utente (agente umano o software) con più account.

Si consideri un conto bancario. È possibile avere più di un conto presso più di un istituto finanziario. Una volta aperto un conto, l'utente riceve le credenziali, ad esempio una carta bancomat e il relativo PIN, da usare per accedere al saldo, fatturare i pagamenti e così via, per ogni account. Tali credenziali possono essere usate solo presso l'istituto finanziario che le ha rilasciate.

Come i conti di un istituto finanziario, anche gli account in Microsoft Identity Platform sono accessibili tramite credenziali. Tali credenziali sono registrate o rilasciate direttamente da Microsoft, oppure da Microsoft per conto di un'organizzazione.

Per continuare con questo esempio, la differenza tra Microsoft Identity Platform e un istituto finanziario è che Microsoft Identity Platform fornisce un framework che consente all'utente di usare un unico account e le credenziali ad esso associate per accedere a risorse appartenenti a più utenti e organizzazioni. È come se una carta emessa da una banca potesse essere utilizzata in un altro istituto finanziario. Questo è possibile perché tutte le organizzazioni in questione usano Microsoft Identity Platform, che consente di usare lo stesso account in più organizzazioni. Ecco un esempio:

Sam opera su Contoso.com ma gestisce le macchine virtuali di Azure appartenenti a Fabrikam.com. Per poter gestire le macchine virtuali di Fabrikam, Sam deve disporre dell'autorizzazione di accesso. Per concedere questo accesso, è possibile aggiungere l'account di Sam a Fabrikam.com e assegnare al suo account un ruolo che gli consente di usare le macchine virtuali. Questa operazione può essere eseguita tramite il portale di Azure.

Aggiungendo l'account di Sam su Contoso.com come membro di Fabrikam.com, verrà creato un nuovo record nel Microsoft Entra ID di Fabrikam.com per Sam. Il record di Sam in Microsoft Entra ID è noto come oggetto utente. In questo caso, l'oggetto utente fa riferimento all'oggetto utente di Sam su Contoso.com. L'oggetto utente Fabrikam di Sam è la rappresentazione locale di Sam e viene usato per archiviare informazioni sull'account associato a Sam nel contesto di Fabrikam.com. Su Contoso.com, Sam ha il ruolo di consulente DevOps senior. In Fabrikam, Sam ha il ruolo di terzista per macchine virtuali. Su Contoso.com, Sam non è responsabile né autorizzato a gestire macchine virtuali. In Fabrikam.com, questa è la sua unica funzione lavorativa. Sam continua ad avere un unico insieme di credenziali di cui tenere traccia, ovvero le credenziali rilasciate da Contoso.com.

Se una chiamata acquireToken ha esito positivo, verrà visualizzato un riferimento a un oggetto IAccount che può essere usato nelle richieste acquireTokenSilent successive.

IMultiTenantAccount

Se si dispone di un'app che accede alle attestazioni relative a un account da ognuno dei tenant in cui è rappresentato l'account, è possibile eseguire il cast di oggetti IAccount a IMultiTenantAccount. Questa interfaccia fornisce una mappa di ITenantProfiles, collegati con chiave in base all'ID tenant, che consente di accedere alle attestazioni appartenenti all'account in ognuno dei tenant a cui è stato richiesto un token, in relazione all'account corrente.

Le attestazioni alla radice di IAccount e IMultiTenantAccount contengono sempre le attestazioni del tenant principale. Se non è ancora stata effettuata la richiesta di un token nel tenant principale, questa raccolta sarà vuota.

Altre modifiche

Usare il nuovo AuthenticationCallback

// Existing ADAL Interface
public interface AuthenticationCallback<T> {

    /**
     * This will have the token info.
     *
     * @param result returns <T>
     */
    void onSuccess(T result);

    /**
     * Sends error information. This can be user related error or server error.
     * Cancellation error is AuthenticationCancelError.
     *
     * @param exc return {@link Exception}
     */
    void onError(Exception exc);
}
// New Interface for Interactive AcquireToken
public interface AuthenticationCallback {

    /**
     * Authentication finishes successfully.
     *
     * @param authenticationResult {@link IAuthenticationResult} that contains the success response.
     */
    void onSuccess(final IAuthenticationResult authenticationResult);

    /**
     * Error occurs during the authentication.
     *
     * @param exception The {@link MsalException} contains the error code, error message and cause if applicable. The exception
     *                  returned in the callback could be {@link MsalClientException}, {@link MsalServiceException}
     */
    void onError(final MsalException exception);

    /**
     * Will be called if user cancels the flow.
     */
    void onCancel();
}

// New Interface for Silent AcquireToken
public interface SilentAuthenticationCallback {

    /**
     * Authentication finishes successfully.
     *
     * @param authenticationResult {@link IAuthenticationResult} that contains the success response.
     */
    void onSuccess(final IAuthenticationResult authenticationResult);

    /**
     * Error occurs during the authentication.
     *
     * @param exception The {@link MsalException} contains the error code, error message and cause if applicable. The exception
     *                  returned in the callback could be {@link MsalClientException}, {@link MsalServiceException} or
     *                  {@link MsalUiRequiredException}.
     */
    void onError(final MsalException exception);
}

Eseguire la migrazione a nuove eccezioni

In ADAL è presente un solo tipo di eccezione, AuthenticationException, che include un metodo per recuperare il valore di enumerazione ADALError. In MSAL è presente una gerarchia di eccezioni, ognuna delle quali ha un proprio insieme di codici di errore specifici associati.

Eccezione Descrizione
MsalArgumentException Generata se uno o più argomenti di input non sono validi.
MsalClientException Generata se l'errore è sul lato client.
MsalDeclinedScopeException Generata se uno o più ambiti richiesti sono stati rifiutati dal server.
MsalException Generata da MSAL e selezionata per impostazione predefinita.
MsalIntuneAppProtectionPolicyRequiredException Generata se la risorsa ha criteri di protezione MAMCA abilitati.
MsalServiceException Generata se l'errore è sul lato server.
MsalUiRequiredException Generata se il token non può essere aggiornato in modo automatico.
MsalUserCancelException Generata se l'utente ha annullato il flusso di autenticazione.

Conversione da ADALError a MsalException

Se si rilevano questi errori in ADAL... ...queste eccezioni MSAL:
Nessun ADALError equivalente MsalArgumentException
  • ADALError.ANDROIDKEYSTORE_FAILED
  • ADALError.AUTH_FAILED_USER_MISMATCH
  • ADALError.DECRYPTION_FAILED
  • ADALError.DEVELOPER_AUTHORITY_CAN_NOT_BE_VALIDED
  • ADALError.DEVELOPER_AUTHORITY_IS_NOT_VALID_INSTANCE
  • ADALError.DEVELOPER_AUTHORITY_IS_NOT_VALID_URL
  • ADALError.DEVICE_CONNECTION_IS_NOT_AVAILABLE
  • ADALError.DEVICE_NO_SUCH_ALGORITHM
  • ADALError.ENCODING_IS_NOT_SUPPORTED
  • ADALError.ENCRYPTION_ERROR
  • ADALError.IO_EXCEPTION
  • ADALError.JSON_PARSE_ERROR
  • ADALError.NO_NETWORK_CONNECTION_POWER_OPTIMIZATION
  • ADALError.SOCKET_TIMEOUT_EXCEPTION
MsalClientException
Nessun ADALError equivalente MsalDeclinedScopeException
  • ADALError.APP_PACKAGE_NAME_NOT_FOUND
  • ADALError.BROKER_APP_VERIFICATION_FAILED
  • ADALError.PACKAGE_NAME_NOT_FOUND
MsalException
Nessun ADALError equivalente MsalIntuneAppProtectionPolicyRequiredException
  • ADALError.SERVER_ERROR
  • ADALError.SERVER_INVALID_REQUEST
MsalServiceException
  • ADALError.AUTH_REFRESH_FAILED_PROMPT_NOT_ALLOWED
MsalUiRequiredException
Nessun ADALError equivalente MsalUserCancelException

Registrazione da ADAL a MSAL

// Legacy Interface
    StringBuilder logs = new StringBuilder();
    Logger.getInstance().setExternalLogger(new ILogger() {
            @Override
            public void Log(String tag, String message, String additionalMessage, LogLevel logLevel, ADALError errorCode) {
                logs.append(message).append('\n');
            }
        });
// New interface
  StringBuilder logs = new StringBuilder();
  Logger.getInstance().setExternalLogger(new ILoggerCallback() {
      @Override
      public void log(String tag, Logger.LogLevel logLevel, String message, boolean containsPII) {
          logs.append(message).append('\n');
      }
  });

// New Log Levels:
public enum LogLevel
{
    /**
     * Error level logging.
     */
    ERROR,
    /**
     * Warning level logging.
     */
    WARNING,
    /**
     * Info level logging.
     */
    INFO,
    /**
     * Verbose level logging.
     */
    VERBOSE
}