Exemplo n.º 1
0
def sign_file(xml_file, root_id, assert_id, key_file, cert_file):
    """sign *xml_file* with *key_file* and include content of *cert_file*.
    *xml_file* can be a file, a filename string or an HTTP/FTP url.

    *key_file* contains the PEM encoded private key. It must be a filename string.

    *cert_file* contains a PEM encoded certificate (corresponding to *key_file*),
    included as `X509Data` in the dynamically created `Signature` template.
    """
    # template aware infrastructure
    from dm.xmlsec.binding.tmpl import parse, Element, SubElement, \
         fromstring, XML
    from dm.xmlsec.binding.tmpl import Signature

    doc = parse(xml_file)

    xmlsec.addIDs(doc.getroot(),['ID'])

    assertion = doc.findall('saml:Assertion', {"saml": "urn:oasis:names:tc:SAML:2.0:assertion"})[0]



    assertion_xml = sign_xml(tostring(assertion), assert_id, key_file, cert_file)

    assertion_doc = fromstring(assertion_xml)
    doc.getroot().remove(doc.findall("saml:Assertion", {"saml": "urn:oasis:names:tc:SAML:2.0:assertion"})[0])
    doc.getroot().insert(0, assertion_doc)

    

    return sign_xml(tostring(doc), root_id, key_file, cert_file)
Exemplo n.º 2
0
def sign_envelope(envelope, key_file, password=None):
    """Sign the given soap request with the given key"""
    doc = etree.fromstring(envelope)
    body = get_body(doc)

    queue = SignQueue()
    queue.push_and_mark(body)

    security_node = ensure_security_header(doc, queue)
    security_token_node = create_binary_security_token(key_file)
    signature_node = Signature(
        xmlsec.TransformExclC14N, xmlsec.TransformRsaSha1)

    security_node.append(security_token_node)
    security_node.append(signature_node)
    queue.insert_references(signature_node)

    key_info = create_key_info_node(security_token_node)
    signature_node.append(key_info)

    # Sign the generated xml
    xmlsec.addIDs(doc, ['Id'])
    dsigCtx = xmlsec.DSigCtx()
    dsigCtx.signKey = xmlsec.Key.load(
        key_file,
        xmlsec.KeyDataFormatPem,
        password,
    )
    dsigCtx.sign(signature_node)
    return etree.tostring(doc)
Exemplo n.º 3
0
def sign_envelope(envelope, key_file):
    """Sign the given soap request with the given key"""
    doc = etree.fromstring(envelope)
    body = get_body(doc)

    queue = SignQueue()
    queue.push_and_mark(body)

    security_node = ensure_security_header(doc, queue)
    security_token_node = create_binary_security_token(key_file)
    queue.push_and_mark(security_token_node)
    signature_node = Signature(xmlsec.TransformExclC14N,
                               xmlsec.TransformRsaSha1)

    security_node.append(security_token_node)
    security_node.append(signature_node)
    queue.insert_references(signature_node)

    key_info = create_key_info_node(security_token_node)
    signature_node.append(key_info)

    # Sign the generated xml
    xmlsec.addIDs(doc, ['Id'])
    dsigCtx = xmlsec.DSigCtx()
    dsigCtx.signKey = xmlsec.Key.load(key_file, xmlsec.KeyDataFormatPem, None)
    dsigCtx.sign(signature_node)
    return etree.tostring(doc)
Exemplo n.º 4
0
    def testSignedHttpPostBinding(self):
        """
        Test to use the binding: urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST
        To sign a samlp:AuthnRequest you need to have a private key set for the service provider.
        To verify the assertion is signed correct you can also use the xmlsec1 command line tool:
        xmlsec1 --verify --id-attr:ID AuthnRequest --trusted-pem tests/certs/example.com/example.crt authn_signed_assertion.xml
        """
        filename = join(dirname(__file__), '..', '..', '..', 'settings',
                        'example_settings_http_post_binding.json')
        stream = open(filename, 'r')
        settings = json.load(stream)
        stream.close()

        settings = OneLogin_Saml2_Settings(settings)

        authn_request = OneLogin_Saml2_Authn_Request(settings)
        authn_request_encoded = authn_request.get_request()
        decoded = b64decode(authn_request_encoded)
        inflated = decompress(decoded, -15)

        sample_output_directory = join(dirname(__file__), '..', '..', '..',
                                       'sample_output')
        if not os.path.exists(sample_output_directory):
            os.makedirs(sample_output_directory)

        with open(
                join(dirname(__file__), '..', '..', '..',
                     'sample_output/authn_signed_assertion.xml'), 'wb') as f:
            f.write(inflated)

        # Turn the inflated xml (which is just a string) into a in memory XML document
        doc = fromstring(inflated)

        # Verification of enveloped signature
        node = doc.find(".//{%s}Signature" % xmlsec.DSigNs)
        key_file = join(dirname(__file__), '..', '..', '..',
                        'certs/example.com', 'example.pubkey')

        dsigCtx = xmlsec.DSigCtx()

        signKey = xmlsec.Key.load(key_file, xmlsec.KeyDataFormatPem, None)
        signKey.name = 'example.pubkey'

        # Note: the assignment below effectively copies the key
        dsigCtx.signKey = signKey

        # Add ID attributes different from xml:id
        # See the Notes on https://pypi.python.org/pypi/dm.xmlsec.binding/1.3.2
        xmlsec.addIDs(doc, ["ID"])

        # This raises an exception if the document does not verify
        dsigCtx.verify(node)
Exemplo n.º 5
0
    def testSignedHttpPostBinding(self):
        """
        Test to use the binding: urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST
        To sign a samlp:AuthnRequest you need to have a private key set for the service provider.
        To verify the assertion is signed correct you can also use the xmlsec1 command line tool:
        xmlsec1 --verify --id-attr:ID AuthnRequest --trusted-pem tests/certs/example.com/example.crt authn_signed_assertion.xml
        """
        filename = join(dirname(__file__), '..', '..', '..', 'settings', 'example_settings_http_post_binding.json')
        stream = open(filename, 'r')
        settings = json.load(stream)
        stream.close()

        settings = OneLogin_Saml2_Settings(settings)

        authn_request = OneLogin_Saml2_Authn_Request(settings)
        authn_request_encoded = authn_request.get_request()
        decoded = b64decode(authn_request_encoded)
        inflated = decompress(decoded, -15)

        sample_output_directory = join(dirname(__file__), '..', '..', '..', 'sample_output')
        if not os.path.exists(sample_output_directory):
            os.makedirs(sample_output_directory)

        with open(join(dirname(__file__), '..', '..', '..', 'sample_output/authn_signed_assertion.xml'), 'wb') as f:
            f.write(inflated)

        # Turn the inflated xml (which is just a string) into a in memory XML document
        doc = fromstring(inflated)

        # Verification of enveloped signature
        node = doc.find(".//{%s}Signature" % xmlsec.DSigNs)
        key_file = join(dirname(__file__), '..', '..', '..', 'certs/example.com', 'example.pubkey')

        dsigCtx = xmlsec.DSigCtx()

        signKey = xmlsec.Key.load(key_file, xmlsec.KeyDataFormatPem, None)
        signKey.name = 'example.pubkey'

        # Note: the assignment below effectively copies the key
        dsigCtx.signKey = signKey

        # Add ID attributes different from xml:id
        # See the Notes on https://pypi.python.org/pypi/dm.xmlsec.binding/1.3.2
        xmlsec.addIDs(doc, ["ID"])

        # This raises an exception if the document does not verify
        dsigCtx.verify(node)
Exemplo n.º 6
0
def verify_envelope(reply, key_file):
    """Verify that the given soap request is signed with the certificate"""
    doc = etree.fromstring(reply)
    node = doc.find(".//{%s}Signature" % xmlsec.DSigNs)
    if node is None:
        raise CertificationError("No signature node found")
    dsigCtx = xmlsec.DSigCtx()

    xmlsec.addIDs(doc, ['Id'])
    signKey = xmlsec.Key.load(key_file, xmlsec.KeyDataFormatPem)
    signKey.name = os.path.basename(key_file)

    dsigCtx.signKey = signKey
    try:
        dsigCtx.verify(node)
    except xmlsec.VerificationError:
        return False
    return True
Exemplo n.º 7
0
 def finalize(self):
     r = super(_BindingDOMSupportSignatureExtension, self).finalize()
     sr = self._signature_requests
     if sr is None: return r
     # perform all signature requests in reverse order
     from lxml.etree import parse, tostring
     from dm.xmlsec.binding import addIDs
     from StringIO import StringIO
     doc = self.document().toxml()
     doc_tree = parse(StringIO(doc))
     addIDs(doc_tree.getroot(), ['ID'])
     while sr:
         r, i = sr.pop()
         r.sign(i, doc_tree)
     signed_doc = tostring(doc_tree)
     # interestingly: I must use "xml.dom.mindom" for parsing
     #   ``pyxb.utils.domutils.StringToDOM`` does not work
     from xml.dom.minidom import parseString
     self.__document = parseString(signed_doc)
 def finalize(self):
   r = super(_BindingDOMSupportSignatureExtension, self).finalize()
   sr = self._signature_requests
   if sr is None: return r
   # perform all signature requests in reverse order
   from lxml.etree import parse, tostring
   from dm.xmlsec.binding import addIDs
   from StringIO import StringIO
   doc = self.document().toxml()
   doc_tree = parse(StringIO(doc))
   addIDs(doc_tree.getroot(), ['ID'])
   while sr:
     r, i = sr.pop()
     r.sign(i, doc_tree)
   signed_doc = tostring(doc_tree)
   # interestingly: I must use "xml.dom.mindom" for parsing
   #   ``pyxb.utils.domutils.StringToDOM`` does not work
   from xml.dom.minidom import parseString
   self.__document = parseString(signed_doc)
