Guia de migração da ADAL para a MSAL para Android

Este artigo destaca as alterações que você precisa fazer para migrar um aplicativo que usa a ADAL para que ele passe a usar a MSAL.

Destaques da diferença

A ADAL trabalha com o ponto de extremidade do Azure Active Directory v1.0. A MSAL funciona com a plataforma de identidade da Microsoft, conhecida anteriormente como ponto de extremidade do Azure Active Directory v 2.0. A plataforma de identidade da Microsoft tem as seguintes diferenças em relação ao Azure Active Directory v1.0:

Oferece suporte a:

  • Identidade Organizacional (Azure Active Directory)

  • Identidades não organizacionais, como Outlook.com, Xbox Live, entre outros

  • (Somente Azure AD B2C) Logon federado com Google, Facebook, Twitter e Amazon

  • Os padrões são compatíveis com:

    • OAuth v2.0
    • OIDC (OpenID Connect)

A API pública da MSAL introduz alterações importantes, incluindo:

  • Um novo modelo para acessar tokens:
    • A ADAL fornece acesso a tokens através do AuthenticationContext, que representa o servidor. A MSAL fornece acesso a tokens através do PublicClientApplication, que representa o cliente. Os desenvolvedores do cliente não precisam criar uma nova instância PublicClientApplication para cada Autoridade com a qual precisam interagir. Apenas uma configuração PublicClientApplication é necessária.
    • Suporte para solicitar tokens de acesso usando escopos além de identificadores de recurso.
    • Suporte para consentimento incremental. Os desenvolvedores podem solicitar escopos à medida que o usuário acessa cada vez mais funcionalidades no aplicativo, incluindo aquelas não incluídas durante o registro do aplicativo.
    • As autoridades não são mais validadas em tempo de execução. Em vez disso, o desenvolvedor declara uma lista de "autoridades conhecidas" durante o desenvolvimento.
  • Alterações de API de token:
    • Na ADAL, AcquireToken() faz uma solicitação silenciosa. Caso falhe, ela faz uma solicitação interativa. Como resultado deste comportamento, alguns desenvolvedores confiaram apenas em AcquireToken, o que resultou na solicitação inesperada de credenciais do usuário em alguns momentos. A MSAL exige que os desenvolvedores sejam intencionais sobre quando o usuário recebe um prompt de interface de usuário.
      • AcquireTokenSilent sempre resulta em uma solicitação silenciosa que seja bem-sucedida ou falhe.
      • AcquireToken sempre resulta em uma solicitação que solicita ao usuário através da interface do usuário.
  • A MSAL dá suporte à entrada de um navegador padrão ou de uma exibição da Web inserida:
    • Por padrão, o navegador padrão no dispositivo é usado. Isso permite que a MSAL use o estado de autenticação (cookies) que pode já estar presente para uma ou mais contas conectadas. Se nenhum estado de autenticação estiver presente, a autenticação durante a autorização através da MSAL resultará na criação de um estado de autenticação (cookies) para o benefício de outros aplicativos Web que serão usados no mesmo navegador.
  • Modelo de nova exceção:
    • As exceções definem de forma mais clara o tipo de erro que ocorreu e o que o desenvolvedor precisa fazer para resolvê-lo.
  • A MSAL dá suporte a objetos de parâmetro para chamadas AcquireToken e AcquireTokenSilent.
  • A MSAL dá suporte à configuração declarativa para:
    • ID do Cliente, URI de Redirecionamento.
    • Navegador Padrão vs Incorporado
    • Autoridades
    • Configurações de HTTP, como tempo limite de leitura e conexão

Registro e migração do aplicativo para a MSAL

Você não precisa alterar o registro do aplicativo existente para usar a MSAL. Se você quiser aproveitar o consentimento incremental/progressivo, talvez seja necessário examinar o registro para identificar os escopos específicos que você deseja solicitar de forma incremental. Abaixo você encontra mais informações sobre escopos e consentimento incremental.

Em seu registro de aplicativo no portal, você verá uma guia Permissões de API. Isso fornece uma lista das APIs e permissões (escopos) às quais seu aplicativo está atualmente configurado para solicitar acesso. Ele também mostra uma lista dos nomes de escopo associados a cada permissão de API.

Com a ADAL e o ponto de extremidade do Azure AD v1, o consentimento do usuário para os recursos de sua propriedade foi concedido no primeiro uso. Com a MSAL e a plataforma de identidade da Microsoft, o consentimento pode ser solicitado de forma incremental. O consentimento incremental é útil para permissões que um usuário pode considerar como alto privilégio, ou pode perguntar se não foi fornecida uma explicação clara do por que a permissão é necessária. Na ADAL, essas permissões podem ter resultado no abandono pelo usuário da entrada em seu aplicativo.

Dica

Use o consentimento incremental para fornecer contexto adicional aos usuários sobre por que seu aplicativo precisa de uma permissão.

