title: Validating SAML signature in python
body: <p>I need to implement authentication in python from a 3rd party by using SAML2. I have looked into <a href="https://pypi.python.org/pypi/pysaml2/1.1.0" rel="nofollow noreferrer">pysaml2</a> and found that to be quite confusing, and decided to give <a href="https://pypi.python.org/pypi/M2Crypto" rel="nofollow noreferrer">M2Crypto</a> a chance after I found <a href="https://stackoverflow.com/questions/9704919/saml-signature-verification-using-python-m2crypto">this question</a> by <a href="https://stackoverflow.com/users/518959/ennael">Ennael</a>.</p>
  
  <p>The SAML token I receive <a href="http://pastebin.com/vehrUdkB" rel="nofollow noreferrer">can be found here</a>. I have already extracted all the information I need from the <code>Assertion</code> tag (the user's SSN, IP and the SAML tokens expiration window) but I can't get the <code>verify_signature</code> function from Ennael (and the <a href="https://stackoverflow.com/questions/9704919/saml-signature-verification-using-python-m2crypto/17372895#17372895">revised code</a> from <a href="https://stackoverflow.com/users/2464942/ezra-nugroho">Ezra Nugroho</a>) to return True. I have also tried to change <code>verify_EVP.reset_context(md='sha1')</code> to <code>verify_EVP.reset_context(md='sha256')</code> but that didn't work either.</p>
  
  <p>I think my mistake must be in the signed_info part. What do I pass to <code>verify_signature</code> for that part? Do I have to preprocess it in any way? I have been looking into the Transform tag but don't know where too look next.</p>
  
  <p>Any help will be greatly appreciated. If someone needs the XML before the obfuscation to test and help me just PM me.</p>
  
  <p><strong>EDIT</strong> This is my code (very similar to the things i linked to. The main function is at the bottom):</p>
  
  <pre><code>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)
  </code></pre>
  
  <p><strong>UPDATE</strong>: Is it possible I need some more information from the 3rd party authentication provider? Do I need a private key for any of this?</p>