Exemplo n.º 9
0
def verify_envelope(reply, key_file, password=None):
    """Verify that the given soap request is signed with the certificate"""
    doc = etree.fromstring(reply)
    node = doc.find(".//{%s}Signature" % xmlsec.DSigNs)
    if node is None:
        raise CertificationError("No signature node found")
    dsigCtx = xmlsec.DSigCtx()

    xmlsec.addIDs(doc, ['Id'])
    signKey = xmlsec.Key.load(
        key_file,
        xmlsec.KeyDataFormatPem,
        password,
    )
    signKey.name = os.path.basename(key_file)

    dsigCtx.signKey = signKey
    try:
        dsigCtx.verify(node)
    except xmlsec.VerificationError, e:
        return e.args[1] == 2
Exemplo n.º 10
0
def sign_file(xml_file, root_id, assertion_id,key_file, cert_file):
    #import pdb;pdb.set_trace()
    """sign *xml_file* with *key_file* and include content of *cert_file*.
    *xml_file* can be a file, a filename string or an HTTP/FTP url.

    *key_file* contains the PEM encoded private key. It must be a filename string.

    *cert_file* contains a PEM encoded certificate (corresponding to *key_file*),
    included as `X509Data` in the dynamically created `Signature` template.
    """
    # template aware infrastructure
    from dm.xmlsec.binding.tmpl import parse, Element, SubElement, fromstring, XML
    from dm.xmlsec.binding.tmpl import Signature

    doc = parse(xml_file)

    xmlsec.addIDs(doc.getroot(),['ID'])

    signature = Signature(xmlsec.TransformExclC14N,
                          xmlsec.TransformRsaSha1
                          )
    doc.getroot().insert(0, signature)

    ref = signature.addReference(xmlsec.TransformSha1,None,'#'+root_id)
    #ref = signature.addReference(xmlsec.TransformSha1)

    ref.addTransform(xmlsec.TransformEnveloped)
    ref.addTransform(xmlsec.TransformExclC14N)
    key_info = signature.ensureKeyInfo()
    key_info.addX509Data()
    # now what we already know
    dsigCtx = xmlsec.DSigCtx()
    # Note: we do not provide read access to `dsigCtx.signKey`.
    #  Therefore, unlike the `xmlsec` example, we must set the certificate
    signKey = xmlsec.Key.load(key_file, xmlsec.KeyDataFormatPem, None)
    signKey.loadCert(cert_file, xmlsec.KeyDataFormatPem)
    # Note: the assignment below effectively copies the key
    dsigCtx.signKey = signKey
    dsigCtx.sign(signature)
    return tostring(doc)
Exemplo n.º 11
0
def verify_signatures(doc, val, keyname=None, context=None):
    """verify all signatures contained in *doc* and update *val*.

  *doc* is a string containing an XML document.
  *val* is its ``pyxb`` binding.

  *keyname*, if given, identifies the key that has verified the enclosing
  context, e.g. the transport.

  *context* is a signature context. Default: ``default_verify_context``

  The function recursively descends *val* and tries to verify
  the signature for each encountered ``Signable`` instance.
  A ``VerifyError`` is raised when the signature verification fails.
  """
    from lxml.etree import parse
    from StringIO import StringIO
    from dm.xmlsec.binding import addIDs

    def verify(node, keyname):
        """verify *node* and (recursively) its decendents."""
        if isinstance(node, Signable):
            # this object is signable
            if getattr(node, node.S_SIGNATURE_ATTRIBUTE) is not None:
                # has its own signature -- verify it
                keyname = node.S_GET_KEYNAME()
                context.verify(dp, getattr(node, node.S_ID_ATTRIBUTE), keyname)
            node.set_signature_verification(keyname)
        # recurse
        ss = getattr(node, '_symbolSet', None)
        if ss is None: return
        # node._symbolSet returns a map eu --> list(child)
        for cl in ss().values():
            for c in cl:
                verify(c, keyname)

    dp = parse(StringIO(doc))
    if context is None: context = default_verify_context
    addIDs(dp.getroot(), ['ID'])
    verify(val, keyname)
Exemplo n.º 12
0
def sign_envelope(envelope, key_file, add_to_queue=None):
    """Sign the given soap request body with the given key. An optional add_to_queue callable can be
    passed to add additional elements to the signing queue. This function gets passed the document
    tree and should return a collection of Elements."""
    doc = etree.fromstring(envelope)
    body = get_body(doc)

    queue = SignQueue()
    queue.push_and_mark(body)

    if add_to_queue:
        if not hasattr(add_to_queue, '__call__'):
            raise ValueError('`zadd_to_queue` kwarg must be a callable')

        extra_sign_queue = add_to_queue(doc)
        if not hasattr(extra_sign_queue, '__iter__'):
            raise ValueError('`add_to_queue` must return an iterable value')

        for el in extra_sign_queue:
            queue.push_and_mark(el)

    security_node = ensure_security_header(doc, queue)
    security_token_node = create_binary_security_token(key_file)
    signature_node = Signature(xmlsec.TransformExclC14N,
                               xmlsec.TransformRsaSha1)

    security_node.append(security_token_node)
    security_node.append(signature_node)
    queue.insert_references(signature_node)

    key_info = create_key_info_node(security_token_node)
    signature_node.append(key_info)

    # Sign the generated xml
    xmlsec.addIDs(doc, ['Id'])
    dsigCtx = xmlsec.DSigCtx()
    dsigCtx.signKey = xmlsec.Key.load(key_file, xmlsec.KeyDataFormatPem, None)
    dsigCtx.sign(signature_node)
    return etree.tostring(doc)
def verify_signatures(doc, val, keyname=None, context=None):
  """verify all signatures contained in *doc* and update *val*.

  *doc* is a string containing an XML document.
  *val* is its ``pyxb`` binding.

  *keyname*, if given, identifies the key that has verified the enclosing
  context, e.g. the transport.

  *context* is a signature context. Default: ``default_verify_context``

  The function recursively descends *val* and tries to verify
  the signature for each encountered ``Signable`` instance.
  A ``VerifyError`` is raised when the signature verification fails.
  """
  from lxml.etree import parse
  from StringIO import StringIO
  from dm.xmlsec.binding import addIDs

  def verify(node, keyname):
    """verify *node* and (recursively) its decendents."""
    if isinstance(node, Signable):
      # this object is signable
      if getattr(node, node.S_SIGNATURE_ATTRIBUTE) is not None:
        # has its own signature -- verify it
        keyname = node.S_GET_KEYNAME()
        context.verify(dp, getattr(node, node.S_ID_ATTRIBUTE), keyname)
      node.set_signature_verification(keyname)
    # recurse
    ss = getattr(node, '_symbolSet', None)
    if ss is None: return
    # node._symbolSet returns a map eu --> list(child)
    for cl in ss().values():
      for c in cl: verify(c, keyname)

  dp = parse(StringIO(doc))
  if context is None: context = default_verify_context
  addIDs(dp.getroot(), ['ID'])
  verify(val, keyname)
Exemplo n.º 14
0
    def validate_sign(xml, cert=None, fingerprint=None, validatecert=False, debug=False):
        """
        Validates a signature (Message or Assertion).

        :param xml: The element we should validate
        :type: string | Document

        :param cert: The pubic cert
        :type: string

        :param fingerprint: The fingerprint of the public cert
        :type: string

        :param validatecert: If true, will verify the signature and if the cert is valid.
        :type: bool

        :param debug: Activate the xmlsec debug
        :type: bool
        """
        try:
            if xml is None or xml == '':
                raise Exception('Empty string supplied as input')
            elif isinstance(xml, etree._Element):
                elem = xml
            elif isinstance(xml, Document):
                xml = xml.toxml()
                elem = fromstring(str(xml))
            elif isinstance(xml, Element):
                xml.setAttributeNS(
                    unicode(OneLogin_Saml2_Constants.NS_SAMLP),
                    'xmlns:samlp',
                    unicode(OneLogin_Saml2_Constants.NS_SAMLP)
                )
                xml.setAttributeNS(
                    unicode(OneLogin_Saml2_Constants.NS_SAML),
                    'xmlns:saml',
                    unicode(OneLogin_Saml2_Constants.NS_SAML)
                )
                xml = xml.toxml()
                elem = fromstring(str(xml))
            elif isinstance(xml, basestring):
                elem = fromstring(str(xml))
            else:
                raise Exception('Error parsing xml string')

            xmlsec.initialize()

            if debug:
                xmlsec.set_error_callback(print_xmlsec_errors)

            xmlsec.addIDs(elem, ["ID"])

            signature_nodes = OneLogin_Saml2_Utils.query(elem, '//ds:Signature')

            if len(signature_nodes) > 0:
                signature_node = signature_nodes[0]

                if (cert is None or cert == '') and fingerprint:
                    x509_certificate_nodes = OneLogin_Saml2_Utils.query(signature_node, '//ds:Signature/ds:KeyInfo/ds:X509Data/ds:X509Certificate')
                    if len(x509_certificate_nodes) > 0:
                        x509_certificate_node = x509_certificate_nodes[0]
                        x509_cert_value = x509_certificate_node.text
                        x509_fingerprint_value = OneLogin_Saml2_Utils.calculate_x509_fingerprint(x509_cert_value)
                        if fingerprint == x509_fingerprint_value:
                            cert = OneLogin_Saml2_Utils.format_cert(x509_cert_value)

                if cert is None or cert == '':
                    return False

                dsig_ctx = xmlsec.DSigCtx()

                file_cert = OneLogin_Saml2_Utils.write_temp_file(cert)

                if validatecert:
                    mngr = xmlsec.KeysMngr()
                    mngr.loadCert(file_cert.name, xmlsec.KeyDataFormatCertPem, xmlsec.KeyDataTypeTrusted)
                    dsig_ctx = xmlsec.DSigCtx(mngr)
                else:
                    dsig_ctx = xmlsec.DSigCtx()
                    dsig_ctx.signKey = xmlsec.Key.load(file_cert.name, xmlsec.KeyDataFormatCertPem, None)

                file_cert.close()

                dsig_ctx.setEnabledKeyData([xmlsec.KeyDataX509])
                dsig_ctx.verify(signature_node)
                return True
            else:
                return False
        except Exception:
            return False
