Exemple #1
0
    def decrypt_element(encrypted_data, key, debug=False):
        """
        Decrypts an encrypted element.

        :param encrypted_data: The encrypted data.
        :type: lxml.etree.Element | DOMElement | basestring

        :param key: The key.
        :type: string

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

        :returns: The decrypted element.
        :rtype: lxml.etree.Element
        """
        if isinstance(encrypted_data, Element):
            encrypted_data = fromstring(str(encrypted_data.toxml()))
        elif isinstance(encrypted_data, basestring):
            encrypted_data = fromstring(str(encrypted_data))

        xmlsec.initialize()

        if debug:
            xmlsec.set_error_callback(print_xmlsec_errors)

        mngr = xmlsec.KeysMngr()

        key = xmlsec.Key.loadMemory(key, xmlsec.KeyDataFormatPem, None)
        mngr.addKey(key)
        enc_ctx = xmlsec.EncCtx(mngr)

        return enc_ctx.decrypt(encrypted_data)
Exemple #2
0
    def decrypt_element(encrypted_data, key, debug=False):
        """
        Decrypts an encrypted element.

        :param encrypted_data: The encrypted data.
        :type: lxml.etree.Element | DOMElement | basestring

        :param key: The key.
        :type: string

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

        :returns: The decrypted element.
        :rtype: lxml.etree.Element
        """
        if isinstance(encrypted_data, Element):
            encrypted_data = fromstring(str(encrypted_data.toxml()))
        elif isinstance(encrypted_data, basestring):
            encrypted_data = fromstring(str(encrypted_data))

        xmlsec.initialize()

        if debug:
            xmlsec.set_error_callback(print_xmlsec_errors)

        mngr = xmlsec.KeysMngr()

        key = xmlsec.Key.loadMemory(key, xmlsec.KeyDataFormatPem, None)
        mngr.addKey(key)
        enc_ctx = xmlsec.EncCtx(mngr)

        return enc_ctx.decrypt(encrypted_data)
Exemple #3
0
    def __build_signature(self,
                          saml_data,
                          relay_state,
                          saml_type,
                          sign_algorithm=OneLogin_Saml2_Constants.RSA_SHA1):
        """
        Builds the Signature
        :param saml_data: The SAML Data
        :type saml_data: string

        :param relay_state: The target URL the user should be redirected to
        :type relay_state: string

        :param saml_type: The target URL the user should be redirected to
        :type saml_type: string  SAMLRequest | SAMLResponse

        :param sign_algorithm: Signature algorithm method
        :type sign_algorithm: string
        """
        assert saml_type in ['SAMLRequest', 'SAMLResponse']

        # Load the key into the xmlsec context
        key = self.__settings.get_sp_key()

        if not key:
            raise OneLogin_Saml2_Error(
                "Trying to sign the %s but can't load the SP private key" %
                saml_type, OneLogin_Saml2_Error.SP_CERTS_NOT_FOUND)

        xmlsec.initialize()

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

        saml_data_str = '%s=%s' % (saml_type, quote_plus(saml_data))
        relay_state_str = 'RelayState=%s' % quote_plus(relay_state)
        alg_str = 'SigAlg=%s' % quote_plus(sign_algorithm)

        sign_data = [saml_data_str, relay_state_str, alg_str]
        msg = '&'.join(sign_data)

        # 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 = dsig_ctx.signBinary(str(msg), sign_algorithm_transform)
        return b64encode(signature)
