2014-01-18 57 views
2

我需要通過使用SAML2從第三方在python中實現身份驗證。我查看了pysaml2,發現相當混亂,並且在this question發現Ennael後決定給M2Crypto一個機會。驗證python中的SAML簽名

我收到的SAML令牌can be found here。我已經從Assertion標記(用戶的SSN,IP和SAML令牌到期窗口)中提取了所需的全部信息,但我無法從Ennael獲得verify_signature函數(和revised codeEzra Nugroho)返回True。我也嘗試將verify_EVP.reset_context(md='sha1')更改爲verify_EVP.reset_context(md='sha256'),但是這也不起作用。

我想我的錯誤必須在signed_info部分。那部分我通過verify_signature什麼?我必須以任何方式預處理它嗎?我一直在研究Transform標籤,但不知道接下來的位置。

任何幫助將不勝感激。如果有人在混淆之前需要使用XML來測試並幫助我完成下一步操作。

編輯這是我的代碼(非常相似,我掛東西的主要功能是在底部):

def verify_signature(signed_info, cert, signature): 
    from M2Crypto import EVP, RSA, X509, m2 
    x509 = X509.load_cert_string(base64.decodestring(cert), X509.FORMAT_DER) 
    pubkey = x509.get_pubkey().get_rsa() 
    verify_EVP = EVP.PKey() 
    verify_EVP.assign_rsa(pubkey) 
    verify_EVP.reset_context(md='sha1') 
    verify_EVP.verify_init() 
    verify_EVP.verify_update(signed_info) 

    return verify_EVP.verify_final(signature.decode('base64')) 

def decode_response(resp): 
    return base64.b64decode(resp) 

def get_xmldoc(xmlstring): 
    return XML(xmlstring) 


def get_signature(doc): 
    return doc.find('{http://www.w3.org/2000/09/xmldsig#}Signature') 


def get_signed_info(signature): 
    signed_info = signature.find(
     '{http://www.w3.org/2000/09/xmldsig#}SignedInfo') 
    signed_info_str = tostring(signed_info) 
    # return parse(StringIO(signed_info_str)) 
    return signed_info_str 


def get_cert(signature): 
    ns = '{http://www.w3.org/2000/09/xmldsig#}' 
    keyinfo = signature.find('{}KeyInfo'.format(ns)) 
    keydata = keyinfo.find('{}X509Data'.format(ns)) 
    certelem = keydata.find('{}X509Certificate'.format(ns)) 
    return certelem.text 


def get_signature_value(signature): 
    return signature.find(
     '{http://www.w3.org/2000/09/xmldsig#}SignatureValue').text 

def parse_saml(saml): 
    dec_resp = decode_response(saml) 
    xml = get_xmldoc(dec_resp) 

    signature = get_signature(xml) 
    signed_info = get_signed_info(signature) 
    cert = get_cert(signature) 
    signature_value = get_signature_value(signature) 

    is_valid = verify_signature(signed_info, cert, signature_value) 

UPDATE:是否有可能我需要一些更多的信息第三方身份驗證提供程序?我需要私鑰嗎?

+0

您可能想顯示您的代碼,以便有人可以幫助您。 – hughdbrown

+0

完成 - 認爲鏈接就夠了。 –

+0

你不需要第三方提供商提供的任何東西,你也不需要私鑰來檢查簽名 –

回答

2

我面臨同樣的問題,不得不爲它開發一個模塊:https://github.com/kislyuk/signxml。我選擇僅依賴於PyCrypto和pyOpenSSL,因爲M2Crypto不太受歡迎,而且維護不好,從兼容性(例如PyPy)和安全角度來看都是一個危險。我也使用lxml進行規範化(c14n)。從signxml文檔:

from signxml import xmldsig 

cert = open("example.pem").read() 
key = open("example.key").read() 
root = ElementTree.fromstring(data) 
xmldsig(root).verify() 
+0

謝謝,我明天會看看它,讓你知道它是怎麼回事! –

+0

從signxml v。0.3.5開始,我的驗證工作正常! –

+0

沒有人可以用這個lib來幫助我嗎? http://stackoverflow.com/questions/33138385/invalid-xml-singnature-using-signxml-python-lib –

1

您需要在驗證簽名之前對簽名信息進行規範化。這就是轉換標籤所暗示的。基本上,由於相同的XML格式可能不同,因此需要以規範格式驗證XML簽名。

+0

我使用了[ElementC14N.py](https://bitbucket.org/effbot/et-2009-provolone/src/tip/elementtree/elementtree/ElementC14N.py),並嘗試對SignedInfo進行規範化處理,但沒有改變一個東西。你可以在'get_signed_info'中看到註釋('return parse(StringIO(signed_info_str))')。這是不正確的? –

+0

根據您在pastebin中的saml聲明,所使用的轉換應該是c14n獨佔的;見標籤:「」 ElementC14N.py似乎能夠做到這一點,但要確保你正在使用正確的方法。 –