Exemplo n.º 15
0
    def add_sign(xml,
                 key,
                 cert,
                 debug=False,
                 sign_algorithm=OneLogin_Saml2_Constants.RSA_SHA1,
                 digest_algorithm=OneLogin_Saml2_Constants.SHA1):
        """
        Adds signature key and senders certificate to an element (Message or
        Assertion).

        :param xml: The element we should sign
        :type: string | Document

        :param key: The private key
        :type: string

        :param cert: The public
        :type: string

        :param debug: Activate the xmlsec debug
        :type: bool

        :param sign_algorithm: Signature algorithm method
        :type sign_algorithm: string

        :param digest_algorithm: Digest algorithm method
        :type digest_algorithm: string

        :returns: Signed XML
        :rtype: string
        """
        if xml is None or xml == '':
            raise Exception('Empty string supplied as input')
        elif isinstance(xml, etree._Element):
            elem = xml
        elif isinstance(xml, Document):
            xml = xml.toxml()
            elem = fromstring(xml.encode('utf-8'))
        elif isinstance(xml, Element):
            xml.setAttributeNS(unicode(OneLogin_Saml2_Constants.NS_SAMLP),
                               'xmlns:samlp',
                               unicode(OneLogin_Saml2_Constants.NS_SAMLP))
            xml.setAttributeNS(unicode(OneLogin_Saml2_Constants.NS_SAML),
                               'xmlns:saml',
                               unicode(OneLogin_Saml2_Constants.NS_SAML))
            xml = xml.toxml()
            elem = fromstring(xml.encode('utf-8'))
        elif isinstance(xml, basestring):
            elem = fromstring(xml.encode('utf-8'))
        else:
            raise Exception('Error parsing xml string')

        error_callback_method = None
        if debug:
            error_callback_method = print_xmlsec_errors
        xmlsec.set_error_callback(error_callback_method)

        sign_algorithm_transform_map = {
            OneLogin_Saml2_Constants.DSA_SHA1: xmlsec.TransformDsaSha1,
            OneLogin_Saml2_Constants.RSA_SHA1: xmlsec.TransformRsaSha1,
            OneLogin_Saml2_Constants.RSA_SHA256: xmlsec.TransformRsaSha256,
            OneLogin_Saml2_Constants.RSA_SHA384: xmlsec.TransformRsaSha384,
            OneLogin_Saml2_Constants.RSA_SHA512: xmlsec.TransformRsaSha512
        }
        sign_algorithm_transform = sign_algorithm_transform_map.get(
            sign_algorithm, xmlsec.TransformRsaSha1)

        signature = Signature(xmlsec.TransformExclC14N,
                              sign_algorithm_transform,
                              nsPrefix='ds')

        issuer = OneLogin_Saml2_Utils.query(elem, '//saml:Issuer')
        if len(issuer) > 0:
            issuer = issuer[0]
            issuer.addnext(signature)
            elem_to_sign = issuer.getparent()
        else:
            entity_descriptor = OneLogin_Saml2_Utils.query(
                elem, '//md:EntityDescriptor')
            if len(entity_descriptor) > 0:
                elem.insert(0, signature)
            else:
                elem[0].insert(0, signature)
            elem_to_sign = elem

        elem_id = elem_to_sign.get('ID', None)
        if elem_id is not None:
            if elem_id:
                elem_id = '#' + elem_id
        else:
            generated_id = generated_id = OneLogin_Saml2_Utils.generate_unique_id(
            )
            elem_id = '#' + generated_id
            elem_to_sign.attrib['ID'] = generated_id

        xmlsec.addIDs(elem_to_sign, ["ID"])

        digest_algorithm_transform_map = {
            OneLogin_Saml2_Constants.SHA1: xmlsec.TransformSha1,
            OneLogin_Saml2_Constants.SHA256: xmlsec.TransformSha256,
            OneLogin_Saml2_Constants.SHA384: xmlsec.TransformSha384,
            OneLogin_Saml2_Constants.SHA512: xmlsec.TransformSha512
        }
        digest_algorithm_transform = digest_algorithm_transform_map.get(
            digest_algorithm, xmlsec.TransformSha1)

        ref = signature.addReference(digest_algorithm_transform)
        if elem_id:
            ref.attrib['URI'] = elem_id

        ref.addTransform(xmlsec.TransformEnveloped)
        ref.addTransform(xmlsec.TransformExclC14N)

        key_info = signature.ensureKeyInfo()
        key_info.addX509Data()

        dsig_ctx = xmlsec.DSigCtx()
        sign_key = xmlsec.Key.loadMemory(key, xmlsec.KeyDataFormatPem, None)

        file_cert = OneLogin_Saml2_Utils.write_temp_file(cert)
        sign_key.loadCert(file_cert.name, xmlsec.KeyDataFormatCertPem)
        file_cert.close()

        dsig_ctx.signKey = sign_key
        dsig_ctx.sign(signature)

        return tostring(elem, encoding='unicode').encode('utf-8')
        newdoc = parseString(
            tostring(elem, encoding='unicode').encode('utf-8'))
        return newdoc.saveXML(newdoc.firstChild)
Exemplo n.º 16
0
    def validate_sign(xml,
                      cert=None,
                      fingerprint=None,
                      fingerprintalg='sha1',
                      validatecert=False,
                      debug=False,
                      xpath=None):
        """
        Validates a signature (Message or Assertion).

        :param xml: The element we should validate
        :type: string | Document

        :param cert: The pubic cert
        :type: string

        :param fingerprint: The fingerprint of the public cert
        :type: string

        :param fingerprintalg: The algorithm used to build the fingerprint
        :type: string

        :param validatecert: If true, will verify the signature and if the cert is valid.
        :type: bool

        :param debug: Activate the xmlsec debug
        :type: bool

        :param xpath: The xpath of the signed element
        :type: string
        """
        try:
            if xml is None or xml == '':
                raise Exception('Empty string supplied as input')
            elif isinstance(xml, etree._Element):
                elem = xml
            elif isinstance(xml, Document):
                xml = xml.toxml()
                elem = fromstring(xml.encode('utf-8'))
            elif isinstance(xml, Element):
                xml.setAttributeNS(unicode(OneLogin_Saml2_Constants.NS_SAMLP),
                                   'xmlns:samlp',
                                   unicode(OneLogin_Saml2_Constants.NS_SAMLP))
                xml.setAttributeNS(unicode(OneLogin_Saml2_Constants.NS_SAML),
                                   'xmlns:saml',
                                   unicode(OneLogin_Saml2_Constants.NS_SAML))
                xml = xml.toxml()
                elem = fromstring(xml.encode('utf-8'))
            elif isinstance(xml, basestring):
                elem = fromstring(xml.encode('utf-8'))
            else:
                raise Exception('Error parsing xml string')

            if debug:
                xmlsec.set_error_callback(print_xmlsec_errors)

            xmlsec.addIDs(elem, ["ID"])

            if xpath:
                signature_nodes = OneLogin_Saml2_Utils.query(elem, xpath)
            else:
                signature_nodes = OneLogin_Saml2_Utils.query(
                    elem, OneLogin_Saml2_Utils.RESPONSE_SIGNATURE_XPATH)

                if len(signature_nodes) == 0:
                    signature_nodes = OneLogin_Saml2_Utils.query(
                        elem, OneLogin_Saml2_Utils.ASSERTION_SIGNATURE_XPATH)

            if len(signature_nodes) == 1:
                signature_node = signature_nodes[0]

                return OneLogin_Saml2_Utils.validate_node_sign(
                    signature_node, elem, cert, fingerprint, fingerprintalg,
                    validatecert, debug)
            else:
                return False
        except Exception:
            return False
