如何验证MS Azure AD生成的JWT id_token?

问题描述 投票:0回答:4

我有一个 angularjs SPA Web 应用程序,它使用 ADAL-JS (和 adal-angular)。 它被设置为在 MS Azure 中对我们的公司 AD 进行身份验证。登录流程似乎工作正常,并且 SPA 收到 id_token。

接下来,当用户单击按钮时,SPA 会向我在 AWS API Gateway 上托管的 REST API 发出请求。我正在

Authorization: Bearer <id_token>
标头上传递 id_token。 API 网关按预期接收标头,现在必须确定给定的令牌是否有效,以允许或拒绝访问。

我有一个示例令牌,它在 https://jwt.io/ 上正确解析,但到目前为止我还没有找到我应该用来验证签名的公钥或证书。我看过:

认为我应该使用https://login.microsoftonline.com/common/discovery/keys中密钥的x5c属性值来匹配JWT id_token中的kid和x5t属性(当前为

a3QN0BZS7s4nN-BdrjbF0Y_LdMM
) ,这会导致以“MIIDBTCCAe2gAwIBAgIQY...”开头的 x5c 值)。但是,https://jwt.io/页面报告“无效签名”(我还尝试用“-----BEGIN CERTIFICATE-----”和“-----END”包装密钥值证书-----”)。

另外,是否有一个(可能是Python)库可以像上面的情况一样方便地验证给定的id_token(这样我就不必自己去即时获取签名密钥?)...最好的我发现(ADAL for python)似乎没有提供此功能?

python azure jwt adal
4个回答
28
投票

迄今为止我能想到的最佳解决方案:

x5c

https://login.microsoftonline.com/common/discovery/keys
 获取证书
https://login.microsoftonline.com/common/discovery/v2.0/keys
属性数组中的第一个值),匹配 id_token 中的
kid
x5t

将证书包装在

-----BEGIN CERTIFICATE-----\n
\n-----END CERTIFICATE-----
中(换行符似乎很重要),并将结果用作公钥(与 id_token 一起使用,在 https://jwt.io/ 上)。

当然,您的实际用例可能是让某些程序验证传入的 JWT id_tokens,因此您的目标不是简单地通过 https://jwt.io/ 上的 Web UI 获取令牌进行验证.

例如,在Python中,我需要这样的东西:

#!/usr/bin/env python

import jwt
from cryptography.x509 import load_pem_x509_certificate
from cryptography.hazmat.backends import default_backend

PEMSTART = "-----BEGIN CERTIFICATE-----\n"
PEMEND = "\n-----END CERTIFICATE-----\n"

mspubkey = "The value from the x5c property"
IDTOKEN = "the id_token to be validated"
tenant_id = "your tenant id"

cert_str = PEMSTART + mspubkey + PEMEND
cert_obj = load_pem_x509_certificate(cert_str, default_backend())
public_key = cert_obj.public_key()

decoded = jwt.decode(IDTOKEN, public_key, algorithms=['RS256'], audience=tenant_id)
if decoded:
    print "Decoded!"
else:
    print "Could not decode token."

有关各种语言的 JWT 库的列表,请参阅JWT 站点。 我正在使用 pyjwt 及其 cryptography 依赖项(具有二进制依赖项,因此需要为目标操作系统构建和打包)。

然后,当然,您可以验证其他详细信息,例如此处推荐的声明


2
投票
对于 JVM 解决方案,使用

com.nimbusds:numbus-jose-jwt:4.29

 是解析和验证签名 RSA256 id_token 的最直接方法。以下 Scala 代码使用 JSON Web Key 解析 JWT 令牌:

val jwt = SignedJWT.parse(token) val n = new Base64URL("Your Modulus Component of RSA Key") val e = new Base64URL("AQAB") val rsaKey = new RSAKey.Builder(n, e).keyUse(KeyUse.SIGNATURE).algorithm(JWSAlgorithm.RS256).build() val verified = jwt.verify(new RSASSAVerifier(rsaKey))

您的应用程序仍需要从 Azure Active Directory B2C

discovery/v2.0/key

 动态获取 JSON Web 密钥集,以获取 AAD B2C 可能使用的密钥集。为了提高效率,这可能应该被缓存并且 TTL 不超过 24 小时。 


0
投票
另外,是否有一个(可能是Python)库可以像上面的情况一样方便地验证给定的id_token(这样我就不必自己去即时获取签名密钥?)...最好的我发现(ADAL for python)似乎没有提供这个功能?

就其价值而言,

MSAL Python(ADAL Python 的后继者)会在后台验证 id 令牌,并为您的应用程序提供 id 令牌中已解码的声明。这样您的应用程序(刚刚通过 MSAL Python 获取了该 id 令牌)就可以在本地使用它。

接下来,当用户单击按钮时,SPA 会向我在 AWS API Gateway 上托管的 REST API 发出请求。我正在

Authorization: Bearer <id_token>

 标头上传递 id_token。 API 网关按预期接收标头,现在必须确定给定的令牌是否有效,以允许或拒绝访问。

通常,id 令牌不会“在

Authorization: Bearer <id_token>

 标头上”用于发送给第 3 方以进行授权。 YMMV.


0
投票
使用此 NodeJS 代码来验证令牌

const config = await fetch("https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration").then((response) => { return response.json(); }); const jwks = await fetch(config.jwks_uri).then((response) => { return response.json(); }); const tokenHeader = JSON.parse(atob(token.split(".")[0])); const publicKey = jwks.keys.find((key) => key.kid === tokenHeader.kid); if(!publicKey) { throw new Error("Invalid token"); } const publicKeyPEM = `-----BEGIN CERTIFICATE-----\n${publicKey.x5c[0]}\n-----END CERTIFICATE-----`; const data = verify(token, publicKeyPEM);
    
© www.soinside.com 2019 - 2024. All rights reserved.