2015-06-11 13 views
21

Я столкнулся OAuth2 JWT маркер проверки исключений последний час (так что никто не может получить доступ к моей приложения):Google OAuth2 JWT исключением маркера проверки

java.security.SignatureException: длина подписи не правильно: есть 256, но ожидал 128. Я использую google-http-client 1.20.0 и Java 1.7.0. Такая же конфигурация работала до сих пор - любые идеи?

Stacktrace 

java.security.SignatureException: Signature length not correct: got 256 but was expecting 128 
    at sun.security.rsa.RSASignature.engineVerify(Unknown Source) ~[na:1.7.0_45] 
    at java.security.Signature$Delegate.engineVerify(Unknown Source) ~[na:1.7.0_45] 
    at java.security.Signature.verify(Unknown Source) ~[na:1.7.0_45] 
    at com.google.api.client.util.SecurityUtils.verify(SecurityUtils.java:164) ~[google-http-client-1.20.0.jar:1.20.0] 
+0

Такая же проблема здесь и с использованием Java 1.8.0_45. – brunnsbe

+0

Я использую этот механизм в приложении Google при использовании токенов доступа из учетной записи менеджера учетных записей google. (Только что начал получать их час назад) –

+1

@ user3686724 Какую аудиторию вы задали для GoogleIdTokenVerifier? Используете ли вы идентификатор клиента или идентификатор токена? (Мы сталкиваемся с той же проблемой за последние 60 минут) – orrsella

ответ

7

Такая же проблема здесь, я добавил исходный код GoogleIdTokenVerifier в мой проект и изменил метод:

public boolean verify(GoogleIdToken googleIdToken) throws GeneralSecurityException, IOException { 
    // check the payload 
    if (!super.verify(googleIdToken)) { 
     return false; 
    } 
    // verify signature 
    for (PublicKey publicKey : publicKeys.getPublicKeys()) { 
     try { 
     if (googleIdToken.verifySignature(publicKey)) { 
      return true; 
      } 
    } catch (Exception e) { 
     System.err.println("Verify Token:" + e); 
    } 
    } 
    return false; 
    } 

просто обрабатывать исключения, второй сертификат работает отлично.

Edit: вы можете создать подкласс, как Erik-z предложил, если вы хотите, чтобы сделать его более чистым:

Edit 2: Я не могу заставить его работать, используя код ниже, я буду придерживаться уродливого хака выше.

package com.my.project.package; 

import java.io.IOException; 
import java.security.GeneralSecurityException; 
import java.security.PublicKey; 

import com.google.api.client.auth.openidconnect.IdTokenVerifier; 
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken; 
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier; 
import com.google.api.client.http.HttpTransport; 
import com.google.api.client.json.JsonFactory; 

// Remember to remove this class later by making it deprecated 
@Deprecated 
public class GoogleIdTokenVerifier2 extends GoogleIdTokenVerifier { 

    // Add constructors as needed 
    public GoogleIdTokenVerifier2(HttpTransport transport, JsonFactory jsonFactory) { 
     super(transport, jsonFactory); 
    } 

    @Override 
    public boolean verify(GoogleIdToken googleIdToken) throws GeneralSecurityException, IOException { 
     // check the payload 
     if (!((IdTokenVerifier)this).verify(googleIdToken)) { 
      return false; 
     } 
     // verify signature 
     for (PublicKey publicKey : getPublicKeysManager().getPublicKeys()) { 
      try { 
       if (googleIdToken.verifySignature(publicKey)) { 
        return true; 
       } 
      } catch (Exception e) { 
       System.err.println("Verify Token:" + e); 
      } 
     } 
     return false; 
    } 
} 
5

Не думаю, что это окончательное решение, но временная работа, вокруг которого, безусловно, работает, чтобы изменить аудиторию проверяющего к tokenId.

GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory).setAudience(Arrays.asList(clientId)).build(); 

в

GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory) 
        .setAudience(Arrays.asList(tokenResponse.getIdToken())).build(); 
+0

Спасибо, Иттай! Это обходное решение также работает с моим кодом. Хорошая остановка для серьезной проблемы производства для моей компании. – kennbrodhagen

+0

рад слышать :-) Я думаю, но не уверен, что эффективно это просто отключает проверку. Возможно, Google затвердел, это проверки сертификатов, и это вызвало внезапный всплеск. – Ittai

2

Первопричина находится на стороне Google, то сертификаты в формате JSON в плохом порядке:

https://www.googleapis.com/oauth2/v1/certs

Вы можете настроить порядок их , например:

http://test.gacivs.info/frontend/certs.json

После, вы можете указать свой собственный адрес (или используя мое :) в формате JSON с помощью метода GooglePublicKeysManager.setPublicCertsEncodedUrl (...):

final GoogleIdToken idToken = GoogleIdToken.parse(JSON_FACTORY, token); 
final GooglePublicKeysManager manager = new GooglePublicKeysManager.Builder(HTTP_TRANSPORT, JSON_FACTORY).setPublicCertsEncodedUrl(CUSTOM_CERTS_URL).build(); 
final GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(manager).setAudience(Arrays.asList(CLIENT_ID)).build(); 
verifier.verify(idToken); 