Exemplo n.º 17
0
    def validate_node_sign(signature_node,
                           elem,
                           cert=None,
                           fingerprint=None,
                           fingerprintalg='sha1',
                           validatecert=False,
                           debug=False):
        """
        Validates a signature node.

        :param signature_node: The signature node
        :type: Node

        :param xml: The element we should validate
        :type: Document

        :param cert: The public cert
        :type: string

        :param fingerprint: The fingerprint of the public cert
        :type: string

        :param fingerprintalg: The algorithm used to build the fingerprint
        :type: string

        :param validatecert: If true, will verify the signature and if the cert is valid.
        :type: bool

        :param debug: Activate the xmlsec debug
        :type: bool
        """
        try:
            if debug:
                xmlsec.set_error_callback(print_xmlsec_errors)

            xmlsec.addIDs(elem, ["ID"])

            if (cert is None or cert == '') and fingerprint:
                x509_certificate_nodes = OneLogin_Saml2_Utils.query(
                    signature_node,
                    '//ds:Signature/ds:KeyInfo/ds:X509Data/ds:X509Certificate')
                if len(x509_certificate_nodes) > 0:
                    x509_certificate_node = x509_certificate_nodes[0]
                    x509_cert_value = x509_certificate_node.text
                    x509_fingerprint_value = OneLogin_Saml2_Utils.calculate_x509_fingerprint(
                        x509_cert_value, fingerprintalg)
                    if fingerprint == x509_fingerprint_value:
                        cert = OneLogin_Saml2_Utils.format_cert(
                            x509_cert_value)

            # Check if Reference URI is empty
            # reference_elem = OneLogin_Saml2_Utils.query(signature_node, '//ds:Reference')
            # if len(reference_elem) > 0:
            #    if reference_elem[0].get('URI') == '':
            #        reference_elem[0].set('URI', '#%s' % signature_node.getparent().get('ID'))

            if cert is None or cert == '':
                return False

            file_cert = OneLogin_Saml2_Utils.write_temp_file(cert)

            if validatecert:
                mngr = xmlsec.KeysMngr()
                mngr.loadCert(file_cert.name, xmlsec.KeyDataFormatCertPem,
                              xmlsec.KeyDataTypeTrusted)
                dsig_ctx = xmlsec.DSigCtx(mngr)
            else:
                dsig_ctx = xmlsec.DSigCtx()
                dsig_ctx.signKey = xmlsec.Key.load(file_cert.name,
                                                   xmlsec.KeyDataFormatCertPem,
                                                   None)

            file_cert.close()

            dsig_ctx.setEnabledKeyData([xmlsec.KeyDataX509])
            dsig_ctx.verify(signature_node)
            return True
        except Exception:
            return False
Exemplo n.º 18
0
    def validate_sign(xml, cert=None, fingerprint=None, fingerprintalg='sha1', validatecert=False, debug=False, xpath=None, multicerts=None):
        """
        Validates a signature (Message or Assertion).

        :param xml: The element we should validate
        :type: string | Document

        :param cert: The pubic cert
        :type: string

        :param fingerprint: The fingerprint of the public cert
        :type: string

        :param fingerprintalg: The algorithm used to build the fingerprint
        :type: string

        :param validatecert: If true, will verify the signature and if the cert is valid.
        :type: bool

        :param debug: Activate the xmlsec debug
        :type: bool

        :param xpath: The xpath of the signed element
        :type: string

        :param multicerts: Multiple public certs
        :type: list

        :param raise_exceptions: Whether to return false on failure or raise an exception
        :type raise_exceptions: Boolean
        """
        if xml is None or xml == '':
            raise Exception('Empty string supplied as input')
        elif isinstance(xml, etree._Element):
            elem = xml
        elif isinstance(xml, Document):
            xml = xml.toxml()
            elem = fromstring(str(xml), forbid_dtd=True)
        elif isinstance(xml, Element):
            xml.setAttributeNS(
                unicode(OneLogin_Saml2_Constants.NS_SAMLP),
                'xmlns:samlp',
                unicode(OneLogin_Saml2_Constants.NS_SAMLP)
            )
            xml.setAttributeNS(
                unicode(OneLogin_Saml2_Constants.NS_SAML),
                'xmlns:saml',
                unicode(OneLogin_Saml2_Constants.NS_SAML)
            )
            xml = xml.toxml()
            elem = fromstring(str(xml), forbid_dtd=True)
        elif isinstance(xml, basestring):
            elem = fromstring(str(xml), forbid_dtd=True)
        else:
            raise Exception('Error parsing xml string')

        error_callback_method = None
        if debug:
            error_callback_method = print_xmlsec_errors
        xmlsec.set_error_callback(error_callback_method)

        xmlsec.addIDs(elem, ["ID"])

        if xpath:
            signature_nodes = OneLogin_Saml2_Utils.query(elem, xpath)
        else:
            signature_nodes = OneLogin_Saml2_Utils.query(elem, OneLogin_Saml2_Utils.RESPONSE_SIGNATURE_XPATH)

            if len(signature_nodes) == 0:
                signature_nodes = OneLogin_Saml2_Utils.query(elem, OneLogin_Saml2_Utils.ASSERTION_SIGNATURE_XPATH)

        if len(signature_nodes) == 1:
            signature_node = signature_nodes[0]

            if not multicerts:
                return OneLogin_Saml2_Utils.validate_node_sign(signature_node, elem, cert, fingerprint, fingerprintalg, validatecert, debug, raise_exceptions=True)
            else:
                # If multiple certs are provided, I may ignore cert and
                # fingerprint provided by the method and just check the
                # certs multicerts
                fingerprint = fingerprintalg = None
                for cert in multicerts:
                    if OneLogin_Saml2_Utils.validate_node_sign(signature_node, elem, cert, fingerprint, fingerprintalg, validatecert, False, raise_exceptions=False):
                        return True
                raise OneLogin_Saml2_ValidationError('Signature validation failed. SAML Response rejected.')
        else:
            raise OneLogin_Saml2_ValidationError('Expected exactly one signature node; got {}.'.format(len(signature_nodes)), OneLogin_Saml2_ValidationError.WRONG_NUMBER_OF_SIGNATURES)
Exemplo n.º 19
0
    def add_sign(xml, key, cert, debug=False, sign_algorithm=OneLogin_Saml2_Constants.RSA_SHA1, digest_algorithm=OneLogin_Saml2_Constants.SHA1):
        """
        Adds signature key and senders certificate to an element (Message or
        Assertion).

        :param xml: The element we should sign
        :type: string | Document

        :param key: The private key
        :type: string

        :param cert: The public
        :type: string

        :param debug: Activate the xmlsec debug
        :type: bool

        :param sign_algorithm: Signature algorithm method
        :type sign_algorithm: string

        :param digest_algorithm: Digest algorithm method
        :type digest_algorithm: string

        :returns: Signed XML
        :rtype: string
        """
        if xml is None or xml == '':
            raise Exception('Empty string supplied as input')
        elif isinstance(xml, etree._Element):
            elem = xml
        elif isinstance(xml, Document):
            xml = xml.toxml()
            elem = fromstring(xml.encode('utf-8'), forbid_dtd=True)
        elif isinstance(xml, Element):
            xml.setAttributeNS(
                unicode(OneLogin_Saml2_Constants.NS_SAMLP),
                'xmlns:samlp',
                unicode(OneLogin_Saml2_Constants.NS_SAMLP)
            )
            xml.setAttributeNS(
                unicode(OneLogin_Saml2_Constants.NS_SAML),
                'xmlns:saml',
                unicode(OneLogin_Saml2_Constants.NS_SAML)
            )
            xml = xml.toxml()
            elem = fromstring(xml.encode('utf-8'), forbid_dtd=True)
        elif isinstance(xml, basestring):
            elem = fromstring(xml.encode('utf-8'), forbid_dtd=True)
        else:
            raise Exception('Error parsing xml string')

        error_callback_method = None
        if debug:
            error_callback_method = print_xmlsec_errors
        xmlsec.set_error_callback(error_callback_method)

        sign_algorithm_transform_map = {
            OneLogin_Saml2_Constants.DSA_SHA1: xmlsec.TransformDsaSha1,
            OneLogin_Saml2_Constants.RSA_SHA1: xmlsec.TransformRsaSha1,
            OneLogin_Saml2_Constants.RSA_SHA256: xmlsec.TransformRsaSha256,
            OneLogin_Saml2_Constants.RSA_SHA384: xmlsec.TransformRsaSha384,
            OneLogin_Saml2_Constants.RSA_SHA512: xmlsec.TransformRsaSha512
        }
        sign_algorithm_transform = sign_algorithm_transform_map.get(sign_algorithm, xmlsec.TransformRsaSha1)

        signature = Signature(xmlsec.TransformExclC14N, sign_algorithm_transform, nsPrefix='ds')

        issuer = OneLogin_Saml2_Utils.query(elem, '//saml:Issuer')
        if len(issuer) > 0:
            issuer = issuer[0]
            issuer.addnext(signature)
            elem_to_sign = issuer.getparent()
        else:
            entity_descriptor = OneLogin_Saml2_Utils.query(elem, '//md:EntityDescriptor')
            if len(entity_descriptor) > 0:
                elem.insert(0, signature)
            else:
                elem[0].insert(0, signature)
            elem_to_sign = elem

        elem_id = elem_to_sign.get('ID', None)
        if elem_id is not None:
            if elem_id:
                elem_id = '#' + elem_id
        else:
            generated_id = generated_id = OneLogin_Saml2_Utils.generate_unique_id()
            elem_id = '#' + generated_id
            elem_to_sign.attrib['ID'] = generated_id

        xmlsec.addIDs(elem_to_sign, ["ID"])

        digest_algorithm_transform_map = {
            OneLogin_Saml2_Constants.SHA1: xmlsec.TransformSha1,
            OneLogin_Saml2_Constants.SHA256: xmlsec.TransformSha256,
            OneLogin_Saml2_Constants.SHA384: xmlsec.TransformSha384,
            OneLogin_Saml2_Constants.SHA512: xmlsec.TransformSha512
        }
        digest_algorithm_transform = digest_algorithm_transform_map.get(digest_algorithm, xmlsec.TransformSha1)

        ref = signature.addReference(digest_algorithm_transform)
        if elem_id:
            ref.attrib['URI'] = elem_id

        ref.addTransform(xmlsec.TransformEnveloped)
        ref.addTransform(xmlsec.TransformExclC14N)

        key_info = signature.ensureKeyInfo()
        key_info.addX509Data()

        dsig_ctx = xmlsec.DSigCtx()
        sign_key = xmlsec.Key.loadMemory(key, xmlsec.KeyDataFormatPem, None)

        file_cert = OneLogin_Saml2_Utils.write_temp_file(cert)
        sign_key.loadCert(file_cert.name, xmlsec.KeyDataFormatCertPem)
        file_cert.close()

        dsig_ctx.signKey = sign_key
        dsig_ctx.sign(signature)

        return tostring(elem, encoding='unicode').encode('utf-8')
