我们使用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签名"。
问题是间歇性的。有时候它有效,有时它不起作用。
非常感谢任何建议。
答案 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解码器的正确实现应该是:
所以我的推论是,这是正确但复杂的来自Google的OIDC行为,默认情况下在Connect2D OAuth SDK中没有实现。
我应该在Connect2D OAuth SDK bitbucket网站上报告这个。
"解决方法"似乎是不直接使用DefaultJWTDecoder,而是将其子类化并添加缺少的逻辑,据我所知,这似乎是可行的,尽管密钥更新可能需要一点思考。
<强>更新强>
评论是:
对不起,有点混淆,现在有一个全新的框架来处理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,你有两个选择:
- 实施替代JWTDecoder。
- 扩展JWSVerifier实现以支持密钥ID查找。
醇>第一种方法可能是两者中更容易的。
因为我正在使用Apache Shiro,所以我必须与之集成,但大部分逻辑都是here,尽管我还没有对它进行过大量的测试。该功能分支的其余部分似乎使用ConnectID对Google OIDC进行了强大的身份验证。
基本原则是添加键旋转逻辑。
如果你可以更新到4.0的ConnectID,你可能会更快,但由于各种依赖层,我不得不坚持使用3.4.1。