... и это работает.

Надеется, что Google решить проблему в ближайшее время ... :)

+0

О, это исправлено. :) –

0

Это скопировано из моего ответа here, но более актуально для тех, кто не использует Google Cloud Endpoint (соответствующий этот вопрос). Проблема заключается в следующем:

  • RSA имеет подписи переменной длины, в зависимости от размера ключа.
  • Google обновил пары ключей, которые он использует для подписания, и теперь один из ключевых пар порождает другую длину подпись от другого
  • java.security.Signature.verify(byte[] signature) бросает исключение, если подпись неправильной длины передается (вместо возвращения ложных сведений, обычно это делается, когда подпись не соответствует ключу)

Самое простое решение, чтобы обернуть проверки вызова (try...catch) и возвращает ложь, если вы получите исключение

Глядя на пример кода на http://android-developers.blogspot.com/2013/01/verifying-back-end-calls-from-android.html , похоже, что вы можете ch Анж эта линия:

GoogleIdToken token = GoogleIdToken.parse(mJFactory, tokenString); 

в

JsonWebSignature jws = JsonWebSignature.parser(mJFactory).setPayloadClass(Payload.class).parse(tokenString); 
GoogleIdToken token = new GoogleIdToken(jws.getHeader(), (Payload) jws.getPayload(), jws.getSignatureBytes(), jws.getSignedContentBytes()) { 
    public boolean verify(GoogleIdTokenVerifier verifier) 
    throws GeneralSecurityException, IOException { 
     try { 
      return verifier.verify(this); 
     } catch (java.security.SignatureException e) { 
      return false; 
     } 
    } 
}; 

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

0

Мне кажется, что библиотеки могут плохо себя вести. В качестве альтернативы проверке токена в автономном режиме вы можете использовать конечные точки OAuth2 от Google для проверки токенов. Основной пример из API explorer can be seen here.

Вы можете проверить маркер с завитка командой curl https://www.googleapis.com/oauth2/v2/tokeninfo?id_token=[id_token], например:

curl https://www.googleapis.com/oauth2/v2/tokeninfo?id_token=eyJhbGciOiJSUzI1NiIsImtpZCI6IjRlYjczOTg0MzBkNTNjZjZjNGZkMGU5YmM4NzkzZWViZWNkMWY1NWUifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwic3ViIjoiMTA3Mzc3MTkxNjgxODAyNjY5ODY2IiwiYXpwIjoiMTE2MjY4ODY3NTIuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdF9oYXNoIjoieGJSVGJOdFJYRnJzcUJHTkRtRTR6USIsImF1ZCI6IjExNjI2ODg2NzUyLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiY19oYXNoIjoiU3JFa25WczRUejhQSWJicExnNXF2QSIsImlhdCI6MTQzNDA0MTY5OSwiZXhwIjoxNDM0MDQ1Mjk5fQ.vqQXCTFfbDqpTYnfFrDD7m68oEuGqd8NWa4s9wstOrrcyuVKUsqFXM_2bH-un_4C8UBvqtQEyzU_-53DxgvhCHQ7S0W-wtQ9YMoJcy7iL1wDjcy1p7aFVoeGCoqxWv1vzlWTUDu_FnD9oIBSAawyDexvRwwGxN8O1D8nzyj__1DQ_ivxIMF-j1W89mc7adK4p5B8ioZA_PI-AGawX2Nm8t58yBMIYrTk0XExr9Pf4eHHRGbrQxcd0ERGHbRMYuG6k-MzdnVNHIScgZ3Cixx9v15PbQ5hXExNvleifG_Wk3Thnz0j6Uacr4fbi-mO93-h8c0r3BSvQ270_JqlpL5q5Q 
0

Если вы не хотите (или не может) изменить источник библиотеки Google, вы можете просто расширить GoogleIdTokenVerifier. (вы должны дублировать другой метод, который обращается к некоторым частным переменным - к счастью, все они доступны через get-members). Это работает для меня:

GoogleIdTokenVerifier myVerifier = new GoogleIdTokenVerifier(httpTransport, jsonFactory) { 

    public boolean superVerify(IdToken idToken) { 
       return (getIssuer()== null || idToken.verifyIssuer(getIssuer())) 
        && (getAudience() == null || idToken.verifyAudience(getAudience())) 
        && idToken.verifyTime(getClock().currentTimeMillis(), getAcceptableTimeSkewSeconds()); 
    } 


    @Override 
    public boolean verify(GoogleIdToken googleIdToken) throws GeneralSecurityException, IOException { 
     // check the payload 
     if (!superVerify(googleIdToken)) { 
      log.info("superVerify returned false"); 
     return false; 
     } 
     // verify signature 
     for (PublicKey publicKey : getPublicKeysManager().getPublicKeys()) { 
       try { 
         if (googleIdToken.verifySignature(publicKey)) { 
           log.info("verifySignature: success!"); 
           return true; 
         } 
       } catch (Exception e) { 
         log.info("error verifying!", e); 
       } 
     } 
     return false; 
    } 

};