Exemplo n.º 20
0
    def validate_sign(xml,
                      cert=None,
                      fingerprint=None,
                      fingerprintalg='sha1',
                      validatecert=False,
                      debug=False):
        """
        Validates a signature (Message or Assertion).

        :param xml: The element we should validate
        :type: string | Document

        :param cert: The pubic cert
        :type: string

        :param fingerprint: The fingerprint of the public cert
        :type: string

        :param fingerprintalg: The algorithm used to build the fingerprint
        :type: string

        :param validatecert: If true, will verify the signature and if the cert is valid.
        :type: bool

        :param debug: Activate the xmlsec debug
        :type: bool
        """
        try:
            if xml is None or xml == '':
                raise Exception('Empty string supplied as input')
            elif isinstance(xml, etree._Element):
                elem = xml
            elif isinstance(xml, Document):
                xml = xml.toxml()
                elem = fromstring(str(xml))
            elif isinstance(xml, Element):
                xml.setAttributeNS(unicode(OneLogin_Saml2_Constants.NS_SAMLP),
                                   'xmlns:samlp',
                                   unicode(OneLogin_Saml2_Constants.NS_SAMLP))
                xml.setAttributeNS(unicode(OneLogin_Saml2_Constants.NS_SAML),
                                   'xmlns:saml',
                                   unicode(OneLogin_Saml2_Constants.NS_SAML))
                xml = xml.toxml()
                elem = fromstring(str(xml))
            elif isinstance(xml, basestring):
                elem = fromstring(str(xml))
            else:
                raise Exception('Error parsing xml string')

            xmlsec.initialize()

            if debug:
                xmlsec.set_error_callback(print_xmlsec_errors)

            xmlsec.addIDs(elem, ["ID"])

            signature_nodes = OneLogin_Saml2_Utils.query(
                elem, '/samlp:Response/ds:Signature')

            if not len(signature_nodes) > 0:
                signature_nodes += OneLogin_Saml2_Utils.query(
                    elem,
                    '/samlp:Response/saml:EncryptedAssertion/saml:Assertion/ds:Signature'
                )
                signature_nodes += OneLogin_Saml2_Utils.query(
                    elem, '/samlp:Response/saml:Assertion/ds:Signature')

            if len(signature_nodes) == 1:
                signature_node = signature_nodes[0]

                return OneLogin_Saml2_Utils.validate_node_sign(
                    signature_node, elem, cert, fingerprint, fingerprintalg,
                    validatecert, debug)
            else:
                return False
        except Exception:
            return False
Exemplo n.º 21
0
    def validate_metadata_sign(xml, cert=None, fingerprint=None, fingerprintalg='sha1', validatecert=False, debug=False):
        """
        Validates a signature of a EntityDescriptor.

        :param xml: The element we should validate
        :type: string | Document

        :param cert: The pubic cert
        :type: string

        :param fingerprint: The fingerprint of the public cert
        :type: string

        :param fingerprintalg: The algorithm used to build the fingerprint
        :type: string

        :param validatecert: If true, will verify the signature and if the cert is valid.
        :type: bool

        :param debug: Activate the xmlsec debug
        :type: bool

        :param raise_exceptions: Whether to return false on failure or raise an exception
        :type raise_exceptions: Boolean
        """
        if xml is None or xml == '':
            raise Exception('Empty string supplied as input')
        elif isinstance(xml, etree._Element):
            elem = xml
        elif isinstance(xml, Document):
            xml = xml.toxml()
            elem = fromstring(str(xml), forbid_dtd=True)
        elif isinstance(xml, Element):
            xml.setAttributeNS(
                unicode(OneLogin_Saml2_Constants.NS_MD),
                'xmlns:md',
                unicode(OneLogin_Saml2_Constants.NS_MD)
            )
            xml = xml.toxml()
            elem = fromstring(str(xml), forbid_dtd=True)
        elif isinstance(xml, basestring):
            elem = fromstring(str(xml), forbid_dtd=True)
        else:
            raise Exception('Error parsing xml string')

        error_callback_method = None
        if debug:
            error_callback_method = print_xmlsec_errors
        xmlsec.set_error_callback(error_callback_method)

        xmlsec.addIDs(elem, ["ID"])

        signature_nodes = OneLogin_Saml2_Utils.query(elem, '/md:EntitiesDescriptor/ds:Signature')

        if len(signature_nodes) == 0:
            signature_nodes += OneLogin_Saml2_Utils.query(elem, '/md:EntityDescriptor/ds:Signature')

            if len(signature_nodes) == 0:
                signature_nodes += OneLogin_Saml2_Utils.query(elem, '/md:EntityDescriptor/md:SPSSODescriptor/ds:Signature')
                signature_nodes += OneLogin_Saml2_Utils.query(elem, '/md:EntityDescriptor/md:IDPSSODescriptor/ds:Signature')

        if len(signature_nodes) > 0:
            for signature_node in signature_nodes:
                OneLogin_Saml2_Utils.validate_node_sign(signature_node, elem, cert, fingerprint, fingerprintalg, validatecert, debug, raise_exceptions=True)
            return True
        else:
            raise Exception('Could not validate metadata signature: No signature nodes found.')
Exemplo n.º 22
0
    def add_sign_with_id(xml, uid, key, cert, debug=False, sign_algorithm=OneLogin_Saml2_Constants.RSA_SHA1,
                         digest_algorithm=OneLogin_Saml2_Constants.SHA1):

        # thanks to https://github.com/onelogin/python-saml/pull/78/files for the help. credit to @tachang

        xmlsec.initialize()
        xmlsec.set_error_callback(print_xmlsec_errors)
        #
        sign_algorithm_transform_map = {
             OneLogin_Saml2_Constants.DSA_SHA1: xmlsec.TransformDsaSha1,
             OneLogin_Saml2_Constants.RSA_SHA1: xmlsec.TransformRsaSha1,
             OneLogin_Saml2_Constants.RSA_SHA256: xmlsec.TransformRsaSha256,
             OneLogin_Saml2_Constants.RSA_SHA384: xmlsec.TransformRsaSha384,
             OneLogin_Saml2_Constants.RSA_SHA512: xmlsec.TransformRsaSha512
         }
        sign_algorithm_transform = sign_algorithm_transform_map.get(sign_algorithm, xmlsec.TransformRsaSha1)

        signature = Signature(xmlsec.TransformExclC14N, sign_algorithm_transform)

        if xml is None or xml == '':
            raise Exception('Empty string supplied as input')
        elif isinstance(xml, etree._Element):
            doc = xml
        elif isinstance(xml, Document):
            xml = xml.toxml()
            doc= fromstring(str(xml))
        elif isinstance(xml, Element):
            xml.setAttributeNS(
                unicode(OneLogin_Saml2_Constants.NS_SAMLP),
                'xmlns:samlp',
                unicode(OneLogin_Saml2_Constants.NS_SAMLP)
            )
            xml.setAttributeNS(
                unicode(OneLogin_Saml2_Constants.NS_SAML),
                'xmlns:saml',
                unicode(OneLogin_Saml2_Constants.NS_SAML)
            )
            xml = xml.toxml()
            doc = fromstring(str(xml))
        elif isinstance(xml, basestring):
            doc = fromstring(str(xml))
        else:
            raise Exception('Error parsing xml string')

        # # ID attributes different from xml:id must be made known by the application through a call
        # # to the addIds(node, ids) function defined by xmlsec.
        xmlsec.addIDs(doc, ['ID'])

        doc.insert(0, signature)

        digest_algorithm_transform_map = {
            OneLogin_Saml2_Constants.SHA1: xmlsec.TransformSha1,
            OneLogin_Saml2_Constants.SHA256: xmlsec.TransformSha256
        }

        digest_algorithm_transform = digest_algorithm_transform_map.get(digest_algorithm, xmlsec.TransformRsaSha1)

        ref = signature.addReference(digest_algorithm_transform, uri="#%s" % uid)
        ref.addTransform(xmlsec.TransformEnveloped)
        ref.addTransform(xmlsec.TransformExclC14N)

        key_info = signature.ensureKeyInfo()
        key_info.addKeyName()
        key_info.addX509Data()

        dsig_ctx = xmlsec.DSigCtx()

        sign_key = xmlsec.Key.loadMemory(key, xmlsec.KeyDataFormatPem, None)

        from tempfile import NamedTemporaryFile
        cert_file = NamedTemporaryFile(delete=True)
        cert_file.write(cert)
        cert_file.seek(0)

        sign_key.loadCert(cert_file.name, xmlsec.KeyDataFormatPem)

        dsig_ctx.signKey = sign_key

        # # Note: the assignment below effectively copies the key
        dsig_ctx.sign(signature)

        newdoc = parseString(etree.tostring(doc))

        return newdoc.saveXML(newdoc.firstChild)
