Openid 间歇错误Jws签名w/t Google Apps开放ID身份验证

Openid 间歇错误Jws签名w/t Google Apps开放ID身份验证,openid,google-oauth,google-apps,Openid,Google Oauth,Google Apps,我们正在使用Connect2D OAuth SDK(请参阅:)通过开放ID协议对Google应用程序用户进行身份验证。用户报告验证时出现间歇性问题。偶尔,我们的应用程序无法验证从谷歌应用程序收到的令牌 OIDToken token = new OIDToken(getApplication(), tokenResponse.getIDToken(), id); ReadOnlyJWTClaimsSet claimsSet = null; try { claimsSet = token.v

我们正在使用Connect2D OAuth SDK(请参阅:)通过开放ID协议对Google应用程序用户进行身份验证。用户报告验证时出现间歇性问题。偶尔,我们的应用程序无法验证从谷歌应用程序收到的令牌

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());
}
报告的错误是:“错误的JWS签名”

问题是间歇性的。有时有效,有时无效


非常感谢您的建议。

我很肯定这是答案,但我可能错了。我们拭目以待

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

{
 "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),因此您首先获得哪个密钥取决于运气。它们似乎是按顺序添加的,所以计时模式(我猜)取决于谷歌选择一个键的顺序,这个键的顺序相当一致,再加上键的旋转

i、 其逻辑是(简化的):

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

JWT解码器的正确实现可能应:

  • 使用kid和算法选择要使用的键
  • 如果没有可用于给定kid的验证器,则可能应该从discovery API端点重新获取密钥。这是因为谷歌经常更改他们的密钥,所以如果你初始化一次,你就永远不会得到新的密钥
因此,我的推断是,这是来自Google的正确但复杂的OIDC行为,默认情况下,它不是在Connect2D OAuth SDK中实现的

我可能应该在Connect2D OAuth SDK bitbucket站点上报告这一点

“解决方法”似乎不是直接使用DefaultJWTDecoder,而是将其子类化并添加缺少的逻辑,据我所知,这似乎基本上是可行的,尽管关键更新可能需要一些思考

更新

是的,这是问题所在,经以下评论确认:

评论是:

很抱歉,有点混乱,是Nimbus JOSE+JWT库现在有了一个全新的处理JWTs()的框架,但是,它与OIDC SDK的集成仍然在我们的任务清单上。我们目前正忙于完成新版本的Connect2id服务器,在7月29日之前无法在SDK上花费时间

如果您使用的是OIDC SDK的v3.4.1,则有两个选项:

  • 实现一个替代的JWTDecoder
  • 扩展JWSVerifier实现以支持密钥ID查找
  • 第一种方法可能是两种方法中比较容易的一种

    因为我使用的是ApacheShiro,所以我必须与之集成,但是大部分逻辑都是这样的,尽管我还没有对它进行过大量测试。该特性分支的其余部分似乎确实使用ConnectID对Google OIDC进行了可靠的身份验证

    基本原理是添加键旋转逻辑


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

    是的,我也看到了。我对代币到期的时区差异表示怀疑,因为它似乎在时间段内起作用,然后是时间段失效,但我还没有时间确认每天重复的模式。是的,我希望谷歌的人能对此做出回应。我正在研究这一点,但我有第二个更好的假设。谷歌轮换他们的公钥,用于验证签名的令牌。我想知道是否有一些公钥缓存正在进行中。我可以将令牌传递给Google自己的调试API,这样就可以了,但如果我将令牌放入,它将无法验证。请参阅下面的详细信息。我很确定这是一个连接错误,谷歌推出了一个相当高的关键旋转系统。斯图尔特。谢谢你的分析。如果您设法获得有效的实施/解决方案,请告知我们。Stuart。RotatingJWTDecoder.java的第48行可能有一个空ptr异常,变量为kid1。。我的解决方案是调用apachecommons返回ObjectUtils.compare(kid1,kid2)@杰米:非常感谢。我已经把它作为一个问题记录了下来,我将在这个变化中工作。
        JWSAlgorithm alg = signedJWT.getHeader().getAlgorithm();        
        JWSVerifier verifier = jwsVerifiers.get(alg);
        boolean verified = signedJWT.verify(verifier);