Exemple #4
0
    def validate_binary_sign(signed_query,
                             signature,
                             cert=None,
                             algorithm=OneLogin_Saml2_Constants.RSA_SHA1,
                             debug=False):
        """
        Validates signed bynary data (Used to validate GET Signature).

        :param signed_query: The element we should validate
        :type: string


        :param signature: The signature that will be validate
        :type: string

        :param cert: The pubic cert
        :type: string

        :param algorithm: Signature algorithm
        :type: string

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

            if debug:
                xmlsec.set_error_callback(print_xmlsec_errors)

            dsig_ctx = xmlsec.DSigCtx()

            file_cert = OneLogin_Saml2_Utils.write_temp_file(cert)
            dsig_ctx.signKey = xmlsec.Key.load(file_cert.name,
                                               xmlsec.KeyDataFormatCertPem,
                                               None)
            file_cert.close()

            # 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(
                algorithm, xmlsec.TransformRsaSha1)

            dsig_ctx.verifyBinary(signed_query, sign_algorithm_transform,
                                  signature)
            return True
        except Exception:
            return False
Exemple #5
0
    def __build_signature(self, saml_data, relay_state, saml_type, sign_algorithm=OneLogin_Saml2_Constants.RSA_SHA1):
        """
        Builds the Signature
        :param saml_data: The SAML Data
        :type saml_data: string

        :param relay_state: The target URL the user should be redirected to
        :type relay_state: string

        :param saml_type: The target URL the user should be redirected to
        :type saml_type: string  SAMLRequest | SAMLResponse

        :param sign_algorithm: Signature algorithm method
        :type sign_algorithm: string
        """
        assert saml_type in ['SAMLRequest', 'SAMLResponse']

        # Load the key into the xmlsec context
        key = self.__settings.get_sp_key()

        if not key:
            raise OneLogin_Saml2_Error(
                "Trying to sign the %s but can't load the SP private key" % saml_type,
                OneLogin_Saml2_Error.SP_CERTS_NOT_FOUND
            )

        xmlsec.initialize()

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

        saml_data_str = '%s=%s' % (saml_type, quote_plus(saml_data))
        relay_state_str = 'RelayState=%s' % quote_plus(relay_state)
        alg_str = 'SigAlg=%s' % quote_plus(sign_algorithm)

        sign_data = [saml_data_str, relay_state_str, alg_str]
        msg = '&'.join(sign_data)

        # 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 = dsig_ctx.signBinary(str(msg), sign_algorithm_transform)
        return b64encode(signature)
Exemple #6
0
    def validate_binary_sign(
        signed_query, signature, cert=None, algorithm=OneLogin_Saml2_Constants.RSA_SHA1, debug=False
    ):
        """
        Validates signed bynary data (Used to validate GET Signature).

        :param signed_query: The element we should validate
        :type: string


        :param signature: The signature that will be validate
        :type: string

        :param cert: The pubic cert
        :type: string

        :param algorithm: Signature algorithm
        :type: string

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

            if debug:
                xmlsec.set_error_callback(print_xmlsec_errors)

            dsig_ctx = xmlsec.DSigCtx()

            file_cert = OneLogin_Saml2_Utils.write_temp_file(cert)
            dsig_ctx.signKey = xmlsec.Key.load(file_cert.name, xmlsec.KeyDataFormatCertPem, None)
            file_cert.close()

            # 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(algorithm, xmlsec.TransformRsaSha1)

            dsig_ctx.verifyBinary(signed_query, sign_algorithm_transform, signature)
            return True
        except Exception:
            return False
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)
Exemple #8
0
    def validate_binary_sign(signed_query,
                             signature,
                             cert=None,
                             algorithm=xmlsec.TransformRsaSha1,
                             debug=False):
        """
        Validates signed bynary data (Used to validate GET Signature).

        :param signed_query: The element we should validate
        :type: string


        :param signature: The signature that will be validate
        :type: string

        :param cert: The pubic cert
        :type: string

        :param algorithm: Signature algorithm
        :type: string

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

            if debug:
                xmlsec.set_error_callback(print_xmlsec_errors)

            dsig_ctx = xmlsec.DSigCtx()

            file_cert = OneLogin_Saml2_Utils.write_temp_file(cert)
            dsig_ctx.signKey = xmlsec.Key.load(file_cert.name,
                                               xmlsec.KeyDataFormatCertPem,
                                               None)
            file_cert.close()

            dsig_ctx.verifyBinary(signed_query, algorithm, signature)
            return True
        except Exception:
            return False
Exemple #9
0
    def validate_binary_sign(signed_query, signature, cert=None, algorithm=xmlsec.TransformRsaSha1, debug=False):
        """
        Validates signed bynary data (Used to validate GET Signature).

        :param signed_query: The element we should validate
        :type: string


        :param signature: The signature that will be validate
        :type: string

        :param cert: The pubic cert
        :type: string

        :param algorithm: Signature algorithm
        :type: string

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

            if debug:
                xmlsec.set_error_callback(print_xmlsec_errors)

            dsig_ctx = xmlsec.DSigCtx()

            file_cert = OneLogin_Saml2_Utils.write_temp_file(cert)
            dsig_ctx.signKey = xmlsec.Key.load(file_cert.name, xmlsec.KeyDataFormatCertPem, None)
            file_cert.close()

            dsig_ctx.verifyBinary(signed_query, algorithm, signature)
            return True
        except Exception:
            return False