Os administradores da organização podem consentir com as permissões solicitadas por seu aplicativo em nome de todos os membros de sua organização. Algumas organizações só permitem que os administradores forneçam consentimento em aplicativos. O consentimento do administrador exige que você inclua todas as permissões e escopos de API usados pelo seu aplicativo no registro do aplicativo.

Dica

Embora você possa solicitar um escopo usando a MSAL para algo não incluído no registro do aplicativo, recomendamos que você atualize o registro do aplicativo para incluir todos os recursos e escopos aos quais um usuário pode conceder permissão.

Migrando de IDs do recurso para escopos

Autenticar e solicitar autorização para todas as permissões na primeira utilização

Se você estiver usando a ADAL e não precisar usar o consentimento incremental, a maneira mais simples de começar a usar a MSAL é fazer uma acquireToken solicitação usando o novo AcquireTokenParameter objeto e definindo o valor da ID do recurso.

Cuidado

Não é possível definir os escopos e uma ID do recurso. A tentativa de definir ambos resultará em IllegalArgumentException.

Isso resultará no mesmo comportamento v1 que você está acostumado. Todas as permissões solicitadas no registro do aplicativo são solicitadas pelo usuário durante sua primeira interação.

Autenticar e solicitar permissões somente quando necessário

Para aproveitar o consentimento incremental, faça uma lista de permissões (escopos) que seu aplicativo usa do registro do aplicativo, e organize-a em duas listas com base em:

  • Quais escopos você deseja solicitar durante a primeira interação do usuário com seu aplicativo durante a entrada.
  • As permissões associadas a um recurso importante do aplicativo que você também precisará explicar ao usuário.

Depois de organizar os escopos, organize cada lista de acordo com o recurso (API) para o qual você deseja solicitar um token. Bem como quaisquer outros escopos que você deseja que o usuário autorize ao mesmo tempo.

O objeto parâmetros usado para fazer sua solicitação para a MSAL dá suporte a:

  • Scope: lista de escopos para os quais você deseja solicitar autorização e receber um token de acesso.
  • ExtraScopesToConsent: uma lista adicional de escopos para os quais você deseja solicitar autorização enquanto estiver solicitando um token de acesso para outro recurso. Essa lista de escopos permite minimizar o número de vezes que você precisa solicitar a autorização do usuário. Isso significa menos autorização de usuário ou solicitações de consentimento.

Migrar do AuthenticationContext para o PublicClientApplications

Construindo o PublicClientApplication

Ao usar a MSAL, você cria uma instância de PublicClientApplication. Esse objeto modela a identidade do aplicativo, e é usado para fazer solicitações a uma ou mais autoridades. Com esse objeto, você configurará a identidade do cliente, o URI de redirecionamento, a autoridade padrão, se deseja usar o navegador do dispositivo ou a exibição da Web incorporada, o nível de log e muito mais.

Você pode configurar esse objeto declarativamente com JSON, que você fornece como um arquivo ou armazena como um recurso em seu APK.

Embora esse objeto não seja um singleton, ele usa, internamente, Executors compartilhado para solicitações interativas e silenciosas.

Entre Empresas

Na ADAL, todas as organizações para as quais você solicita tokens de acesso exigem uma instância separada do AuthenticationContext. Isto não é mais uma exigência na MSAL. Você pode especificar a autoridade da qual deseja solicitar um token como parte de sua solicitação silenciosa ou interativa.

Migrar da validação de autoridade para autoridades conhecidas

A MSAL não possui um sinalizador para habilitar ou desabilitar a validação de autoridade. A validação de autoridade é um recurso da ADAL e, nas primeiras versões da MSAL, isso impede que seu código solicite tokens de uma autoridade potencialmente mal-intencionada. A MSAL agora recupera uma lista de autoridades conhecidas da Microsoft e mescla essa lista com as autoridades que você especificou em sua configuração.

Dica

Se você for um usuário do B2C (Business to Consumer) do Azure, isso significa que você não precisa mais desabilitar a validação de autoridade. Em vez disso, inclua cada uma das políticas do Azure AD B2C com suporte como autoridades em sua configuração da MSAL.

Se você tentar usar uma autoridade que não seja conhecida pela Microsoft e não esteja incluída na sua configuração, você obterá UnknownAuthorityException.

Log

Agora você pode configurar o log de forma declarativa como parte de sua configuração, da seguinte forma:

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

Migrar de UserInfo para Conta

Na ADAL, o AuthenticationResult fornece um objeto UserInfo usado para recuperar informações sobre a conta autenticada. O termo "usuário", que significava um agente de software ou humano, foi aplicado de uma forma que dificultou a comunicação de que alguns aplicativos dão suporte a um único usuário (seja um agente de software ou humano) que tenha várias contas.

Considere uma conta bancária. Você pode ter mais de uma conta em mais de uma instituição financeira. Ao abrir uma conta, você (o usuário) recebe credenciais, como um cartão & uma senha, que são usadas para acessar seu saldo, pagamentos de cobrança, entre outros, para cada conta. Essas credenciais só podem ser usadas na instituição financeira que as emitiu.

