2017-03-31 179 views
3

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

接下来,当用户单击按钮时,SPA向我在AWS API网关上托管的REST API发出请求。我在Authorization: Bearer <id_token>标题上传递了id_token。 API网关按预期接收头,现在必须确定给定令牌是否良好,以允许或拒绝访问。

我有一个示例令牌,它在https://jwt.io/上正确解析,但我至今未能找到公钥或证书来验证签名。我已经看了看:

认为我应该使用的关键x5c属性的值在https://login.microsoftonline.com/common/discovery/keys匹配来自JWT id_token孩子和x5t性能(目前a3QN0BZS7s4nN-BdrjbF0Y_LdMM,导致开始与x5c值“MIIDBTCCAe2gAwIBAgIQY ......”) 。但是,https://jwt.io/页面报告“无效签名”(我也尝试用“----- BEGIN CERTIFICATE -----”和“----- END CERTIFICATE -----”包装密钥值)。

另外,是否有一个(可能是python)库,可以方便地验证给定的id_token,如上例(这样我就不必自己动手抓住签名密钥?).. 。我能找到的最好的(ADAL for python)似乎没有提供此功能?

+0

你见过[this](https://github.com/Azure/msrestazure-for-python/blob/master/msrestazure/azure_active_directory.py#L166) – 4c74356b41

+0

嘿@ 4c74356b41 - 感谢您的链接!可以很方便但是..我没有看到在那个库中签入令牌签名的位置? – FOR

回答

7

我可以放在一起迄今最好的解决办法:

抓斗从任https://login.microsoftonline.com/common/discovery/keyshttps://login.microsoftonline.com/common/discovery/v2.0/keys,匹配从id_token kidx5t证书(所述x5c属性数组中的第一值)。

裹在-----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库的各种语言列表,请参阅the JWT Site。 我使用pyjwt和它的cryptography依赖关系(它具有二进制依赖关系,因此需要为目标OS构建和打包)。

然后,当然,你可以验证额外的细节,如索赔recommended here

+1

我还没有编码过以前的python。根据我的理解,您不应该这样做,因为Azure AD使用的签名密钥可能会非常频繁地滚动,并且从今年开始,Microsoft甚至不会通知计划/应用程序可以无缝处理它。见下面https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-signing-key-rollover –

+0

@Gopi Kolla你是绝对正确的。事实上,除了这个初始代码之外(我的目的是弄清楚令牌验证是如何工作的),我已经抓住了MS公钥(每天安排时间,因为他们建议每24小时检查一次)并保存它们在那里我可以按需使用它们。 但是我感兴趣...如果一个人不应该做所有我一直在盯着的工作(并慢慢削减)......如何使用MS Azure AD来进行身份验证而不是.NET应用程序(在Azure上运行)? – FOR

+0

接受答案,因为它真的有效! – FOR

0

对于JVM解决方案,使用com.nimbusds:numbus-jose-jwt:4.29是解析和验证已签名的RSA256 id_token的最直接方式。下面的Scala代码解析JWT令牌与JSON网络密钥:

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网络密钥集动态获取一组可能使用AAD键B2C。这应该可以被缓存并且TTL不超过24小时以提高效率。