Вход в Google: «Сертификат для ключа с идентификатором xxxx не найден» при использовании пакета Python google-auth - PullRequest
0 голосов
/ 23 декабря 2018

Я поддерживаю сайт и его мобильные приложения (iOS и Android).Для входа в Google в мобильном приложении я использую пакет google-auth Python на стороне сервера.

Примерно месяц назад я начал получать сообщения об ошибках, связанных с Google.Вход со стороны сервера.Сообщение об ошибке выглядит следующим образом:

Сертификат для идентификатора ключа 728f4016652079b9ed99861bb09bafc5a45baa86 не найден.

Серверная часть аутентификации входа в систему Google следует за этим документом:

from google.oauth2 import id_token
from google.auth.transport import requests

# ...

try:
    # The following line may raise ValueError with message:
    # Certificate for key id xxxx not found.
    id_info = id_token.verify_oauth2_token(google_id_token, requests.Request())

    if id_info['aud'] not in VALID_CLIENT_IDS:
        logger.error('Invalid aud from Google ID token: %s', id_info['aud'])
        raise ValueError('Unverified audience.')
    # ...
except ValueError as exc:
    logger.error('Fail to verify Google ID token: %s', exc, extra={'request': request})

Ошибка происходит от модуля google.auth.jwt при проверке выпущенного Google JWT по списку общедоступных сертификатов Google.

Погружаясь в код google-auth , я вижу, что функция verify_oauth2_token() извлекает публичные сертификаты Google с URL-адреса https://www.googleapis.com/oauth2/v1/certs. Кажется, что иногда для некоторых токенов Google ID, отправляемых сВ некоторых телефонах Android идентификатор ключа не может быть найден в этом URL.

Вот некоторые другие детали, которые могут быть полезны:

  • Похоже, что приложение для iOS не имеет такого типавопрос.Из заголовка USER_AGENT видно, что ошибка возникает только в приложении для Android (USER_AGENT=okhttp/3.11.0).И это происходит только в некоторых устройствах Android, а не во всех.
  • Мне было интересно, если это происходит только для телефонов Android из Китая (например, если они подключаются через VPN).Поэтому я также проверил IP-адрес пользователя.Но оказалось, что некоторые из этих пользователей были из Европы.
  • Какой-то идентификатор ключа снова и снова повторяется в журналах ошибок сервера.Например, идентификатор ключа aa436c3f63b281ce0d976da0b51a34860ff960eb виден десятки раз, с начала ноября до настоящего времени (конец декабря).
  • Я постоянно вижу эту ошибку, несколько раз (10 ~ 30 раз) каждыйдень.

Мой сайт работает в следующей среде:

  • ОС: Linux (CentOS 7) 64-битная
  • Apache 2 с mod_wsgi 4.5.24
  • Python 3.6.7 и Django 2.1.2
  • google-auth версия: пробовал и 1.3.0 и 1.6.1

так как не смогвоспроизвести эту проблему либо на моем iPhone, либо на моем телефоне Android (Huawei P20, куплен во Франции), я полностью застрял.

Но у одного из моих друзей возникла эта проблема, и он купил свой Androidтелефон из Гонконга.Это заставляет меня задуматься, возможно ли, что в некоторых странах для входа в Google используются другие сертификаты, отличные от общедоступных, по адресу https://www.googleapis.com/oauth2/v1/certs?

Не думаю, что это ошибка в пакете google-auth,Мне интересно, слышал ли кто-нибудь из вас об этой ошибке, и мог бы дать мне подсказку о ее возможной причине?

Заранее спасибо!

1 Ответ

0 голосов
/ 24 июня 2019

ОК, я наконец понял это.Я публикую свои выводы здесь, надеясь, что это может помочь кому-то еще.

В коде Python на стороне сервера нет ничего плохого.Причина, по которой это не удалось, заключалась в том, что клиентское приложение отправило маркер идентификатора Google ID с истекшим сроком действия.

Вот исправленная версия моей функции LoginActivity:

...

@OnClick(R.id.google_sign_in_button)
void loginWithGoogle() {
    //
    // If user has already signed in to our app with Google, sign him out first.
    //
    // NOTE: This step is required, or the ID token might not pass the server-side validation!
    //
    // After sign-in, we need to get the user's ID token issued and signed by Google, and send
    // it back to our server for validation.
    //
    // Google is rotating its OAuth2 certificate regularly, so an old ID token issued long time
    // ago by Google might not pass the server-side validation -- if the certificate used to
    // sign the ID token has expired.
    //
    // This may happen when user has already signed in to our app with Google. In such case,
    // the ID token we get from the user's Google account is obsolete. Our server will fail to
    // validate it, with the error message:
    //
    //     Fail to verify Google ID token: Certificate for key id xxx not found.
    //
    // Google recommends using the `silentSignIn` method for the already-signed-in user
    // (see step 2 of: https://developers.google.com/identity/sign-in/android/backend-auth).
    // For the sake of simplicity, we don't do that. Instead, we go directly to step 3
    // by signing user out, giving him the option to sign-in again.
    //
    final GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this);
    if (account != null) {
        // User has already signed in: Sign out and sign in again.
        // NOTE: THIS IS THE FIX TO MY PROBLEM.
        mGoogleSignInClient.signOut().addOnCompleteListener(this, new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                startGoogleSignInActivity();
            }
        });
    } else {
        // User is not yet signed in: Start the Google sign-in flow.
        startGoogleSignInActivity();
    }
}

private void startGoogleSignInActivity() {
    final Intent intent = mGoogleSignInClient.getSignInIntent();
    startActivityForResult(intent, REQUEST_LOGIN_WITH_GOOGLE);
}

Ключевой момент заключается в следующем: мне нужнопроверьте, если пользователь уже вошел в систему с Google.Если да, мне нужно выйти из системы и перезапустить действие «Войти в Google».

Поскольку Android имеет встроенную поддержку учетной записи Google, я полагаю, что ОС может кэшировать учетную запись Google пользователя, если пользовательуже аутентифицирован (в каком-то другом приложении или в масштабе всей системы).Но эта кэшированная учетная запись может содержать маркер идентификатора с истекшим сроком действия.Принудительный выход пользователя из системы и повторный вход предоставят мне новый новый токен ID.

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

...