Por analogia, como nas contas em uma instituição financeira, as contas na plataforma de identidade da Microsoft são acessadas usando credenciais. Essas credenciais são registradas ou emitidas pela Microsoft. Ou pela Microsoft em nome de uma organização.

A diferença entre a plataforma de identidade da Microsoft e uma instituição financeira, nessa analogia, é que a plataforma de identidade da Microsoft fornece uma estrutura que permite que um usuário use uma conta, bem como suas credenciais associadas, para acessar recursos que pertencem a diversos indivíduos e organizações. É como poder usar um cartão emitido por um banco em outra instituição financeira. Isso funciona porque todas as organizações em questão estão usando a plataforma de identidade da Microsoft, o que permite que uma conta seja usada em várias organizações. Veja um exemplo:

O Sam trabalha na Contoso.com, mas gerencia as máquinas virtuais do Azure que pertencem ao Fabrikam.com. Para que o Sam gerencie as máquinas virtuais da Fabrikam, ele precisa estar autorizado a acessá-las. Esse acesso pode ser concedido adicionando a conta do Sam ao Fabrikam.com e concedendo a ele uma função que permita que ele trabalhe com as máquinas virtuais. Isto seria feito no portal do Azure.

A inclusão da conta Contoso.com do Sam como um membro de Fabrikam.com resultaria na criação de um novo registro no Azure Active Directory da Fabrikam.com para o Sam. O registro do Sam no Azure Active Directory é conhecido como um objeto de usuário. Nesse caso, esse objeto de usuário apontaria de volta para o objeto de usuário do Sam no Contoso.com. O objeto de usuário da Fabrikam do Sam é a representação local do Sam, e seria usado para armazenar informações sobre a conta associada ao Sam no contexto da Fabrikam.com. Na Contoso.com, o cargo do Sam é Consultor Sênior de DevOps. Na Fabrikam, o cargo do Sam é Prestador de Serviço-Máquinas Virtuais. Na Contoso.com, o Sam não é responsável por, nem está autorizado a gerenciar máquinas virtuais. Na Fabrikam.com, essa é sua única função de trabalho. No entanto, o Sam ainda tem apenas um conjunto de credenciais para controlar, que são as credenciais emitidas pela Contoso.com.

Quando uma chamada acquireToken bem-sucedida for feita, você verá uma referência a um IAccount objeto que pode ser usado em solicitações acquireTokenSilent posteriores.

IMultiTenantAccount

Se você tiver um aplicativo que acesse declarações sobre uma conta de cada locatário no qual a conta é representada, você pode converter objetos IAccount em IMultiTenantAccount. Essa interface fornece um mapa de ITenantProfiles, inserido pela ID do locatário, que permite que você acesse as declarações que pertencem à conta em cada um dos locatários dos quais você solicitou um token, em relação à conta atual.

As declarações na raiz de IAccount e IMultiTenantAccount sempre contêm as declarações do locatário da página inicial. Se você ainda não fez uma solicitação para um token no locatário da página inicial, essa coleção estará vazia.

Outras alterações

Use a AuthenticationCallback nova

// 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);
}

Migrar para as novas exceções

Na ADAL, há um tipo de exceção, AuthenticationException, que inclui um método para recuperar o valor ADALError enumerado. Na MSAL, há uma hierarquia de exceções, e cada uma tem seu próprio conjunto de códigos de erro específicos associados.

Exceção Descrição
MsalArgumentException Gerado se um ou mais argumentos de entrada forem inválidos.
MsalClientException Gerado se o erro for do lado do cliente.
MsalDeclinedScopeException Gerado se um ou mais escopos solicitados foram recusados pelo servidor.
MsalException Exceção verificada padrão gerada pela MSAL.
MsalIntuneAppProtectionPolicyRequiredException Gerado se a política de proteção MAMCA estiver habilitada no recurso.
MsalServiceException Gerado se o erro for do lado do servidor.
MsalUiRequiredException Gerado se o token não puder ser atualizado silenciosamente.
MsalUserCancelException Gerado se o usuário cancelou o fluxo de autenticação.

Tradução do ADALError para MsalException

Se você estiver capturando esses erros na ADAL... ... capture estas exceções da MSAL:
Nenhum 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
Nenhum ADALError equivalente MsalDeclinedScopeException
  • ADALError.APP_PACKAGE_NAME_NOT_FOUND
  • ADALError.BROKER_APP_VERIFICATION_FAILED
  • ADALError.PACKAGE_NAME_NOT_FOUND
MsalException
Nenhum ADALError equivalente MsalIntuneAppProtectionPolicyRequiredException
  • ADALError.SERVER_ERROR
  • ADALError.SERVER_INVALID_REQUEST
MsalServiceException
  • ADALError.AUTH_REFRESH_FAILED_PROMPT_NOT_ALLOWED
MsalUiRequiredException
Nenhum ADALError equivalente MsalUserCancelException

Registro na ADAL no Registro na 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
}