AzureAD для Android выдает ошибку ADALError.AUTH_REFRESH_FAILED_PROMPT_NOT_ALLOWED

У меня есть приложение, в котором пользователь выполняет аутентификацию в Office365 с помощью библиотеки AzureAD для Android. .

Работает хорошо, пользователи могут аутентифицироваться и работать с приложением. К сожалению, через некоторое время они начинают нажимать AuthenticationException с кодом ADALError.AUTH_REFRESH_FAILED_PROMPT_NOT_ALLOWED в качестве кода ошибки.

Я проверил исходный код AzurelAD. Единственное место, где решается эта проблема, - это acquireTokenAfterValidation() метод:

private AuthenticationResult acquireTokenAfterValidation(CallbackHandler callbackHandle,
        final IWindowComponent activity, final boolean useDialog,
        final AuthenticationRequest request) {
    Logger.v(TAG, "Token request started");

    // BROKER flow intercepts here
    // cache and refresh call happens through the authenticator service
    if (mBrokerProxy.canSwitchToBroker()
            && mBrokerProxy.verifyUser(request.getLoginHint(),
                    request.getUserId())) {
        .......
        Logger.v(TAG, "Token is not returned from backgroud call");
        if (!request.isSilent() && callbackHandle.callback != null && activity != null) {
            ....
        } else {
            // User does not want to launch activity
            String msg = "Prompt is not allowed and failed to get token:";
            Logger.e(TAG, msg, "", ADALError.AUTH_REFRESH_FAILED_PROMPT_NOT_ALLOWED);
            callbackHandle.onError(new AuthenticationException(
                    ADALError.AUTH_REFRESH_FAILED_PROMPT_NOT_ALLOWED, msg));
        }

        // It will start activity if callback is provided. Return null here.
        return null;
    } else {
        return localFlow(callbackHandle, activity, useDialog, request);
    }
}

Мой исходный код:

authenticator.getAccessTokenSilentSync(getMailService());

public class Authenticator {
    ..............
    public String getAccessTokenSilentSync(ServiceInfo serviceInfo) {
        throwIfNotInitialized();
        return getAuthenticationResultSilentSync(serviceInfo).getAccessToken();
    }

    private AuthenticationResult getAuthenticationResultSilentSync(ServiceInfo serviceInfo) {
        try {
            return authenticationContext.acquireTokenSilentSync(
                    serviceInfo.ServiceResourceId,
                    Client.ID,
                    userIdentity.getAdUserId());
        } catch (AuthenticationException ex) {
            // HERE THE EXCEPTION IS HANDLED.
        }
    }
    ..............
} 

Stacktrace я получаю:

    <package name>.data_access.error_handler.AuthenticationExceptionWithServiceInfo: Refresh token is failed and prompt is not allowed
    at com.microsoft.aad.adal.AuthenticationContext.localFlow(AuthenticationContext.java:1294)
    at com.microsoft.aad.adal.AuthenticationContext.acquireTokenAfterValidation(AuthenticationContext.java:1229)
    at com.microsoft.aad.adal.AuthenticationContext.acquireTokenLocalCall(AuthenticationContext.java:1123)
    at com.microsoft.aad.adal.AuthenticationContext.refreshToken(AuthenticationContext.java:1609)
    at com.microsoft.aad.adal.AuthenticationContext.localFlow(AuthenticationContext.java:1261)
    at com.microsoft.aad.adal.AuthenticationContext.acquireTokenAfterValidation(AuthenticationContext.java:1229)
    at com.microsoft.aad.adal.AuthenticationContext.acquireTokenLocalCall(AuthenticationContext.java:1123)
    at com.microsoft.aad.adal.AuthenticationContext.refreshToken(AuthenticationContext.java:1609)
    at com.microsoft.aad.adal.AuthenticationContext.localFlow(AuthenticationContext.java:1261)
    at com.microsoft.aad.adal.AuthenticationContext.acquireTokenAfterValidation(AuthenticationContext.java:1229)
    at com.microsoft.aad.adal.AuthenticationContext.acquireTokenLocalCall(AuthenticationContext.java:1123)
    at com.microsoft.aad.adal.AuthenticationContext.access$600(AuthenticationContext.java:58)
    at com.microsoft.aad.adal.AuthenticationContext$4.call(AuthenticationContext.java:1072)
    at com.microsoft.aad.adal.AuthenticationContext$4.call(AuthenticationContext.java:1067)
    at java.util.concurrent.FutureTask.run(FutureTask.java:237)

