无法使用 oidc-client-js 和 Apereo CAS 验证访问令牌
Failed to validate Access Token with oidc-client-js and Apereo CAS
我正在尝试使用 Apereo CAS 5.1.1 in my react application using OIDC. Looking for libraries to achieve this, I landed on oidc-client-js 1.7.0 登录,但遇到以下错误:
ResponseValidator._validateAccessToken: Failed to validate at_hash dWr5-bD5lv8C1x3VcfFn1Q dWr5+bD5lv8C1x3VcfFn1Q==
循迹找到异常抛出的地方
var a = s.substr(0, s.length / 2), u = this._joseUtil.hexToBase64Url(a);
return u !== e.profile.at_hash ?
(i.Log.error("ResponseValidator._validateAccessToken: Failed to validate at_hash", u, e.profile.at_hash), Promise.reject(new Error("Failed to validate at_hash"))) :
(i.Log.debug("ResponseValidator._validateAccessToken: success"), Promise.resolve(e));
问题是 this._joseUtil.hexToBase64Url(a)
没有添加填充 (=
),在这种特殊情况下 +
符号。那是因为 URL 不接受这些字符。因此,比较总是(或几乎总是)是错误的。例如,在这个执行中:
dWr5-bD5lv8C1x3VcfFn1Q != dWr5+bD5lv8C1x3VcfFn1Q==
另一方面,我认为我的应用程序中缺少或配置错误的东西,否则每个使用此库的人都会遇到同样的问题。
所以,我的问题是:如何在这种情况下成功验证访问令牌?
谢谢。
我通过交互执行验证的两段代码发现问题。
原来我使用的 CAS 版本 (5.1.1) 在创建访问令牌哈希 at_hash
值时出错。
classorg.apereo.cas.oidc.token.OidcIdTokenGeneratorService
有如下方法:generateAccessTokenHash
。它实际生成哈希的最后几行代码是:
final byte[] digested = DigestUtils.rawDigest(hashAlg, tokenBytes);
final byte[] hashBytesLeftHalf = Arrays.copyOf(digested, digested.length / 2);
return EncodingUtils.encodeBase64(hashBytesLeftHalf);
问题是它编码为 base64,而 at_hash
应该根据 this:
在 base64url 中编码
Access Token hash value. Its value is the base64url encoding of the
left-most half of the hash of the octets of the ASCII representation
of the access_token value, where the hash algorithm used is the hash
algorithm used in the alg Header Parameter of the ID Token's JOSE
Header. For instance, if the alg is RS256, hash the access_token value
with SHA-256, then take the left-most 128 bits and base64url encode
them. The at_hash value is a case sensitive string.
此问题已在以下 CAS 版本中解决,至少我可以确认 5.2.x 通过将最后一行(除其他事项外)更改为:
解决了该问题
return EncodingUtils.encodeUrlSafeBase64(hashBytesLeftHalf);
我希望这对面临同样问题的任何人有所帮助。
我正在尝试使用 Apereo CAS 5.1.1 in my react application using OIDC. Looking for libraries to achieve this, I landed on oidc-client-js 1.7.0 登录,但遇到以下错误:
ResponseValidator._validateAccessToken: Failed to validate at_hash dWr5-bD5lv8C1x3VcfFn1Q dWr5+bD5lv8C1x3VcfFn1Q==
循迹找到异常抛出的地方
var a = s.substr(0, s.length / 2), u = this._joseUtil.hexToBase64Url(a);
return u !== e.profile.at_hash ?
(i.Log.error("ResponseValidator._validateAccessToken: Failed to validate at_hash", u, e.profile.at_hash), Promise.reject(new Error("Failed to validate at_hash"))) :
(i.Log.debug("ResponseValidator._validateAccessToken: success"), Promise.resolve(e));
问题是 this._joseUtil.hexToBase64Url(a)
没有添加填充 (=
),在这种特殊情况下 +
符号。那是因为 URL 不接受这些字符。因此,比较总是(或几乎总是)是错误的。例如,在这个执行中:
dWr5-bD5lv8C1x3VcfFn1Q != dWr5+bD5lv8C1x3VcfFn1Q==
另一方面,我认为我的应用程序中缺少或配置错误的东西,否则每个使用此库的人都会遇到同样的问题。
所以,我的问题是:如何在这种情况下成功验证访问令牌?
谢谢。
我通过交互执行验证的两段代码发现问题。
原来我使用的 CAS 版本 (5.1.1) 在创建访问令牌哈希 at_hash
值时出错。
classorg.apereo.cas.oidc.token.OidcIdTokenGeneratorService
有如下方法:generateAccessTokenHash
。它实际生成哈希的最后几行代码是:
final byte[] digested = DigestUtils.rawDigest(hashAlg, tokenBytes);
final byte[] hashBytesLeftHalf = Arrays.copyOf(digested, digested.length / 2);
return EncodingUtils.encodeBase64(hashBytesLeftHalf);
问题是它编码为 base64,而 at_hash
应该根据 this:
Access Token hash value. Its value is the base64url encoding of the left-most half of the hash of the octets of the ASCII representation of the access_token value, where the hash algorithm used is the hash algorithm used in the alg Header Parameter of the ID Token's JOSE Header. For instance, if the alg is RS256, hash the access_token value with SHA-256, then take the left-most 128 bits and base64url encode them. The at_hash value is a case sensitive string.
此问题已在以下 CAS 版本中解决,至少我可以确认 5.2.x 通过将最后一行(除其他事项外)更改为:
解决了该问题return EncodingUtils.encodeUrlSafeBase64(hashBytesLeftHalf);
我希望这对面临同样问题的任何人有所帮助。