Exemplo n.º 23
0
    def validate_sign(xml, cert=None, fingerprint=None, validatecert=False, debug=False):
        """
        Validates a signature (Message or Assertion).

        :param xml: The element we should validate
        :type: string | Document

        :param cert: The pubic cert
        :type: string

        :param fingerprint: The fingerprint of the public cert
        :type: string

        :param validatecert: If true, will verify the signature and if the cert is valid.
        :type: bool

        :param debug: Activate the xmlsec debug
        :type: bool
        """
        try:
            if xml is None or xml == '':
                raise Exception('Empty string supplied as input')
            elif isinstance(xml, etree._Element):
                elem = xml
            elif isinstance(xml, Document):
                xml = xml.toxml()
                elem = fromstring(str(xml))
            elif isinstance(xml, Element):
                xml.setAttributeNS(
                    unicode(OneLogin_Saml2_Constants.NS_SAMLP),
                    'xmlns:samlp',
                    unicode(OneLogin_Saml2_Constants.NS_SAMLP)
                )
                xml.setAttributeNS(
                    unicode(OneLogin_Saml2_Constants.NS_SAML),
                    'xmlns:saml',
                    unicode(OneLogin_Saml2_Constants.NS_SAML)
                )
                xml = xml.toxml()
                elem = fromstring(str(xml))
            elif isinstance(xml, basestring):
                elem = fromstring(str(xml))
            else:
                raise Exception('Error parsing xml string')

            xmlsec.initialize()

            if debug:
                xmlsec.set_error_callback(print_xmlsec_errors)

            xmlsec.addIDs(elem, ["ID"])

            signature_nodes = OneLogin_Saml2_Utils.query(elem, '//ds:Signature')

            if len(signature_nodes) > 0:
                signature_node = signature_nodes[0]

                if (cert is None or cert == '') and fingerprint:
                    x509_certificate_nodes = OneLogin_Saml2_Utils.query(signature_node, '//ds:Signature/ds:KeyInfo/ds:X509Data/ds:X509Certificate')
                    if len(x509_certificate_nodes) > 0:
                        x509_certificate_node = x509_certificate_nodes[0]
                        x509_cert_value = x509_certificate_node.text
                        x509_fingerprint_value = OneLogin_Saml2_Utils.calculate_x509_fingerprint(x509_cert_value)
                        if fingerprint == x509_fingerprint_value:
                            cert = OneLogin_Saml2_Utils.format_cert(x509_cert_value)

                if cert is None or cert == '':
                    return False

                dsig_ctx = xmlsec.DSigCtx()

                file_cert = OneLogin_Saml2_Utils.write_temp_file(cert)

                if validatecert:
                    mngr = xmlsec.KeysMngr()
                    mngr.loadCert(file_cert.name, xmlsec.KeyDataFormatCertPem, xmlsec.KeyDataTypeTrusted)
                    dsig_ctx = xmlsec.DSigCtx(mngr)
                else:
                    dsig_ctx = xmlsec.DSigCtx()
                    dsig_ctx.signKey = xmlsec.Key.load(file_cert.name, xmlsec.KeyDataFormatCertPem, None)

                file_cert.close()

                dsig_ctx.setEnabledKeyData([xmlsec.KeyDataX509])
                dsig_ctx.verify(signature_node)
                return True
            else:
                return False
        except Exception:
            return False
Exemplo n.º 24
0
    def validate_node_sign(
        signature_node, elem, cert=None, fingerprint=None, fingerprintalg="sha1", validatecert=False, debug=False
    ):
        """
        Validates a signature node.

        :param signature_node: The signature node
        :type: Node

        :param xml: The element we should validate
        :type: Document

        :param cert: The pubic cert
        :type: string

        :param fingerprint: The fingerprint of the public cert
        :type: string

        :param fingerprintalg: The algorithm used to build the fingerprint
        :type: string

        :param validatecert: If true, will verify the signature and if the cert is valid.
        :type: bool

        :param debug: Activate the xmlsec debug
        :type: bool
        """
        try:
            xmlsec.initialize()

            if debug:
                xmlsec.set_error_callback(print_xmlsec_errors)

            xmlsec.addIDs(elem, ["ID"])

            if (cert is None or cert == "") and fingerprint:
                x509_certificate_nodes = OneLogin_Saml2_Utils.query(
                    signature_node, "//ds:Signature/ds:KeyInfo/ds:X509Data/ds:X509Certificate"
                )
                if len(x509_certificate_nodes) > 0:
                    x509_certificate_node = x509_certificate_nodes[0]
                    x509_cert_value = x509_certificate_node.text
                    x509_fingerprint_value = OneLogin_Saml2_Utils.calculate_x509_fingerprint(
                        x509_cert_value, fingerprintalg
                    )
                    if fingerprint == x509_fingerprint_value:
                        cert = OneLogin_Saml2_Utils.format_cert(x509_cert_value)

            if cert is None or cert == "":
                return False

            # Check if Reference URI is empty
            reference_elem = OneLogin_Saml2_Utils.query(signature_node, "//ds:Reference")
            if len(reference_elem) > 0:
                if reference_elem[0].get("URI") == "":
                    reference_elem[0].set("URI", "#%s" % signature_node.getparent().get("ID"))

            dsig_ctx = xmlsec.DSigCtx()

            file_cert = OneLogin_Saml2_Utils.write_temp_file(cert)

            if validatecert:
                mngr = xmlsec.KeysMngr()
                mngr.loadCert(file_cert.name, xmlsec.KeyDataFormatCertPem, xmlsec.KeyDataTypeTrusted)
                dsig_ctx = xmlsec.DSigCtx(mngr)
            else:
                dsig_ctx = xmlsec.DSigCtx()
                dsig_ctx.signKey = xmlsec.Key.load(file_cert.name, xmlsec.KeyDataFormatCertPem, None)

            file_cert.close()

            dsig_ctx.setEnabledKeyData([xmlsec.KeyDataX509])
            dsig_ctx.verify(signature_node)
            return True
        except Exception:
            return False
Exemplo n.º 25
0
    def validate_sign(xml, cert=None, fingerprint=None, fingerprintalg="sha1", validatecert=False, debug=False):
        """
        Validates a signature (Message or Assertion).

        :param xml: The element we should validate
        :type: string | Document

        :param cert: The pubic cert
        :type: string

        :param fingerprint: The fingerprint of the public cert
        :type: string

        :param fingerprintalg: The algorithm used to build the fingerprint
        :type: string

        :param validatecert: If true, will verify the signature and if the cert is valid.
        :type: bool

        :param debug: Activate the xmlsec debug
        :type: bool
        """
        try:
            if xml is None or xml == "":
                raise Exception("Empty string supplied as input")
            elif isinstance(xml, etree._Element):
                elem = xml
            elif isinstance(xml, Document):
                xml = xml.toxml()
                elem = fromstring(str(xml))
            elif isinstance(xml, Element):
                xml.setAttributeNS(
                    unicode(OneLogin_Saml2_Constants.NS_SAMLP),
                    "xmlns:samlp",
                    unicode(OneLogin_Saml2_Constants.NS_SAMLP),
                )
                xml.setAttributeNS(
                    unicode(OneLogin_Saml2_Constants.NS_SAML), "xmlns:saml", unicode(OneLogin_Saml2_Constants.NS_SAML)
                )
                xml = xml.toxml()
                elem = fromstring(str(xml))
            elif isinstance(xml, basestring):
                elem = fromstring(str(xml))
            else:
                raise Exception("Error parsing xml string")

            xmlsec.initialize()

            if debug:
                xmlsec.set_error_callback(print_xmlsec_errors)

            xmlsec.addIDs(elem, ["ID"])

            signature_nodes = OneLogin_Saml2_Utils.query(elem, "/samlp:Response/ds:Signature")

            if not len(signature_nodes) > 0:
                signature_nodes += OneLogin_Saml2_Utils.query(
                    elem, "/samlp:Response/saml:EncryptedAssertion/saml:Assertion/ds:Signature"
                )
                signature_nodes += OneLogin_Saml2_Utils.query(elem, "/samlp:Response/saml:Assertion/ds:Signature")

            if len(signature_nodes) == 1:
                signature_node = signature_nodes[0]

                return OneLogin_Saml2_Utils.validate_node_sign(
                    signature_node, elem, cert, fingerprint, fingerprintalg, validatecert, debug
                )
            else:
                return False
        except Exception:
            return False
Exemplo n.º 26
0
    def validate_node_sign(signature_node,
                           elem,
                           cert=None,
                           fingerprint=None,
                           fingerprintalg='sha1',
                           validatecert=False,
                           debug=False):
        """
        Validates a signature node.

        :param signature_node: The signature node
        :type: Node

        :param xml: The element we should validate
        :type: Document

        :param cert: The public cert
        :type: string

        :param fingerprint: The fingerprint of the public cert
        :type: string

        :param fingerprintalg: The algorithm used to build the fingerprint
        :type: string

        :param validatecert: If true, will verify the signature and if the cert is valid.
        :type: bool

        :param debug: Activate the xmlsec debug
        :type: bool

        :param raise_exceptions: Whether to return false on failure or raise an exception
        :type raise_exceptions: Boolean
        """
        error_callback_method = None
        if debug:
            error_callback_method = print_xmlsec_errors
        xmlsec.set_error_callback(error_callback_method)

        xmlsec.addIDs(elem, ["ID"])

        if (cert is None or cert == '') and fingerprint:
            x509_certificate_nodes = OneLogin_Saml2_Utils.query(
                signature_node,
                '//ds:Signature/ds:KeyInfo/ds:X509Data/ds:X509Certificate')
            if len(x509_certificate_nodes) > 0:
                x509_certificate_node = x509_certificate_nodes[0]
                x509_cert_value = x509_certificate_node.text
                x509_fingerprint_value = OneLogin_Saml2_Utils.calculate_x509_fingerprint(
                    x509_cert_value, fingerprintalg)
                if fingerprint == x509_fingerprint_value:
                    cert = OneLogin_Saml2_Utils.format_cert(x509_cert_value)

        # Check if Reference URI is empty
        # reference_elem = OneLogin_Saml2_Utils.query(signature_node, '//ds:Reference')
        # if len(reference_elem) > 0:
        #    if reference_elem[0].get('URI') == '':
        #        reference_elem[0].set('URI', '#%s' % signature_node.getparent().get('ID'))

        if cert is None or cert == '':
            raise OneLogin_Saml2_Error(
                'Could not validate node signature: No certificate provided.',
                OneLogin_Saml2_Error.CERT_NOT_FOUND)

        file_cert = OneLogin_Saml2_Utils.write_temp_file(cert)

        if validatecert:
            mngr = xmlsec.KeysMngr()
            mngr.loadCert(file_cert.name, xmlsec.KeyDataFormatCertPem,
                          xmlsec.KeyDataTypeTrusted)
            dsig_ctx = xmlsec.DSigCtx(mngr)
        else:
            dsig_ctx = xmlsec.DSigCtx()
            dsig_ctx.signKey = xmlsec.Key.load(file_cert.name,
                                               xmlsec.KeyDataFormatCertPem,
                                               None)

        file_cert.close()

        dsig_ctx.setEnabledKeyData([xmlsec.KeyDataX509])

        try:
            dsig_ctx.verify(signature_node)
        except Exception as err:
            raise OneLogin_Saml2_ValidationError(
                'Signature validation failed. SAML Response rejected. %s',
                OneLogin_Saml2_ValidationError.INVALID_SIGNATURE,
                err.__str__())

        return True
