2014-01-18 137 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似乎能够做到这一点,但要确保你正在使用正确的方法。 –