Openid 间歇错误Jws签名w/t Google Apps开放ID身份验证
我们正在使用Connect2D OAuth SDK(请参阅:)通过开放ID协议对Google应用程序用户进行身份验证。用户报告验证时出现间歇性问题。偶尔,我们的应用程序无法验证从谷歌应用程序收到的令牌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
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端点重新获取密钥。这是因为谷歌经常更改他们的密钥,所以如果你初始化一次,你就永远不会得到新的密钥
如果您可以更新到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);