Exemplo n.º 27
0
    def add_sign_with_id(xml,
                         uid,
                         key,
                         cert,
                         debug=False,
                         sign_algorithm=OneLogin_Saml2_Constants.RSA_SHA1,
                         digest_algorithm=OneLogin_Saml2_Constants.SHA1):

        # thanks to https://github.com/onelogin/python-saml/pull/78/files for the help. credit to @tachang

        xmlsec.initialize()
        xmlsec.set_error_callback(print_xmlsec_errors)
        #
        sign_algorithm_transform_map = {
            OneLogin_Saml2_Constants.DSA_SHA1: xmlsec.TransformDsaSha1,
            OneLogin_Saml2_Constants.RSA_SHA1: xmlsec.TransformRsaSha1,
            OneLogin_Saml2_Constants.RSA_SHA256: xmlsec.TransformRsaSha256,
            OneLogin_Saml2_Constants.RSA_SHA384: xmlsec.TransformRsaSha384,
            OneLogin_Saml2_Constants.RSA_SHA512: xmlsec.TransformRsaSha512
        }
        sign_algorithm_transform = sign_algorithm_transform_map.get(
            sign_algorithm, xmlsec.TransformRsaSha1)

        signature = Signature(xmlsec.TransformExclC14N,
                              sign_algorithm_transform)

        if xml is None or xml == '':
            raise Exception('Empty string supplied as input')
        elif isinstance(xml, etree._Element):
            doc = xml
        elif isinstance(xml, Document):
            xml = xml.toxml()
            doc = fromstring(str(xml))
        elif isinstance(xml, Element):
            xml.setAttributeNS(unicode(OneLogin_Saml2_Constants.NS_SAMLP),
                               'xmlns:samlp',
                               unicode(OneLogin_Saml2_Constants.NS_SAMLP))
            xml.setAttributeNS(unicode(OneLogin_Saml2_Constants.NS_SAML),
                               'xmlns:saml',
                               unicode(OneLogin_Saml2_Constants.NS_SAML))
            xml = xml.toxml()
            doc = fromstring(str(xml))
        elif isinstance(xml, basestring):
            doc = fromstring(str(xml))
        else:
            raise Exception('Error parsing xml string')

        # # ID attributes different from xml:id must be made known by the application through a call
        # # to the addIds(node, ids) function defined by xmlsec.
        xmlsec.addIDs(doc, ['ID'])

        doc.insert(0, signature)

        digest_algorithm_transform_map = {
            OneLogin_Saml2_Constants.SHA1: xmlsec.TransformSha1,
            OneLogin_Saml2_Constants.SHA256: xmlsec.TransformSha256
        }

        digest_algorithm_transform = digest_algorithm_transform_map.get(
            digest_algorithm, xmlsec.TransformRsaSha1)

        ref = signature.addReference(digest_algorithm_transform,
                                     uri="#%s" % uid)
        ref.addTransform(xmlsec.TransformEnveloped)
        ref.addTransform(xmlsec.TransformExclC14N)

        key_info = signature.ensureKeyInfo()
        key_info.addKeyName()
        key_info.addX509Data()

        dsig_ctx = xmlsec.DSigCtx()

        sign_key = xmlsec.Key.loadMemory(key, xmlsec.KeyDataFormatPem, None)

        from tempfile import NamedTemporaryFile
        cert_file = NamedTemporaryFile(delete=True)
        cert_file.write(cert)
        cert_file.seek(0)

        sign_key.loadCert(cert_file.name, xmlsec.KeyDataFormatPem)

        dsig_ctx.signKey = sign_key

        # # Note: the assignment below effectively copies the key
        dsig_ctx.sign(signature)

        newdoc = parseString(etree.tostring(doc))

        return newdoc.saveXML(newdoc.firstChild)
Exemplo n.º 28
0
    def validate_node_sign(signature_node, elem, cert=None, fingerprint=None, fingerprintalg='sha1', validatecert=False, debug=False):
        """
        Validates a signature node.

        :param signature_node: The signature node
        :type: Node

        :param xml: The element we should validate
        :type: Document

        :param cert: The public cert
        :type: string

        :param fingerprint: The fingerprint of the public cert
        :type: string

        :param fingerprintalg: The algorithm used to build the fingerprint
        :type: string

        :param validatecert: If true, will verify the signature and if the cert is valid.
        :type: bool

        :param debug: Activate the xmlsec debug
        :type: bool

        :param raise_exceptions: Whether to return false on failure or raise an exception
        :type raise_exceptions: Boolean
        """
        error_callback_method = None
        if debug:
            error_callback_method = print_xmlsec_errors
        xmlsec.set_error_callback(error_callback_method)

        xmlsec.addIDs(elem, ["ID"])

        if (cert is None or cert == '') and fingerprint:
            x509_certificate_nodes = OneLogin_Saml2_Utils.query(signature_node, '//ds:Signature/ds:KeyInfo/ds:X509Data/ds:X509Certificate')
            if len(x509_certificate_nodes) > 0:
                x509_certificate_node = x509_certificate_nodes[0]
                x509_cert_value = OneLogin_Saml2_Utils.element_text(x509_certificate_node)
                x509_cert_value_formatted = OneLogin_Saml2_Utils.format_cert(x509_cert_value)
                x509_fingerprint_value = OneLogin_Saml2_Utils.calculate_x509_fingerprint(x509_cert_value_formatted, fingerprintalg)

                if fingerprint == x509_fingerprint_value:
                    cert = x509_cert_value_formatted

        # Check if Reference URI is empty
        # reference_elem = OneLogin_Saml2_Utils.query(signature_node, '//ds:Reference')
        # if len(reference_elem) > 0:
        #    if reference_elem[0].get('URI') == '':
        #        reference_elem[0].set('URI', '#%s' % signature_node.getparent().get('ID'))

        if cert is None or cert == '':
            raise OneLogin_Saml2_Error(
                'Could not validate node signature: No certificate provided.',
                OneLogin_Saml2_Error.CERT_NOT_FOUND
            )

        file_cert = OneLogin_Saml2_Utils.write_temp_file(cert)

        if validatecert:
            mngr = xmlsec.KeysMngr()
            mngr.loadCert(file_cert.name, xmlsec.KeyDataFormatCertPem, xmlsec.KeyDataTypeTrusted)
            dsig_ctx = xmlsec.DSigCtx(mngr)
        else:
            dsig_ctx = xmlsec.DSigCtx()
            dsig_ctx.signKey = xmlsec.Key.load(file_cert.name, xmlsec.KeyDataFormatCertPem, None)

        file_cert.close()

        dsig_ctx.setEnabledKeyData([xmlsec.KeyDataX509])

        try:
            dsig_ctx.verify(signature_node)
        except Exception as err:
            raise OneLogin_Saml2_ValidationError(
                'Signature validation failed. SAML Response rejected. %s',
                OneLogin_Saml2_ValidationError.INVALID_SIGNATURE,
                err.__str__()
            )

        return True
Exemplo n.º 29
0
    def validate_metadata_sign(xml,
                               cert=None,
                               fingerprint=None,
                               fingerprintalg='sha1',
                               validatecert=False,
                               debug=False):
        """
        Validates a signature of a EntityDescriptor.

        :param xml: The element we should validate
        :type: string | Document

        :param cert: The pubic cert
        :type: string

        :param fingerprint: The fingerprint of the public cert
        :type: string

        :param fingerprintalg: The algorithm used to build the fingerprint
        :type: string

        :param validatecert: If true, will verify the signature and if the cert is valid.
        :type: bool

        :param debug: Activate the xmlsec debug
        :type: bool

        :param raise_exceptions: Whether to return false on failure or raise an exception
        :type raise_exceptions: Boolean
        """
        if xml is None or xml == '':
            raise Exception('Empty string supplied as input')
        elif isinstance(xml, etree._Element):
            elem = xml
        elif isinstance(xml, Document):
            xml = xml.toxml()
            elem = fromstring(str(xml))
        elif isinstance(xml, Element):
            xml.setAttributeNS(unicode(OneLogin_Saml2_Constants.NS_MD),
                               'xmlns:md',
                               unicode(OneLogin_Saml2_Constants.NS_MD))
            xml = xml.toxml()
            elem = fromstring(str(xml))
        elif isinstance(xml, basestring):
            elem = fromstring(str(xml))
        else:
            raise Exception('Error parsing xml string')

        error_callback_method = None
        if debug:
            error_callback_method = print_xmlsec_errors
        xmlsec.set_error_callback(error_callback_method)

        xmlsec.addIDs(elem, ["ID"])

        signature_nodes = OneLogin_Saml2_Utils.query(
            elem, '/md:EntitiesDescriptor/ds:Signature')

        if len(signature_nodes) == 0:
            signature_nodes += OneLogin_Saml2_Utils.query(
                elem, '/md:EntityDescriptor/ds:Signature')

            if len(signature_nodes) == 0:
                signature_nodes += OneLogin_Saml2_Utils.query(
                    elem,
                    '/md:EntityDescriptor/md:SPSSODescriptor/ds:Signature')
                signature_nodes += OneLogin_Saml2_Utils.query(
                    elem,
                    '/md:EntityDescriptor/md:IDPSSODescriptor/ds:Signature')

        if len(signature_nodes) > 0:
            for signature_node in signature_nodes:
                OneLogin_Saml2_Utils.validate_node_sign(signature_node,
                                                        elem,
                                                        cert,
                                                        fingerprint,
                                                        fingerprintalg,
                                                        validatecert,
                                                        debug,
                                                        raise_exceptions=True)
            return True
        else:
            raise Exception(
                'Could not validate metadata signature: No signature nodes found.'
            )
