Example #1
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)
Example #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)
Example #3
0
def get_response_xml(parameters, signed=False):
    """
    Returns XML for response, with signatures, if signed is True.
    """
    # Reset signatures.
    params = {}
    params.update(parameters)
    params["RESPONSE_SIGNATURE"] = ""
    _get_in_response_to(params)

    template = string.Template(RESPONSE)
    unsigned = template.substitute(params)

    logging.debug("Unsigned:")
    logging.debug(unsigned)
    if not signed:
        return unsigned

    # Sign it.
    # signature_xml = get_signature_xml(unsigned, params['RESPONSE_ID'])
    # params['RESPONSE_SIGNATURE'] = signature_xml
    # signed = template.substitute(params)
    #
    # logging.debug('Signed:')
    # logging.debug(signed)
    config = saml2idp_metadata.SAML2IDP_CONFIG
    private_key_file = config["private_key_file"]
    certificate_file = config["certificate_file"]

    doc = fromstring(unsigned)
    xmlsec.initialize()
    signature = Signature(xmlsec.TransformExclC14N, xmlsec.TransformRsaSha1)
    doc.insert(0, signature)
    ref = signature.addReference(xmlsec.TransformSha1)
    ref.addTransform(xmlsec.TransformEnveloped)
    key_info = signature.ensureKeyInfo()
    key_info.addKeyName()
    key_info.addX509Data()
    dsigCtx = xmlsec.DSigCtx()
    signKey = xmlsec.Key.load(private_key_file, xmlsec.KeyDataFormatPem, None)
    signKey.loadCert(certificate_file, xmlsec.KeyDataFormatPem)
    dsigCtx.signKey = signKey
    dsigCtx.sign(signature)
    return tostring(doc)
Example #4
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)
Example #5
0
def sign_xml(xml, root_id, key_file, cert_file):
    """Sign the given XML."""
    # template aware infrastructure
    from dm.xmlsec.binding.tmpl import parse, Element, SubElement, \
         fromstring, XML
    from dm.xmlsec.binding.tmpl import Signature
    doc = fromstring(xml)
    #doc = parse(xml)
    signature = Signature(xmlsec.TransformExclC14N, xmlsec.TransformRsaSha1)
    doc.insert(0, signature)
    ref = signature.addReference(xmlsec.TransformSha1)
    ref.addTransform(xmlsec.TransformEnveloped)
    ref.addTransform(xmlsec.TransformExclC14N)
    key_info = signature.ensureKeyInfo()
    key_info.addKeyName()
    key_info.addX509Data()
    dsigCtx = xmlsec.DSigCtx()
    signKey = xmlsec.Key.load(key_file, xmlsec.KeyDataFormatPem, None)
    signKey.loadCert(cert_file, xmlsec.KeyDataFormatPem)
    dsigCtx.signKey = signKey
    dsigCtx.sign(signature)
    return tostring(doc)
Example #6
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)
Example #7
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 the metadata with our private key.
        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)

        issuer = OneLogin_Saml2_Utils.query(elem, '//saml:Issuer')
        if len(issuer) > 0:
            issuer = issuer[0]
            issuer.addnext(signature)
        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)

        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)
        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)

        newdoc = parseString(
            tostring(elem, encoding='unicode').encode('utf-8'))

        signature_nodes = newdoc.getElementsByTagName("Signature")

        for signature in signature_nodes:
            signature.removeAttribute('xmlns')
            signature.setAttribute('xmlns:ds', OneLogin_Saml2_Constants.NS_DS)
            if not signature.tagName.startswith('ds:'):
                signature.tagName = 'ds:' + signature.tagName
            nodes = signature.getElementsByTagName("*")
            for node in nodes:
                if not node.tagName.startswith('ds:'):
                    node.tagName = 'ds:' + node.tagName

        return newdoc.saveXML(newdoc.firstChild)
Example #8
0
    def add_sign(xml, key, cert, debug=False):
        """
        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 debug: Activate the xmlsec debug
        :type: bool

        :param cert: The public
        :type: 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(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)

        # Sign the metadacta with our private key.
        signature = Signature(xmlsec.TransformExclC14N, xmlsec.TransformRsaSha1)

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

        ref = signature.addReference(xmlsec.TransformSha1)
        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)

        newdoc = parseString(etree.tostring(elem))

        signature_nodes = newdoc.getElementsByTagName("Signature")

        for signature in signature_nodes:
            signature.removeAttribute('xmlns')
            signature.setAttribute('xmlns:ds', OneLogin_Saml2_Constants.NS_DS)
            if not signature.tagName.startswith('ds:'):
                signature.tagName = 'ds:' + signature.tagName
            nodes = signature.getElementsByTagName("*")
            for node in nodes:
                if not node.tagName.startswith('ds:'):
                    node.tagName = 'ds:' + node.tagName

        return newdoc.saveXML(newdoc.firstChild)
Example #9
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')
Example #10
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)
Example #11
0
    def add_sign(xml, key, cert, debug=False):
        """
        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 debug: Activate the xmlsec debug
        :type: bool

        :param cert: The public
        :type: 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(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)

        # Sign the metadacta with our private key.
        signature = Signature(xmlsec.TransformExclC14N, xmlsec.TransformRsaSha1)

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

        ref = signature.addReference(xmlsec.TransformSha1)
        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)

        newdoc = parseString(etree.tostring(elem))

        signature_nodes = newdoc.getElementsByTagName("Signature")

        for signature in signature_nodes:
            signature.removeAttribute('xmlns')
            signature.setAttribute('xmlns:ds', OneLogin_Saml2_Constants.NS_DS)
            if not signature.tagName.startswith('ds:'):
                signature.tagName = 'ds:' + signature.tagName
            nodes = signature.getElementsByTagName("*")
            for node in nodes:
                if not node.tagName.startswith('ds:'):
                    node.tagName = 'ds:' + node.tagName

        return newdoc.saveXML(newdoc.firstChild)
Example #12
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')
Example #13
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)
Example #14
0
    def add_sign(xml, key, cert, debug=False, sign_algorithm=OneLogin_Saml2_Constants.RSA_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
        """
        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)

        # Sign the metadata with our private key.
        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)

        issuer = OneLogin_Saml2_Utils.query(elem, "//saml:Issuer")
        if len(issuer) > 0:
            issuer = issuer[0]
            issuer.addnext(signature)
        else:
            elem[0].insert(0, signature)

        ref = signature.addReference(xmlsec.TransformSha1)
        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)

        newdoc = parseString(etree.tostring(elem, encoding="unicode").encode("utf-8"))

        signature_nodes = newdoc.getElementsByTagName("Signature")

        for signature in signature_nodes:
            signature.removeAttribute("xmlns")
            signature.setAttribute("xmlns:ds", OneLogin_Saml2_Constants.NS_DS)
            if not signature.tagName.startswith("ds:"):
                signature.tagName = "ds:" + signature.tagName
            nodes = signature.getElementsByTagName("*")
            for node in nodes:
                if not node.tagName.startswith("ds:"):
                    node.tagName = "ds:" + node.tagName

        return newdoc.saveXML(newdoc.firstChild)