2015-06-11 7 views
21

Ich bin vor OAuth2 JWT Token-Verifizierungs Ausnahme letzte Stunde (so kann niemand meine Anwendung zugreifen):Google OAuth2 JWT Token-Verifizierungs Ausnahme

java.security.SignatureException: Signature Länge nicht korrekt: bekam 256 aber erwartet 128. Ich verwende google-http-client 1.20.0 und Java 1.7.0. Die gleiche Konfiguration hat bisher funktioniert - irgendwelche Ideen?

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

Gleiches Problem hier auch mit Java 1.8.0_45. – brunnsbe

+0

Ich erhalte dies in der Google App-Engine, wenn ich Zugriffstokens aus dem Google-Kontoverwalterkonto verwende. (Sie haben gerade angefangen, sie vor einer Stunde zu erhalten) –

+1

@ user3686724 Welche Zielgruppe haben Sie für GoogleIdTokenVerifier festgelegt? Verwenden Sie die Client-ID oder die Token-ID? (Wir haben das gleiche Problem in den letzten 60 Minuten) – orrsella

Antwort

7

Der gleiche Problem hier, ich den Quellcode von GoogleIdTokenVerifier zu meinem Projekt hinzugefügt und geändert, um die Methode:

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

behandelt nur die Ausnahme, arbeitet das zweite Zertifikat in Ordnung.

Edit: Sie können Unterklasse als Erik-z vorgeschlagen, wenn Sie es sauber machen wollen:

Edit 2: Ich kann nicht damit es funktioniert mit dem Code unten, werde ich oben auf die hässliche Hack bleiben.

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

Glauben Sie nicht, es die endgültige Lösung ist aber eine vorübergehende Behelfslösung, die ist auf jeden Fall funktioniert das Publikum des Prüfers auf die TokenID zu ändern.

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

zu

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

Danke, Ittai! Diese Problemumgehung funktioniert auch mein Code. Gute Notlösung für ein ernstes Produktionsproblem für meine Firma. – kennbrodhagen

+0

froh zu hören :-) Ich denke, aber nicht sicher, dass effektiv dies nur Verifikation deaktiviert. Es ist möglich, dass Google seine Zertifikatsüberprüfungen gehärtet hat, und das hat den plötzlichen Anstieg verursacht. – Ittai

2

Die Ursache auf der Google-Seite ist, ist die certs im JSON in schlechter Reihenfolge:

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

Sie die Reihenfolge von ihnen anpassen , so:

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

Nach können Sie Ihre benutzerdefinierte URL (oder mit Mine angeben :) der JSON mit dem GooglePublicKeysManager.setPublicCertsEncodedUrl (...) Methode:

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

... und es funktioniert.

Ich hoffe, das Google das Problem beheben bald ... :)

+0

Oh, es ist behoben. :) –

0

Dies ist aus meiner Antwort kopiert here, aber mehr relevant für diejenigen, die nicht mit Google Cloud Endpoint (dieser Frage entspricht). Das Problem wird dadurch verursacht:

  • RSA hat Signaturen variabler Länge, abhängig von der Schlüsselgröße.
  • Google die Schlüsselpaare aktualisierte es zum Signieren verwendet wird, und nun eine der Schlüsselpaar erzeugt eine unterschiedliche Länge Signatur von den anderen
  • java.security.Signature.verify(byte[] signature) gibt eine Ausnahme aus, wenn eine Signatur der falschen Länge übergeben wird (anstatt falsche zurückzukehren die normalerweise erfolgt, wenn eine Signatur den Schlüssel nicht übereinstimmen
  • )

die einfachste Lösung, die überprüfen, rufen Sie (try...catch) zu wickeln ist, und falsch zurück, wenn Sie eine Ausnahme erhalten

Mit Blick auf den Beispielcode auf http://android-developers.blogspot.com/2013/01/verifying-back-end-calls-from-android.html sieht es so aus als könntest du ch ange diese Linie:

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

zu

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

ich leider keine genaue Setup dies zu testen, lassen Sie mich wissen, ob dies für Sie arbeitet.

0

Es sieht für mich aus, als ob die Bibliotheken sich schlecht verhalten. Als Alternative zur Offline-Token-Überprüfung können Sie die OAuth2-Endpunkte von Google zum Überprüfen von Tokens verwenden. Ein grundlegendes Beispiel aus dem API-Explorer can be seen here.

Sie ein Token mit einem curl Befehl curl https://www.googleapis.com/oauth2/v2/tokeninfo?id_token=[id_token] zum Beispiel überprüfen:

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

Wenn Sie die Quelle der Google-Bibliothek nicht wollen (oder können) ändern, können Sie einfach erweitern der GoogleIdTokenVerifier. (Sie müssen eine andere Methode kopieren, die auf einige private Variablen zugreift - glücklicherweise sind alle über get-Mitglieder erreichbar). Das funktioniert bei mir:

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

}; 
Verwandte Themen