2017-03-31 178 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小時以提高效率。