예제 #1
0
파일: utils.py 프로젝트: skarra/python-saml
    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))

        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)
예제 #2
0
    def decrypt_element(encrypted_data, key, debug=False, inplace=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

        :param inplace: update passed data with decrypted result
        :type: bool

        :returns: The decrypted element.
        :rtype: lxml.etree.Element
        """
        if isinstance(encrypted_data, Element):
            encrypted_data = fromstring(str(encrypted_data.toxml()),
                                        forbid_dtd=True)
        elif isinstance(encrypted_data, basestring):
            encrypted_data = fromstring(str(encrypted_data), forbid_dtd=True)
        elif not inplace and isinstance(encrypted_data, etree._Element):
            encrypted_data = deepcopy(encrypted_data)

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

        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)
예제 #3
0
    def generate_name_id(value,
                         sp_nq,
                         sp_format=None,
                         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)
        if sp_format is not None:
            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)

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

            # 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(
                tostring(edata, encoding='unicode').encode('utf-8'))

            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)
예제 #4
0
    def validate_node_sign(signature_node,
                           elem,
                           cert=None,
                           fingerprint=None,
                           fingerprintalg='sha1',
                           validatecert=False,
                           debug=False):
        """
        Validates a signature node.

        :param signature_node: The signature node
        :type: Node

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

        :param cert: The public cert
        :type: string

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

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

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

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

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

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

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

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

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

        file_cert = OneLogin_Saml2_Utils.write_temp_file(cert)

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

        file_cert.close()

        dsig_ctx.setEnabledKeyData([xmlsec.KeyDataX509])

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

        return True
예제 #5
0
파일: utils.py 프로젝트: skarra/python-saml
    def validate_node_sign(signature_node,
                           elem,
                           cert=None,
                           fingerprint=None,
                           fingerprintalg='sha1',
                           validatecert=False,
                           debug=False):
        """
        Validates a signature node.

        :param signature_node: The signature node
        :type: Node

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

        :param cert: The public cert
        :type: string

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

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

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

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

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

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

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

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

            file_cert = OneLogin_Saml2_Utils.write_temp_file(cert)

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

            file_cert.close()

            dsig_ctx.setEnabledKeyData([xmlsec.KeyDataX509])
            dsig_ctx.verify(signature_node)
            return True
        except Exception:
            return False
예제 #6
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