'''
Created on 1 Feb 2013

@author: Kristy Siu
'''

import logging
import urlparse
import sys
import uuid
from keystone import exception
sys.path.insert(0, '../')
import dm.xmlsec.binding as xmlsec
xmlsec.initialize()
from os.path import dirname, basename
from lxml.etree import parse,tostring,fromstring,ElementTree
from time import localtime, strftime, gmtime
import urllib
import webbrowser
import urllib2
import zlib
import base64
import webob.dec
import webob.exc
import json

from keystone.contrib import mapping
from keystone import catalog
LOG = logging.getLogger(__name__)
Exemple #11
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)
Exemple #12
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
def _encrypt_assertion(unencrypted):
    # load the rsa key
    # Create and initialize keys manager, we use a simple list based
    # keys manager, implement your own KeysStore klass if you need
    # something more sophisticated
    # mngr = xmlsec.KeysMngr()
    # config = saml2idp_metadata.SAML2IDP_CONFIG
    # key = xmlsec.cryptoAppKeyLoad(config['public_key_file'], xmlsec.KeyDataFormatPem, None, None, None)
    # key.setName(config['public_key_file'])
    # # add the key to the manager
    # xmlsec.cryptoAppDefaultKeysMngrAdoptKey(mngr, key)
    #
    # # now encrypt the xml
    # doc = libxml2.parseDoc(unencrypted)
    # # Create encryption template to encrypt XML file and replace
    # # its content with encryption result
    # enc_data_node = xmlsec.TmplEncData(doc, xmlsec.transformAes128CbcId(), None, xmlsec.TypeEncElement, None, None)
    # # put encrypted data in the <enc:CipherValue/> node
    # enc_data_node.ensureCipherValue()
    # # add <dsig:KeyInfo/>
    # key_info_node = enc_data_node.ensureKeyInfo(None)
    # # Add <enc:EncryptedKey/> to store the encrypted session key
    # enc_key_node = key_info_node.addEncryptedKey(xmlsec.transformRsaPkcs1Id(), None, None, None)
    # # put encrypted key in the <enc:CipherValue/> node
    # enc_key_node.ensureCipherValue()
    # # Add <dsig:KeyInfo/> and <dsig:KeyName/> nodes to <enc:EncryptedKey/>
    # key_info_node2 = enc_key_node.ensureKeyInfo(None)
    # # Set key name so we can lookup key when needed
    # key_info_node2.addKeyName(config['public_key_file'])
    # # Create encryption context
    # enc_ctx = xmlsec.EncCtx(mngr)
    # # Generate a Triple DES key
    # key = xmlsec.keyGenerate(xmlsec.keyDataDesId(), 192, xmlsec.KeyDataTypeSession)
    # enc_ctx.encKey = key
    # # Encrypt the data
    # enc_ctx.xmlEncrypt(enc_data_node, doc.getRootElement())
    #
    # # Destroy all
    # key.destroy()
    # mngr.destroy()
    # enc_ctx.destroy()
    # enc_data_node.freeNode()
    # # doc.freeDoc()
    # return doc

    xmlsec.initialize()
    config = saml2idp_metadata.SAML2IDP_CONFIG
    mngr = xmlsec.KeysMngr()
    key = xmlsec.Key.load(config["public_key_file"], xmlsec.KeyDataFormatPem)
    key.name = basename(config["public_key_file"])
    mngr.addKey(key)

    doc = fromstring(unencrypted)
    encData = EncData(xmlsec.TransformDes3Cbc, type=xmlsec.TypeEncElement)
    encData.ensureCipherValue()  # target for encryption result
    keyInfo = encData.ensureKeyInfo()
    encKey = keyInfo.addEncryptedKey(xmlsec.TransformRsaPkcs1)
    encKey.ensureCipherValue()
    encKeyInfo = encKey.ensureKeyInfo()
    encKeyInfo.addKeyName(key.name)
    encCtx = xmlsec.EncCtx(mngr)
    encCtx.encKey = xmlsec.Key.generate(xmlsec.KeyDataDes, 192, xmlsec.KeyDataTypeSession)
    ed = encCtx.encryptXml(encData, doc)
    return tostring(ed.getroottree())
Exemple #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(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()
        #xmlsec.base_64_set_default_line_size(0)

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

        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)
