2015-06-11 28 views
21

Tôi đang phải đối mặt với OAuth2 JWT dấu hiệu xác nhận ngoại lệ giờ cuối cùng (để không ai có thể truy cập vào ứng dụng của tôi):Google OAuth2 JWT xác minh dấu hiệu ngoại lệ

java.security.SignatureException: Chữ ký dài không đúng: có 256 nhưng đã mong 128. Tôi đang sử dụng google-http-client 1.20.0Java 1.7.0. Cấu hình tương tự đã hoạt động cho đến nay - bất kỳ ý tưởng nào?

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

Cùng một vấn đề ở đây cũng như sử dụng Java 1.8.0_45. – brunnsbe

+0

Tôi nhận được thông tin này trên công cụ ứng dụng của Google khi sử dụng mã thông báo truy cập từ tài khoản người quản lý tài khoản google. (Chỉ cần bắt đầu getitng họ một giờ trước) –

+1

@ user3686724 Đối tượng bạn đặt cho GoogleIdTokenVerifier là gì? Bạn có sử dụng id ứng dụng hoặc id mã thông báo không? (Chúng tôi đã gặp phải sự cố tương tự trong 60 phút qua) – orrsella

Trả lời

7

Cùng một vấn đề ở đây, tôi đã thêm mã nguồn của GoogleIdTokenVerifier để dự án của tôi và thay đổi phương pháp:

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

chỉ xử lý các ngoại lệ, Giấy chứng nhận thứ hai hoạt động tốt.

Edit: bạn có thể phân lớp như Erik-z gợi ý nếu bạn muốn làm cho nó sạch hơn:

Chỉnh sửa 2: Tôi không thể làm cho nó hoạt sử dụng mã dưới đây, tôi sẽ dính vào hack xấu xí trên.

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

Đừng nghĩ rằng đó là giải pháp cuối cùng nhưng công việc tạm thời chắc chắn hoạt động là thay đổi đối tượng của người xác minh thành mã thông báoID.

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

Cảm ơn, Ittai! Cách giải quyết này cũng đang làm việc mã của tôi. Good stopgap cho một vấn đề sản xuất nghiêm trọng cho công ty của tôi. – kennbrodhagen

+0

vui mừng khi nghe :-) Tôi nghĩ, nhưng không chắc chắn, điều đó có hiệu quả điều này chỉ tắt xác minh. Có thể là google đã làm cứng nó kiểm tra giấy chứng nhận và đó là những gì gây ra sự đột biến đột ngột. – Ittai

2

Nguyên nhân sâu xa là ở phía Google, Certs trong JSON là nhằm xấu:

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

Bạn có thể điều chỉnh thứ tự của chúng , như sau:

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

Sau đó, bạn có thể chỉ định URL tùy chỉnh của bạn (hoặc sử dụng tôi :) của JSON với phương pháp 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); 

... và nó hoạt động.

Tôi hy vọng, Google khắc phục vấn đề sớm ... :)

+0

Ồ, nó đã được sửa. :) –

0

này được sao chép từ câu trả lời của tôi here, nhưng phù hợp hơn đối với những người không sử dụng Google Cloud Endpoint (phù hợp với câu hỏi này). Vấn đề là do điều này:

  • RSA có chữ ký có chiều dài thay đổi, tùy thuộc vào kích thước khóa.
  • Google cập nhật cặp khóa sử dụng để ký và giờ đây một trong các cặp khóa tạo chữ ký khác nhau từ
  • java.security.Signature.verify(byte[] signature) ném ngoại lệ nếu chữ ký có độ dài sai được chuyển (thay vì trả về false thường được thực hiện khi một chữ ký không phù hợp với chính)

giải pháp đơn giản nhất là quấn gọi xác minh (try...catch), và trả về false nếu bạn nhận được một ngoại lệ

Nhìn vào mã ví dụ trên http://android-developers.blogspot.com/2013/01/verifying-back-end-calls-from-android.html có vẻ như bạn có thể ange dòng này:

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

Tôi tiếc là không có một thiết lập chính xác để kiểm tra điều này, cho tôi biết nếu làm việc này cho bạn.

0

Dường như với tôi, các thư viện có thể hoạt động kém. Để thay thế cho xác minh mã thông báo ngoại tuyến, bạn có thể sử dụng điểm cuối OAuth2 của Google để xác minh mã thông báo. Ví dụ cơ bản từ trình khám phá API can be seen here.

Bạn có thể kiểm tra mã thông báo với một lệnh curl curl https://www.googleapis.com/oauth2/v2/tokeninfo?id_token=[id_token], ví dụ:

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

Nếu bạn không muốn (hoặc không thể) thay đổi nguồn của thư viện google, bạn chỉ có thể mở rộng Trình xác minh GoogleIdToken. (bạn phải sao chép một phương thức khác truy cập một số biến riêng tư - may mắn là tất cả chúng đều có thể truy cập thông qua các thành viên nhận được). Điều này phù hợp với tôi:

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

}; 
Các vấn đề liên quan