没有Google Apps Open ID身份验证的Intermittant Bad Jws签名

时间:2015-05-20 07:15:18

标签: openid google-oauth google-apps

我们使用Connect2D OAuth SDK(请参阅:http://connect2id.com/products/nimbus-oauth-openid-connect-sdk)通过Open ID协议对Google Apps用户进行身份验证。用户报告间歇性问题进行身份验证。有时,我们的应用无法验证从Google Apps收到的令牌。

OIDToken token = new OIDToken(getApplication(), tokenResponse.getIDToken(), id);
ReadOnlyJWTClaimsSet claimsSet = null;
try {
    claimsSet = token.verify();
} catch (Exception e) {
   throw new SecurityProviderException(994,"failed to verify token:"+e.getMessage());
}

报告的错误是:" Bad JWS签名"。

问题是间歇性的。有时候它有效,有时它不起作用。

非常感谢任何建议。

1 个答案:

答案 0 :(得分:2)

我相当肯定这是答案,但我可能错了。我们会看到。

Google面临的主要挑战是它似乎从其证书端点提供了两个备用密钥。它们具有相同的算法,但具有不同的密钥标识符。看起来有点像这样:

{
 "keys": [
  {
   "kty": "RSA",
   "alg": "RS256",
   "use": "sig",
   "kid": "5543f23f58e980646d8088d9393fcc3c1ac69ec5",
   "n": "xxx...",
   "e": "AQAB"
  },
  {
   "kty": "RSA",
   "alg": "RS256",
   "use": "sig",
   "kid": "da6625b36bc09d300353b28a741ce17525a4c33b",
   "n": "yyy...",
   "e": "AQAB"
  }
 ]
}

不幸的是,Connect2D JWT解码器的默认实现仅通过算法选择一个密钥(即,仅仅是RS256),因此您可以先得到哪一个。它们似乎是按顺序添加的,所以时间模式是(我猜测)下降到谷歌选择密钥相当一致的顺序,结合密钥轮换。

即,它的逻辑是(简化的):

    JWSAlgorithm alg = signedJWT.getHeader().getAlgorithm();        
    JWSVerifier verifier = jwsVerifiers.get(alg);
    boolean verified = signedJWT.verify(verifier);

这意味着密钥id(kid)被忽略,即使它存在于JWT头中。实际上,所选的验证者可能是错误的50%,因此显然不会验证。所有查找都是顺序的,因此可能是稳定的,导致观察到的一致成功或失败时期的行为。

JWT解码器的正确实现应该是:

  • 使用kid和算法选择要使用的密钥
  • 如果给定的孩子没有可用的验证者,则应该从发现API端点重新获取密钥。这是因为Google无论如何经常更换密钥,因此如果您初始化一次,您将永远不会获得新密钥。

所以我的推论是,这是正确但复杂的来自Google的OIDC行为,默认情况下在Connect2D OAuth SDK中没有实现。

我应该在Connect2D OAuth SDK bitbucket网站上报告这个。

"解决方法"似乎是不直接使用DefaultJWTDecoder,而是将其子类化并添加缺少的逻辑,据我所知,这似乎是可行的,尽管密钥更新可能需要一点思考。

<强>更新

是问题,由https://bitbucket.org/connect2id/oauth-2.0-sdk-with-openid-connect-extensions/issues/138/google-openid-connect-cant-locate-which的评论确认。

评论是:

  

对不起,有点混淆,现在有一个全新的框架来处理JWT(http://connect2id.com/blog/nimbus-jose-jwt-4.0-rc1),它是Nimbus JOSE + JWT lib,但是,它与OIDC SDK的集成仍然是在我们的待办事项清单上。我们目前正在忙着完成Connect2id服务器的新版本,并且在7月29日之前无法将时间花在SDK上。

     

如果你正在使用OIDC SDK的v3.4.1,你有两个选择:

     
      
  1. 实施替代JWTDecoder。
  2.   
  3. 扩展JWSVerifier实现以支持密钥ID查找。
  4.         

    第一种方法可能是两者中更容易的。

因为我正在使用Apache Shiro,所以我必须与之集成,但大部分逻辑都是here,尽管我还没有对它进行过大量的测试。该功能分支的其余部分似乎使用ConnectID对Google OIDC进行了强大的身份验证。

基本原则是添加键旋转逻辑。

如果你可以更新到4.0的ConnectID,你可能会更快,但由于各种依赖层,我不得不坚持使用3.4.1。