Exemple #15
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
Exemple #16
0
    def generate_name_id(value,
                         sp_nq,
                         sp_format,
                         cert=None,
                         debug=False,
                         nq=None):
        """
        Generates a nameID.

        :param value: fingerprint
        :type: string

        :param sp_nq: SP Name Qualifier
        :type: string

        :param sp_format: SP Format
        :type: string

        :param cert: IdP Public Cert to encrypt the nameID
        :type: string

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

        :param nq: IDP Name Qualifier
        :type: string

        :returns: DOMElement | XMLSec nameID
        :rtype: string
        """
        doc = Document()
        name_id_container = doc.createElementNS(
            OneLogin_Saml2_Constants.NS_SAML, 'container')
        name_id_container.setAttribute("xmlns:saml",
                                       OneLogin_Saml2_Constants.NS_SAML)

        name_id = doc.createElement('saml:NameID')
        if sp_nq is not None:
            name_id.setAttribute('SPNameQualifier', sp_nq)
        if nq is not None:
            name_id.setAttribute('NameQualifier', nq)
        name_id.setAttribute('Format', sp_format)
        name_id.appendChild(doc.createTextNode(value))
        name_id_container.appendChild(name_id)

        if cert is not None:
            xml = name_id_container.toxml()
            elem = fromstring(xml)

            xmlsec.initialize()

            if debug:
                xmlsec.set_error_callback(print_xmlsec_errors)

            # Load the public cert
            mngr = xmlsec.KeysMngr()
            file_cert = OneLogin_Saml2_Utils.write_temp_file(cert)
            key_data = xmlsec.Key.load(file_cert.name,
                                       xmlsec.KeyDataFormatCertPem, None)
            key_data.name = basename(file_cert.name)
            mngr.addKey(key_data)
            file_cert.close()

            # Prepare for encryption
            enc_data = EncData(xmlsec.TransformAes128Cbc,
                               type=xmlsec.TypeEncElement)
            enc_data.ensureCipherValue()
            key_info = enc_data.ensureKeyInfo()
            # enc_key = key_info.addEncryptedKey(xmlsec.TransformRsaPkcs1)
            enc_key = key_info.addEncryptedKey(xmlsec.TransformRsaOaep)
            enc_key.ensureCipherValue()

            # Encrypt!
            enc_ctx = xmlsec.EncCtx(mngr)
            enc_ctx.encKey = xmlsec.Key.generate(xmlsec.KeyDataAes, 128,
                                                 xmlsec.KeyDataTypeSession)

            edata = enc_ctx.encryptXml(enc_data, elem[0])

            newdoc = parseString(etree.tostring(edata))

            if newdoc.hasChildNodes():
                child = newdoc.firstChild
                child.removeAttribute('xmlns')
                child.removeAttribute('xmlns:saml')
                child.setAttribute('xmlns:xenc',
                                   OneLogin_Saml2_Constants.NS_XENC)
                child.setAttribute('xmlns:dsig',
                                   OneLogin_Saml2_Constants.NS_DS)

            nodes = newdoc.getElementsByTagName("*")
            for node in nodes:
                if node.tagName == 'ns0:KeyInfo':
                    node.tagName = 'dsig:KeyInfo'
                    node.removeAttribute('xmlns:ns0')
                    node.setAttribute('xmlns:dsig',
                                      OneLogin_Saml2_Constants.NS_DS)
                else:
                    node.tagName = 'xenc:' + node.tagName

            encrypted_id = newdoc.createElement('saml:EncryptedID')
            encrypted_data = newdoc.replaceChild(encrypted_id,
                                                 newdoc.firstChild)
            encrypted_id.appendChild(encrypted_data)
            return newdoc.saveXML(encrypted_id)
        else:
            return doc.saveXML(name_id)