Версия библиотеки AzureAD, которую я использую: 1.1.7 (чтобы не обвинять слишком старую версию - я проверил список изменений с 1.1.7 по 1.1.11 и не нашел ничего, связанного с вопросом)

Проблема: сейчас я рассматриваю эту ошибку как сигнал, через который пользователь переходит на экран входа в систему. На мой взгляд, это ухудшает восприятие пользователем. Тот факт, что это происходит очень часто и затрагивает многих пользователей, еще больше усугубляет ситуацию.

Вопрос: Могу ли я что-то сделать, чтобы избежать AuthenticationException этой ошибки или как-то ее обойти (т. е. избежать повторного ввода учетных данных пользователем).


person Konstantin Loginov    schedule 05.01.2016    source источник
comment
@iambmelton Я сам обрабатываю promt в коде. Поэтому мне интересно, если я получил исключение, слишком ли поздно делать какие-либо попытки явно обновить токен или есть какие-либо обходные пути для этого? Относительно того, является ли acquireTokenSilentSync() правильным методом. Что ж. Это то, что я хочу выяснить. Некоторое время (недели?) Все работает нормально. (Я делаю этот вызов, чтобы получить токен для каждого внутреннего запроса). Потом он истекает. Мое внутреннее ощущение - это слишком быстро истекает.   -  person Konstantin Loginov    schedule 06.01.2016
comment
@iambmelton Хорошо, я понял: это своего рода ожидаемое поведение, что через некоторое время - 2 недели - пользователи снова выкидывают на экран входа в систему, и нет никакого способа предотвратить это. Это печально, но все же полезно знать! (Что касается молчания / отсутствия молчания - да, я делаю молчание, чтобы обрабатывать поток аутентификации вручную, чтобы иметь хороший вид для ввода электронной почты (например, в OneDrive)). Кстати, если превратить свои комментарии в ответ - могу принять   -  person Konstantin Loginov    schedule 07.01.2016
comment
В порядке! Размещено ниже, комментарии тут уберу, чтобы убрать дублирующуюся инфу :)   -  person Brian Melton-Grace - MSFT    schedule 07.01.2016


Ответы (2)


Вы убедились, что AuthenticationContext.acquireTokenSilentSync() действительно является тем методом, который вы хотите вызвать?

В документации указано, что этот метод явно не отображает подсказку. Из документов:

This is sync function. It will first look at the cache and automatically checks for the token expiration. Additionally, if no suitable access token is found in the cache, but refresh token is available, the function will use the refresh token automatically. This method will not show UI for the user. If prompt is needed, the method will return an exception.

Выданный вам токен обновления должен длиться две недели в соответствии с этой книгой AAD. Ожидается, что после истечения срока действия токена обновления пользователи должны пройти повторную аутентификацию. Можете ли вы проверить сетевой трафик с помощью Fiddler или Charles и проверить срок действия токенов? Если вы можете убедиться, что токены не обновляются до истечения срока их действия, это может указывать на ошибку в библиотеке AD.

Чтобы прояснить разницу в методах на AuthenticationContext - есть две категории методов: «тихие» методы (которые не будут отображать диалоговое окно для пользователя в случае, если им потребуется повторная проверка подлинности), и немолчащие. В случае требования повторной аутентификации (или согласия) от пользователя немалые методы будут запускать новое действие, содержащее логин AAD. На этом этапе процесс аутентификации перезапускается.

Кроме того, если вы внесете изменения в регистрацию своего приложения в Azure, например добавите новые области разрешений, ваши пользователи должны будут повторно предоставить согласие, чтобы приложение продолжало обрабатывать их данные.

person Brian Melton-Grace - MSFT    schedule 06.01.2016

Это связано с тем, что вам необходимо обновить свой токен и реализовать это в своем коде, чтобы пользователю не предлагалось войти в систему каждый раз, когда срок действия токена доступа истек. узнайте, как реализовать токен обновления здесь:

https://msdn.microsoft.com/en-us/library/azure/dn645538.aspx

Надеюсь это поможет.

person Mostafa    schedule 06.01.2016