Exemplo n.º 30
0
    def validate_metadata_sign(
        xml, cert=None, fingerprint=None, fingerprintalg="sha1", validatecert=False, debug=False
    ):
        """
        Validates a signature of a EntityDescriptor.

        :param xml: The element we should validate
        :type: string | Document

        :param cert: The pubic cert
        :type: string

        :param fingerprint: The fingerprint of the public cert
        :type: string

        :param fingerprintalg: The algorithm used to build the fingerprint
        :type: string

        :param validatecert: If true, will verify the signature and if the cert is valid.
        :type: bool

        :param debug: Activate the xmlsec debug
        :type: bool
        """
        try:
            if xml is None or xml == "":
                raise Exception("Empty string supplied as input")
            elif isinstance(xml, etree._Element):
                elem = xml
            elif isinstance(xml, Document):
                xml = xml.toxml()
                elem = fromstring(str(xml))
            elif isinstance(xml, Element):
                xml.setAttributeNS(
                    unicode(OneLogin_Saml2_Constants.NS_MD), "xmlns:md", unicode(OneLogin_Saml2_Constants.NS_MD)
                )
                xml = xml.toxml()
                elem = fromstring(str(xml))
            elif isinstance(xml, basestring):
                elem = fromstring(str(xml))
            else:
                raise Exception("Error parsing xml string")

            xmlsec.initialize()

            if debug:
                xmlsec.set_error_callback(print_xmlsec_errors)

            xmlsec.addIDs(elem, ["ID"])

            signature_nodes = OneLogin_Saml2_Utils.query(elem, "/md:EntitiesDescriptor/ds:Signature")

            if len(signature_nodes) == 0:
                signature_nodes += OneLogin_Saml2_Utils.query(elem, "/md:EntityDescriptor/ds:Signature")

                if len(signature_nodes) == 0:
                    signature_nodes += OneLogin_Saml2_Utils.query(
                        elem, "/md:EntityDescriptor/md:SPSSODescriptor/ds:Signature"
                    )
                    signature_nodes += OneLogin_Saml2_Utils.query(
                        elem, "/md:EntityDescriptor/md:IDPSSODescriptor/ds:Signature"
                    )

            if len(signature_nodes) > 0:
                for signature_node in signature_nodes:
                    if not OneLogin_Saml2_Utils.validate_node_sign(
                        signature_node, elem, cert, fingerprint, fingerprintalg, validatecert, debug
                    ):
                        return False
                return True
            else:
                return False
        except Exception:
            return False
Exemplo n.º 31
0
    def validate_sign(xml,
                      cert=None,
                      fingerprint=None,
                      fingerprintalg='sha1',
                      validatecert=False,
                      debug=False,
                      xpath=None,
                      multicerts=None):
        """
        Validates a signature (Message or Assertion).

        :param xml: The element we should validate
        :type: string | Document

        :param cert: The pubic cert
        :type: string

        :param fingerprint: The fingerprint of the public cert
        :type: string

        :param fingerprintalg: The algorithm used to build the fingerprint
        :type: string

        :param validatecert: If true, will verify the signature and if the cert is valid.
        :type: bool

        :param debug: Activate the xmlsec debug
        :type: bool

        :param xpath: The xpath of the signed element
        :type: string

        :param multicerts: Multiple public certs
        :type: list

        :param raise_exceptions: Whether to return false on failure or raise an exception
        :type raise_exceptions: Boolean
        """
        if xml is None or xml == '':
            raise Exception('Empty string supplied as input')
        elif isinstance(xml, etree._Element):
            elem = xml
        elif isinstance(xml, Document):
            xml = xml.toxml()
            elem = fromstring(str(xml))
        elif isinstance(xml, Element):
            xml.setAttributeNS(unicode(OneLogin_Saml2_Constants.NS_SAMLP),
                               'xmlns:samlp',
                               unicode(OneLogin_Saml2_Constants.NS_SAMLP))
            xml.setAttributeNS(unicode(OneLogin_Saml2_Constants.NS_SAML),
                               'xmlns:saml',
                               unicode(OneLogin_Saml2_Constants.NS_SAML))
            xml = xml.toxml()
            elem = fromstring(str(xml))
        elif isinstance(xml, basestring):
            elem = fromstring(str(xml))
        else:
            raise Exception('Error parsing xml string')

        error_callback_method = None
        if debug:
            error_callback_method = print_xmlsec_errors
        xmlsec.set_error_callback(error_callback_method)

        xmlsec.addIDs(elem, ["ID"])

        if xpath:
            signature_nodes = OneLogin_Saml2_Utils.query(elem, xpath)
        else:
            signature_nodes = OneLogin_Saml2_Utils.query(
                elem, OneLogin_Saml2_Utils.RESPONSE_SIGNATURE_XPATH)

            if len(signature_nodes) == 0:
                signature_nodes = OneLogin_Saml2_Utils.query(
                    elem, OneLogin_Saml2_Utils.ASSERTION_SIGNATURE_XPATH)

        if len(signature_nodes) == 1:
            signature_node = signature_nodes[0]

            if not multicerts:
                return OneLogin_Saml2_Utils.validate_node_sign(
                    signature_node,
                    elem,
                    cert,
                    fingerprint,
                    fingerprintalg,
                    validatecert,
                    debug,
                    raise_exceptions=True)
            else:
                # If multiple certs are provided, I may ignore cert and
                # fingerprint provided by the method and just check the
                # certs multicerts
                fingerprint = fingerprintalg = None
                for cert in multicerts:
                    if OneLogin_Saml2_Utils.validate_node_sign(
                            signature_node,
                            elem,
                            cert,
                            fingerprint,
                            fingerprintalg,
                            validatecert,
                            False,
                            raise_exceptions=False):
                        return True
                raise OneLogin_Saml2_ValidationError(
                    'Signature validation failed. SAML Response rejected.')
        else:
            raise OneLogin_Saml2_ValidationError(
                'Expected exactly one signature node; got {}.'.format(
                    len(signature_nodes)),
                OneLogin_Saml2_ValidationError.WRONG_NUMBER_OF_SIGNATURES)
Exemplo n.º 32
0
    def validate_sign(
        xml, cert=None, fingerprint=None, fingerprintalg="sha1", validatecert=False, debug=False, xpath=None
    ):
        """
        Validates a signature (Message or Assertion).

        :param xml: The element we should validate
        :type: string | Document

        :param cert: The pubic cert
        :type: string

        :param fingerprint: The fingerprint of the public cert
        :type: string

        :param fingerprintalg: The algorithm used to build the fingerprint
        :type: string

        :param validatecert: If true, will verify the signature and if the cert is valid.
        :type: bool

        :param debug: Activate the xmlsec debug
        :type: bool

        :param xpath: The xpath of the signed element
        :type: string
        """
        try:
            if xml is None or xml == "":
                raise Exception("Empty string supplied as input")
            elif isinstance(xml, etree._Element):
                elem = xml
            elif isinstance(xml, Document):
                xml = xml.toxml()
                elem = fromstring(xml.encode("utf-8"))
            elif isinstance(xml, Element):
                xml.setAttributeNS(
                    unicode(OneLogin_Saml2_Constants.NS_SAMLP),
                    "xmlns:samlp",
                    unicode(OneLogin_Saml2_Constants.NS_SAMLP),
                )
                xml.setAttributeNS(
                    unicode(OneLogin_Saml2_Constants.NS_SAML), "xmlns:saml", unicode(OneLogin_Saml2_Constants.NS_SAML)
                )
                xml = xml.toxml()
                elem = fromstring(xml.encode("utf-8"))
            elif isinstance(xml, basestring):
                elem = fromstring(xml.encode("utf-8"))
            else:
                raise Exception("Error parsing xml string")

            if debug:
                xmlsec.set_error_callback(print_xmlsec_errors)

            xmlsec.addIDs(elem, ["ID"])

            if xpath:
                signature_nodes = OneLogin_Saml2_Utils.query(elem, xpath)
            else:
                signature_nodes = OneLogin_Saml2_Utils.query(elem, OneLogin_Saml2_Utils.RESPONSE_SIGNATURE_XPATH)

                if len(signature_nodes) == 0:
                    signature_nodes = OneLogin_Saml2_Utils.query(elem, OneLogin_Saml2_Utils.ASSERTION_SIGNATURE_XPATH)

            if len(signature_nodes) == 1:
                signature_node = signature_nodes[0]

                return OneLogin_Saml2_Utils.validate_node_sign(
                    signature_node, elem, cert, fingerprint, fingerprintalg, validatecert, debug
                )
            else:
                return False
        except Exception:
            return False