Exemple #17
0
    def generate_name_id(value, sp_nq, sp_format, cert=None, debug=False):
        """
        Generates a nameID.

        :param value: fingerprint
        :type: string

        :param sp_nq: SP Name Qualifier
        :type: string

        :param sp_format: SP Format
        :type: string

        :param cert: IdP Public Cert to encrypt the nameID
        :type: string

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

        :returns: DOMElement | XMLSec nameID
        :rtype: string
        """
        doc = Document()
        name_id_container = doc.createElementNS(OneLogin_Saml2_Constants.NS_SAML, 'container')
        name_id_container.setAttribute("xmlns:saml", OneLogin_Saml2_Constants.NS_SAML)

        name_id = doc.createElement('saml:NameID')
        name_id.setAttribute('SPNameQualifier', sp_nq)
        name_id.setAttribute('Format', sp_format)
        name_id.appendChild(doc.createTextNode(value))
        name_id_container.appendChild(name_id)

        if cert is not None:
            xml = name_id_container.toxml()
            elem = fromstring(xml)

            xmlsec.initialize()

            if debug:
                xmlsec.set_error_callback(print_xmlsec_errors)

            # Load the public cert
            mngr = xmlsec.KeysMngr()
            file_cert = OneLogin_Saml2_Utils.write_temp_file(cert)
            key_data = xmlsec.Key.load(file_cert.name, xmlsec.KeyDataFormatCertPem, None)
            key_data.name = basename(file_cert.name)
            mngr.addKey(key_data)
            file_cert.close()

            # Prepare for encryption
            enc_data = EncData(xmlsec.TransformAes128Cbc, type=xmlsec.TypeEncElement)
            enc_data.ensureCipherValue()
            key_info = enc_data.ensureKeyInfo()
            # enc_key = key_info.addEncryptedKey(xmlsec.TransformRsaPkcs1)
            enc_key = key_info.addEncryptedKey(xmlsec.TransformRsaOaep)
            enc_key.ensureCipherValue()

            # Encrypt!
            enc_ctx = xmlsec.EncCtx(mngr)
            enc_ctx.encKey = xmlsec.Key.generate(xmlsec.KeyDataAes, 128, xmlsec.KeyDataTypeSession)

            edata = enc_ctx.encryptXml(enc_data, elem[0])

            newdoc = parseString(etree.tostring(edata))

            if newdoc.hasChildNodes():
                child = newdoc.firstChild
                child.removeAttribute('xmlns')
                child.removeAttribute('xmlns:saml')
                child.setAttribute('xmlns:xenc', OneLogin_Saml2_Constants.NS_XENC)
                child.setAttribute('xmlns:dsig', OneLogin_Saml2_Constants.NS_DS)

            nodes = newdoc.getElementsByTagName("*")
            for node in nodes:
                if node.tagName == 'ns0:KeyInfo':
                    node.tagName = 'dsig:KeyInfo'
                    node.removeAttribute('xmlns:ns0')
                    node.setAttribute('xmlns:dsig', OneLogin_Saml2_Constants.NS_DS)
                else:
                    node.tagName = 'xenc:' + node.tagName

            encrypted_id = newdoc.createElement('saml:EncryptedID')
            encrypted_data = newdoc.replaceChild(encrypted_id, newdoc.firstChild)
            encrypted_id.appendChild(encrypted_data)
            return newdoc.saveXML(encrypted_id)
        else:
            return doc.saveXML(name_id)
Exemple #18
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)
Exemple #19
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
Exemple #20
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
Exemple #21
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
Exemple #22
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
Exemple #23
0
"""Initialize xmlsec bindings."""

from zope.i18nmessageid import MessageFactory

_ = MessageFactory('quintagroup.xmlsec.init')

def initialize(context):
    """Initializer called when used as a Zope 2 product."""

from dm.xmlsec.binding import initialize; initialize()
Exemple #24
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
Exemple #25
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)

            # 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
Exemple #26
0
from urllib import quote_plus
from uuid import uuid4
from xml.dom.minidom import Document, Element
from defusedxml.minidom import parseString
from functools import wraps

import zlib

import dm.xmlsec.binding as xmlsec
from dm.xmlsec.binding.tmpl import EncData, Signature

from onelogin.saml2.constants import OneLogin_Saml2_Constants
from onelogin.saml2.errors import OneLogin_Saml2_Error, OneLogin_Saml2_ValidationError

if not globals().get('xmlsec_setup', False):
    xmlsec.initialize()
    globals()['xmlsec_setup'] = True


def return_false_on_exception(func):
    """
    Decorator. When applied to a function, it will, by default, suppress any exceptions
    raised by that function and return False. It may be overridden by passing a
    "raise_exceptions" keyword argument when calling the wrapped function.
    """
    @wraps(func)
    def exceptfalse(*args, **kwargs):
        if not kwargs.pop('raise_exceptions', False):
            try:
                return func(*args, **kwargs)
            except Exception:
Exemple #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)