def sign_http_post(xmlstr, key, cert, message=False, assertion=True): logger.debug('http-post signing') signer = XMLSigner( signature_algorithm='rsa-sha256', digest_algorithm='sha256', c14n_algorithm='http://www.w3.org/2001/10/xml-exc-c14n#', ) root = fromstring(xmlstr) if assertion: logger.debug('signing assertion') assertions = root.findall('{%s}Assertion' % SAML) for assertion in assertions: issuer = assertion.find('{%s}Issuer' % SAML) issuer.addnext( fromstring( '<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="placeholder"></ds:Signature>' )) root = signer.sign(root, reference_uri=assertion.attrib['ID'], key=key, cert=cert) if message: issuer = root.find('{%s}Issuer' % SAML) issuer.addnext( fromstring( '<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="placeholder"></ds:Signature>' )) root = signer.sign(root, key=key, cert=cert) return tostring(root, pretty_print=False)
def assina_xml(self, xml_element, reference, key_name=None): cert, key = extract_cert_and_key_from_pfx(self.arquivo, self.senha) for element in xml_element.iter("*"): if element.text is not None and not element.text.strip(): element.text = None signer = XMLSigner( method=signxml.methods.enveloped, signature_algorithm="rsa-sha1", digest_algorithm='sha1', c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') ns = {} ns[None] = signer.namespaces['ds'] signer.namespaces = ns ref_uri = ('#%s' % reference) if reference else None signed_root = signer.sign(xml_element, key=key, cert=cert, reference_uri=ref_uri, key_name=key_name) if reference: element_signed = signed_root.find(".//*[@Id='%s']" % reference) signature = signed_root.find( ".//{http://www.w3.org/2000/09/xmldsig#}Signature") if element_signed is not None and signature is not None: parent = element_signed.getparent() parent.append(signature) return etree.tostring(signed_root)
def assina_xml(self, xml_element, reference): cert, key = extract_cert_and_key_from_pfx(self.arquivo, self.senha) for element in xml_element.iter("*"): if element.text is not None and not element.text.strip(): element.text = None signer = XMLSigner( method=signxml.methods.enveloped, signature_algorithm="rsa-sha1", digest_algorithm='sha1', c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') ns = {} ns[None] = signer.namespaces['ds'] signer.namespaces = ns ref_uri = ('#%s' % reference) if reference else None signed_root = signer.sign( xml_element, key=key, cert=cert, reference_uri=ref_uri) if reference: element_signed = signed_root.find(".//*[@Id='%s']" % reference) signature = signed_root.find( ".//{http://www.w3.org/2000/09/xmldsig#}Signature") if element_signed is not None and signature is not None: parent = element_signed.getparent() parent.append(signature) return etree.tostring(signed_root)
def assinar(self, xml, retorna_string=False): # busca tag que tem id(reference_uri), logo nao importa se tem namespace reference = xml.find(".//*[@Id]").attrib['Id'] # retira acentos xml_str = remover_acentos( etree.tostring(xml, encoding="unicode", pretty_print=False)) xml = etree.fromstring(xml_str) signer = XMLSigner( method=signxml.methods.enveloped, signature_algorithm="rsa-sha1", digest_algorithm='sha1', c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') ns = {None: signer.namespaces['ds']} signer.namespaces = ns ref_uri = ('#%s' % reference) if reference else None signed_root = signer.sign(xml, key=self.key, cert=self.cert, reference_uri=ref_uri) ns = {'ns': NAMESPACE_SIG} # coloca o certificado na tag X509Data/X509Certificate tagX509Data = signed_root.find('.//ns:X509Data', namespaces=ns) etree.SubElement(tagX509Data, 'X509Certificate').text = self.cert if retorna_string: return etree.tostring(signed_root, encoding="unicode", pretty_print=False) else: return signed_root
def assina_xml(self, xml_element, reference): cert, key = extract_cert_and_key_from_pfx(self.arquivo, self.senha) for element in xml_element.iter("*"): if element.text is not None and not element.text.strip(): element.text = None signer = XMLSigner( method=signxml.methods.enveloped, signature_algorithm=u"rsa-sha1", digest_algorithm=u'sha1', c14n_algorithm=u'http://www.w3.org/TR/2001/REC-xml-c14n-20010315') ns = {} ns[None] = signer.namespaces['ds'] signer.namespaces = ns element_to_be_signed = xml_element.getchildren()[0].getchildren()[0] signed_root = signer.sign( element_to_be_signed, key=key.encode(), cert=cert.encode()) if reference: element_signed = signed_root.find(".//*[@Id='%s']" % reference) signature = signed_root.find( ".//{http://www.w3.org/2000/09/xmldsig#}Signature") if element_signed is not None and signature is not None: parent = xml_element.getchildren()[0] parent.append(signature) return etree.tostring(xml_element, encoding=str)
def test_x509_certs(self): from OpenSSL.crypto import load_certificate, FILETYPE_PEM, Error as OpenSSLCryptoError tree = etree.parse(self.example_xml_files[0]) ca_pem_file = os.path.join(os.path.dirname(__file__), "example-ca.pem").encode("utf-8") with open(os.path.join(os.path.dirname(__file__), "example.pem"), "rb") as fh: crt = fh.read() with open(os.path.join(os.path.dirname(__file__), "example.key"), "rb") as fh: key = fh.read() for hash_alg in "sha1", "sha256": for method in methods.enveloped, methods.enveloping: print(hash_alg, method) data = tree.getroot() reset_tree(data, method) signer = XMLSigner(method=method, signature_algorithm="rsa-" + hash_alg) signed = signer.sign(data, key=key, cert=crt) signed_data = etree.tostring(signed) XMLVerifier().verify(signed_data, ca_pem_file=ca_pem_file) XMLVerifier().verify(signed_data, x509_cert=crt) XMLVerifier().verify(signed_data, x509_cert=load_certificate(FILETYPE_PEM, crt)) with self.assertRaises(OpenSSLCryptoError): XMLVerifier().verify(signed_data, x509_cert=crt[::-1]) with self.assertRaisesRegexp(InvalidCertificate, "unable to get local issuer certificate"): XMLVerifier().verify(signed_data)
def assina_xml(self, xml_element): cert, key = extract_cert_and_key_from_pfx(self.arquivo, self.senha) for element in xml_element.iter("*"): if element.text is not None and not element.text.strip(): element.text = None signer = XMLSigner( method=methods.enveloped, signature_algorithm=u"rsa-sha1", digest_algorithm=u"sha1", c14n_algorithm=u"http://www.w3.org/TR/2001/REC-xml-c14n-20010315", ) ns = {} ns[None] = signer.namespaces["ds"] signer.namespaces = ns element_signed = xml_element.find(".//{http://nfse.goiania.go.gov.br/xsd/nfse_gyn_v02.xsd}Rps") signed_root = signer.sign( xml_element, key=key.encode(), cert=cert.encode() ) signature = signed_root.find( ".//{http://www.w3.org/2000/09/xmldsig#}Signature" ) if element_signed is not None and signature is not None: parent = xml_element.getchildren()[0] parent.append(signature) return etree.tostring(xml_element, encoding=str)
def assinar(self, xml, retorna_string=False): # busca tag que tem id(reference_uri), logo nao importa se tem namespace reference = xml.find(".//*[@Id]").attrib['Id'] #print('Referencia: ',reference) # retira acentos xml_str = remover_acentos(etree.tostring(xml, encoding="unicode", pretty_print=False)) xml = etree.fromstring(xml_str) signer = XMLSigner( method=signxml.methods.enveloped, signature_algorithm="rsa-sha1", digest_algorithm='sha1', c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') ns = {None: signer.namespaces['ds']} signer.namespaces = ns #print('Chave......: ',self.key) #print('*',200) #print('Certificado: ',self.cert) ref_uri = ('#%s' % reference) if reference else None signed_root = signer.sign( xml, key=self.key, cert=self.cert, reference_uri=ref_uri) ns = {'ns': NAMESPACE_SIG} # coloca o certificado na tag X509Data/X509Certificate tagX509Data = signed_root.find('.//ns:X509Data', namespaces=ns) etree.SubElement(tagX509Data, 'X509Certificate').text = self.cert #print('Assinatura: ',etree.tostring(signed_root, encoding="unicode", pretty_print=False) ) if retorna_string: return etree.tostring(signed_root, encoding="unicode", pretty_print=False) else: return signed_root
def assina_xml(self, xml_element, reference): cert, key = extract_cert_and_key_from_pfx(self.arquivo, self.senha) for element in xml_element.iter("*"): if element.text is not None and not element.text.strip(): element.text = None signer = XMLSigner( method=signxml.methods.enveloped, signature_algorithm="rsa-sha1", digest_algorithm="sha1", c14n_algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315", ) ns = {} ns[None] = signer.namespaces["ds"] signer.namespaces = ns ref_uri = ("#%s" % reference) if reference else None signed_root = signer.sign(xml_element, key=key.encode(), cert=cert.encode(), reference_uri=ref_uri) if reference: element_signed = signed_root.find(".//*[@Id='%s']" % reference) signature = (signed_root.find(".//*[@URI='#%s']" % reference).getparent().getparent()) if element_signed is not None and signature is not None: parent = element_signed.getparent() parent.append(signature) return etree.tostring(signed_root, encoding=str)
def signWithCert(self, stringXml, key, returnString=True): xmlBuffer = etree.fromstring(stringXml) tree = etree.fromstring(stringXml) reference = tree.findall(".//*[@Id]") cert = self.extractCertContent() key = open(key, "rb").read() signer = XMLSigner( method=signxml.methods.enveloped, signature_algorithm="rsa-sha1", digest_algorithm='sha1', c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') ns = {None: signer.namespaces['ds']} signer.namespaces = ns refUri = ('#%s' % reference) if reference else None signedRoot = signer.sign( xmlBuffer, key=key, cert=cert, reference_uri=refUri) ns = {'ns': NAMESPACE_SIG} # Insert the cert file buffered data (content) into specified tags X509Data/X509Certificate tagX509Data = signedRoot.find('.//ns:X509Data', namespaces=ns) etree.SubElement(tagX509Data, 'X509Certificate').text = cert if returnString: xmlEnvelope = etree.tostring(signedRoot, encoding="unicode", pretty_print=False) return xmlEnvelope else: return signedRoot
def test_x509_certs(self): from OpenSSL.crypto import load_certificate, FILETYPE_PEM, Error as OpenSSLCryptoError tree = etree.parse(self.example_xml_files[0]) ca_pem_file = os.path.join(os.path.dirname(__file__), "example-ca.pem").encode("utf-8") with open(os.path.join(os.path.dirname(__file__), "example.pem"), "rb") as fh: crt = fh.read() with open(os.path.join(os.path.dirname(__file__), "example.key"), "rb") as fh: key = fh.read() for hash_alg in "sha1", "sha256": for method in methods.enveloped, methods.enveloping: for c14_transform_option in include_c14_transformation: print(hash_alg, method) data = tree.getroot() reset_tree(data, method) signer = XMLSigner(method=method, signature_algorithm="rsa-" + hash_alg, include_c14n_transform=c14_transform_option) signed = signer.sign(data, key=key, cert=crt) signed_data = etree.tostring(signed) XMLVerifier().verify(signed_data, ca_pem_file=ca_pem_file) XMLVerifier().verify(signed_data, x509_cert=crt) XMLVerifier().verify(signed_data, x509_cert=load_certificate(FILETYPE_PEM, crt)) XMLVerifier().verify(signed_data, x509_cert=crt, cert_subject_name="*.example.com") with self.assertRaises(OpenSSLCryptoError): XMLVerifier().verify(signed_data, x509_cert=crt[::-1]) with self.assertRaises(InvalidSignature): XMLVerifier().verify(signed_data, x509_cert=crt, cert_subject_name="test") with self.assertRaisesRegexp(InvalidCertificate, "unable to get local issuer certificate"): XMLVerifier().verify(signed_data)
def sign(self, data, reference_uri): signer = XMLSigner( method=methods.detached, signature_algorithm="rsa-sha1", digest_algorithm="sha1", c14n_algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315", ) return signer.sign(data=data, key=self.key, cert=self.cert, reference_uri="#{}".format(reference_uri))
def test_signxml_changing_signature_namespace_prefix(self): data = etree.parse(self.example_xml_files[0]).getroot() signer = XMLSigner() signer.namespaces = dict(digi_sign=namespaces['ds']) signed = signer.sign(data, key=self.keys["rsa"]) signed_data = etree.tostring(signed) expected_match = ("<digi_sign:Signature xmlns:" "digi_sign=\"%s\">") % namespaces['ds'] self.assertTrue(re.search(expected_match.encode('ascii'), signed_data))
def sign_http_post(xmlstr, key, cert, message=False, assertion=True): signer = XMLSigner( signature_algorithm='rsa-sha256', digest_algorithm='sha256', ) root = fromstring(xmlstr) if message: root = signer.sign(root, key=key, cert=cert) if assertion: assertions = root.findall('{%s}Assertion' % SAML) for assertion in assertions: _assertion = signer.sign(assertion, key=key, cert=cert) issuer = _assertion.find('{%s}Issuer' % SAML) signature = _assertion.find('%sSignature' % SIG_NS) issuer.addnext(signature) assertion.getparent().replace(assertion, _assertion) response = tostring(root) return base64.b64encode(response).decode('ascii')
def sign_assertion(assertion, key, cert, reference_uri): signer = XMLSigner(signature_algorithm="rsa-sha1", digest_algorithm="sha1", c14n_algorithm="http://www.w3.org/2001/10/xml-exc-c14n#") signed_assertion_element = signer.sign(assertion, key=key, cert=cert, reference_uri=reference_uri) return signed_assertion_element
def sign(node, key_path, cert_path, get_object=False): key = import_key(key_path) cert = import_key(cert_path) signer = XMLSigner( method=methods.enveloped, signature_algorithm='rsa-sha1', digest_algorithm='sha1', c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') signed_node = signer.sign(node, key=key, cert=cert) if get_object is True: return signed_node return etree.tostring(signed_node)
def sign_http_post(xmlstr, key, cert, message=False, assertion=True): # We have to use xml-exc-c14n# because when we isolate the Assertion # element below, a superfluous xmlns:samlp attribute gets added by etree.tostring() # which is not removed by xml-c14n11 (thus generating a wrong digest). signer = XMLSigner( signature_algorithm='rsa-sha256', digest_algorithm='sha256', c14n_algorithm='http://www.w3.org/2001/10/xml-exc-c14n#', ) root = fromstring(xmlstr) if message: root = signer.sign(root, key=key, cert=cert) if assertion: assertions = root.findall('{%s}Assertion' % SAML) for assertion in assertions: _assertion = signer.sign(assertion, key=key, cert=cert) issuer = _assertion.find('{%s}Issuer' % SAML) signature = _assertion.find('%sSignature' % SIG_NS) issuer.addnext(signature) assertion.getparent().replace(assertion, _assertion) response = tostring(root) return base64.b64encode(response).decode('ascii')
def sign(xml, cert_data): signer = XMLSigner( method=signxml.methods.enveloped, signature_algorithm='rsa-sha256', digest_algorithm='sha256', c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315' ) xml_root = None if not isinstance(xml, etree._ElementTree): xml = load_fromfile(xml) xml_root = xml.getroot() signed_root = signer.sign(xml_root, key=cert_data['key_str'], cert=cert_data['cert_str']) return etree.ElementTree(signed_root)
def sign_assertions(response_str): """ Return signed response string """ response_element = etree.fromstring(response_str) cert = read_bytes("keys/cert.pem") key = read_bytes("keys/key.pem") for e in response_element.findall( '{urn:oasis:names:tc:SAML:2.0:assertion}Assertion'): signer = XMLSigner( c14n_algorithm="http://www.w3.org/2001/10/xml-exc-c14n#", signature_algorithm='rsa-sha1', digest_algorithm='sha1') signed_e = signer.sign(e, key=key, cert=cert) response_element.replace(e, signed_e) return etree.tostring(response_element, pretty_print=True)
def sign(element, reference_uri, certificate_data, key_data): signer = XMLSigner( signature_algorithm="rsa-sha1", digest_algorithm="sha1", c14n_algorithm="http://www.w3.org/2001/10/xml-exc-c14n#") # Sign XML. signed_element = signer.sign(element, key=key_data, cert=certificate_data, reference_uri=reference_uri) return signed_element
def assina_xml(self, xml): ##Modificado para utilizar o signxml ao inves do libxml2 e xmlsec from signxml import XMLSigner from signxml import methods xml = self._prepara_doc_xml(xml) doc_xml = lxml.etree.fromstring(xml.encode('utf-8')) #buscando chave de acesso no documento e retiranto TAG Signature chave_de_acesso = self._ler_chave_acesso(doc_xml) if chave_de_acesso is None: raise ValueError( 'Nao foi possivel encontrar a Tag para a assinatura.') #String para bytes para a leitura no signxml chave = self.chave.encode('utf-8') certificado = self.certificado.encode('utf-8') signer = XMLSigner( method=methods.enveloped, signature_algorithm='rsa-sha1', digest_algorithm='sha1', c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') #Retirar os prefixos ds: da assinatura ns = {} ns[None] = signer.namespaces['ds'] signer.namespaces = ns #Assina o documento signed_doc = signer.sign(doc_xml, key=chave, cert=certificado, reference_uri='#{0}'.format(chave_de_acesso)) #Selecionar apenas a tag Signature do documento. signature_tag = None for child in signed_doc: if 'Signature' in child.tag: signature_tag = child if signature_tag is None: raise ("Assinatura nao encontrada.") signature_tag = lxml.etree.tostring(signature_tag).decode('utf-8') signature_tag = self._finaliza_xml(signature_tag) return signature_tag
def make_request(binding, message, destination, key, cert): _binding, method, encoding = BINDINGS_TO_SAML2BINDINGS.get(binding) print('BINDING: {}'.format(binding)) print('METHOD: {}'.format(binding)) print('DESTINATION: {}'.format(destination)) with open(message, 'rb') as fp: message = fp.read() if _binding == BINDING_HTTP_REDIRECT: encoded_message = encoding(message) print('ENCODED MESSAGE: {}'.format(encoded_message)) arguments = { 'SAMLRequest': encoded_message, 'SigAlg': SIG_RSA_SHA256 } args_list = [urlencode({k: arguments[k]}) for k in arguments] query_string = '&'.join(args_list).encode('ascii') digest = SHA256.new() digest.update(query_string) private_key = load_pkey_from_file(key) signer = PKCS1_v1_5.new(private_key) signed = signer.sign(digest) arguments['Signature'] = base64.b64encode(signed) query_string = urlencode(arguments) url = '{}?{}'.format(destination, query_string) print('URL: {}'.format(url)) req_args = [url] elif _binding == BINDING_HTTP_POST: signer = XMLSigner( signature_algorithm='rsa-sha256', digest_algorithm='sha256', ) root = etree.fromstring(message) _key = open(key, 'rb').read() _cert = open(cert, 'rb').read() print(_key, _cert) signed_root = signer.sign(root, key=_key, cert=_cert) message = etree.tostring(signed_root) print('SIGNED XML: {}'.format(message)) encoded_message = encoding(message) print('ENCODED MESSAGE: {}'.format(encoded_message)) url = destination print('URL: {}'.format(url)) extra = {'SAMLRequest': encoded_message} req_args = [url, extra] response = getattr(requests, method)(*req_args, verify=False) print('RESPONSE: {}'. format(response.text))
def sign_assertion(cls, root, key, cert): ''' Reads the certificate and private key to memory from the paths provided. uses signxml module to sign the root object provided. :param root: root object to sign :param : private RSA key to sign with :param : public certificate of the private key :return: a signed root object ''' # Read the private key and certificate key = open(key, "r").read() cert = open(cert, "r").read() # Set up xml signer object signer = XMLSigner(c14n_algorithm=cls.C14_ALG) # Sign the Assertion return signer.sign(root, key=key, cert=cert)
def sign(xml, cert_data, reference_uri=None): signer = XMLSigner( method=signxml.methods.enveloped, signature_algorithm='rsa-sha1', digest_algorithm='sha1', c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') xml_root = None if not isinstance(xml, etree._ElementTree): xml = load_fromfile(xml) xml_root = xml.getroot() # FIX: Isso eh uma gambiarra para poder tirar o prefixo da tag <Signature>, ja que o webservices da Betha # nao consegue achar a assinatura se ela tiver o prefixo do namespace padrao <ds:Signature>... ds = signer.namespaces['ds'] del signer.namespaces['ds'] signer.namespaces[None] = ds signed_root = signer.sign(xml_root, key=cert_data['key_str'], cert=cert_data['cert_str'], reference_uri=reference_uri) return etree.ElementTree(signed_root)
def assina_xml(self, xml_element, reference): cert, key = extract_cert_and_key_from_pfx(self.arquivo, self.senha) for element in xml_element.iter("*"): if element.text is not None and not element.text.strip(): element.text = None signer = XMLSigner( method=signxml.methods.enveloped, signature_algorithm="rsa-sha1", digest_algorithm='sha1', c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') signed_root = signer.sign(xml_element, key=key, cert=cert, reference_uri=('#%s' % reference)) if len(signed_root) > 3: signed_root[2].append(signed_root[3]) return etree.tostring(signed_root)
def test_elementtree_compat(self): data = stdlibElementTree.parse(self.example_xml_files[0]).getroot() signer = XMLSigner() signed = signer.sign(data, key=self.keys["rsa"])
def test_basic_signxml_statements(self): with self.assertRaisesRegexp(InvalidInput, "Unknown signature method"): signer = XMLSigner(method=None) with self.assertRaisesRegexp(InvalidInput, "must be an XML element"): XMLSigner().sign("x") digest_algs = {"sha1", "sha224", "sha256", "sha384", "sha512"} sig_algs = {"hmac", "dsa", "rsa", "ecdsa"} hash_algs = {"sha1", "sha256"} c14n_algs = {"http://www.w3.org/2001/10/xml-exc-c14n#", "http://www.w3.org/2001/10/xml-exc-c14n#WithComments", XMLSignatureProcessor.default_c14n_algorithm} all_methods = itertools.product(digest_algs, sig_algs, hash_algs, methods, c14n_algs) for digest_alg, sig_alg, hash_alg, method, c14n_alg in all_methods: data = [etree.parse(f).getroot() for f in self.example_xml_files] # FIXME: data.extend(stdlibElementTree.parse(f).getroot() for f in (self.example_xml_files) data.append(stdlibElementTree.parse(self.example_xml_files[0]).getroot()) data.append("x y \n z t\n я\n") for d in data: if isinstance(d, str) and method != methods.enveloping: continue print(digest_alg, sig_alg, hash_alg, c14n_alg, method, type(d)) reset_tree(d, method) signer = XMLSigner(method=method, signature_algorithm="-".join([sig_alg, hash_alg]), digest_algorithm=digest_alg, c14n_algorithm=c14n_alg) signed = signer.sign(d, key=self.keys[sig_alg], reference_uri="URI" if method == methods.detached else None) # print(etree.tostring(signed)) hmac_key = self.keys["hmac"] if sig_alg == "hmac" else None verify_kwargs = dict(require_x509=False, hmac_key=hmac_key, validate_schema=True) if method == methods.detached: def resolver(uri): if isinstance(d, stdlibElementTree.Element): return etree.fromstring(stdlibElementTree.tostring(d)) else: return d verify_kwargs["uri_resolver"] = resolver signed_data = etree.tostring(signed) XMLVerifier().verify(signed_data, **verify_kwargs) XMLVerifier().verify(signed_data, parser=parser, **verify_kwargs) (_d, _x, _s) = XMLVerifier().verify(signed_data, id_attribute="Id", **verify_kwargs) if _x is not None: # Ensure the signature is not part of the signed data self.assertIsNone(_x.find(".//{http://www.w3.org/2000/09/xmldsig#}Signature")) self.assertNotEqual(_x.tag, "{http://www.w3.org/2000/09/xmldsig#}Signature") # Ensure the signature was returned self.assertEqual(_s.tag, "{http://www.w3.org/2000/09/xmldsig#}Signature") if method == methods.enveloping: with self.assertRaisesRegexp(InvalidInput, "Unable to resolve reference URI"): XMLVerifier().verify(signed_data, id_attribute="X", **verify_kwargs) with self.assertRaisesRegexp(InvalidInput, "Expected a X.509 certificate based signature"): XMLVerifier().verify(signed_data, hmac_key=hmac_key, uri_resolver=verify_kwargs.get("uri_resolver")) if method != methods.detached: with self.assertRaisesRegexp(InvalidSignature, "Digest mismatch"): mangled_sig = signed_data.replace(b"Austria", b"Mongolia").replace(b"x y", b"a b") XMLVerifier().verify(mangled_sig, **verify_kwargs) with self.assertRaises(cryptography.exceptions.InvalidSignature): mangled_sig = signed_data.replace(b"<ds:DigestValue>", b"<ds:DigestValue>!") XMLVerifier().verify(mangled_sig, **verify_kwargs) with self.assertRaises(cryptography.exceptions.InvalidSignature): sig_value = re.search(b"<ds:SignatureValue>(.+?)</ds:SignatureValue>", signed_data).group(1) mangled_sig = re.sub( b"<ds:SignatureValue>(.+?)</ds:SignatureValue>", b"<ds:SignatureValue>" + b64encode(b64decode(sig_value)[::-1]) + b"</ds:SignatureValue>", signed_data ) XMLVerifier().verify(mangled_sig, **verify_kwargs) with self.assertRaises(etree.XMLSyntaxError): XMLVerifier().verify("", hmac_key=hmac_key, require_x509=False) if sig_alg == "hmac": with self.assertRaisesRegexp(InvalidSignature, "Signature mismatch"): verify_kwargs["hmac_key"] = b"SECRET" XMLVerifier().verify(signed_data, **verify_kwargs)
def generate_saml(self, post_data): '''Update all of the relevant fields in saml_template.xml with the form data''' parser = ET.XMLParser(remove_blank_text=True) now = datetime.datetime.utcnow() issue_instant = now.strftime('%Y-%m-%dT%H:%M:%S.%fZ')[:-4] + 'Z' tree = ET.parse('saml_post/static/saml_post/saml_template.xml', parser=parser) # if this ever breaks it might be easier to troubleshoot with the template as a string ## saml_template = '<samlp:Response ID="_4ba3eca7-7f9f-4a77-9006-4e1fae8bee1b" Version="2.0" IssueInstant="2020-01-10T13:09:52.256Z" Destination="https://secure-enroll.com/sso/saml" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"><Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">https://sts.windows.net/23e14383-b783-4c99-bf4f-5049cd014ec6/</Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="placeholder" /><samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></samlp:Status><Assertion ID="_fdaa4a4b-ffad-4d60-bb95-86bb6c312000" IssueInstant="2020-01-10T13:09:52.256Z" Version="2.0" xmlns="urn:oasis:names:tc:SAML:2.0:assertion"><Issuer>https://sts.windows.net/23e14383-b783-4c99-bf4f-5049cd014ec6/</Issuer><Subject><NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">0VFMNdkRdozsmj7W8PDmoCgje2almNSSeKSz1N2v1FM</NameID><SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><SubjectConfirmationData NotOnOrAfter="2020-01-10T14:09:51.974Z" Recipient="https://secure-enroll.com/sso/saml"/></SubjectConfirmation></Subject><Conditions NotBefore="2020-01-10T13:04:51.974Z" NotOnOrAfter="2020-01-10T14:09:51.974Z"><AudienceRestriction><Audience>https://secure-enroll.com/sso/saml</Audience></AudienceRestriction></Conditions><AttributeStatement><Attribute Name="http://schemas.microsoft.com/identity/claims/tenantid"><AttributeValue>23e14383-b783-4c99-bf4f-5049cd014ec6</AttributeValue></Attribute></AttributeStatement></Assertion></samlp:Response>' ## root = ET.fromstring(saml_template) root = tree.getroot() # namespaces are ew but you can use .find('saml:Assertion', saml) where the second parameter (saml) is this dictionary instead of indexing into each element saml = {'saml': 'urn:oasis:names:tc:SAML:2.0:assertion', 'signature': 'http://www.w3.org/2000/09/xmldsig#}Signature'} root.find('saml:Issuer', saml).text = post_data['issuer_id'] root.attrib['Destination'] = post_data['acs_endpoint'] root.attrib['IssueInstant'] = issue_instant root.find('saml:Assertion', saml).attrib['IssueInstant'] = issue_instant root.find('saml:Assertion', saml).find('saml:Subject', saml).find('saml:NameID', saml).text = post_data[ 'saml_subject'] root.find('saml:Assertion', saml).find('saml:Subject', saml).find('saml:SubjectConfirmation', saml).find( 'saml:SubjectConfirmationData', saml).attrib['NotOnOrAfter'] = (now + timedelta(hours=1)).strftime( '%Y-%m-%dT%H:%M:%S.%fZ')[:-4] + 'Z' root.find('saml:Assertion', saml).find('saml:Subject', saml).find('saml:SubjectConfirmation', saml).find( 'saml:SubjectConfirmationData', saml).attrib['Recipient'] = post_data['audience_id'] root.find('saml:Assertion', saml).find('saml:Conditions', saml).attrib['NotBefore'] = (now - timedelta( minutes=10)).strftime('%Y-%m-%dT%H:%M:%S.%fZ')[:-4] + 'Z' root.find('saml:Assertion', saml).find('saml:Conditions', saml).attrib['NotOnOrAfter'] = (now + timedelta( hours=1)).strftime('%Y-%m-%dT%H:%M:%S.%fZ')[:-4] + 'Z' root.find('saml:Assertion', saml).find('saml:Conditions', saml).find('saml:AudienceRestriction', saml).find( 'saml:Audience', saml).text = post_data['audience_id'] #root.find('saml:Assertion', saml).find('saml:AttributeStatement', saml).find('saml:Attribute', saml).attrib[ # 'Name'] = self.fields['attributes'][0]['attribute_name'] #post_data['attribute_name'] #root.find('saml:Assertion', saml).find('saml:AttributeStatement', saml).find('saml:Attribute', saml).find( # 'saml:AttributeValue', saml).text = self.fields['attributes'][0]['attribute_value'] # post_data['attribute_value'] root.find('saml:Assertion', saml).find('saml:Issuer', saml).text = post_data['issuer_id'] attribute_element_copy = deepcopy(root.find('saml:Assertion', saml).find('saml:AttributeStatement', saml).find( 'saml:Attribute', saml)) element_to_remove = root.find('saml:Assertion', saml).find('saml:AttributeStatement', saml).find('saml:Attribute', saml) root.find('saml:Assertion', saml).find('saml:AttributeStatement', saml).remove(element_to_remove) for attribute in self.fields['attributes']: new_attribute = deepcopy(attribute_element_copy) new_attribute.attrib['Name'] = attribute['attribute_name'] new_attribute.find('saml:AttributeValue', saml).text = attribute['attribute_value'] root.find('saml:Assertion', saml).find('saml:AttributeStatement', saml).append(new_attribute) #test #a = deepcopy(root.find('saml:Assertion', saml).find('saml:AttributeStatement', saml).find('saml:Attribute', saml)) #root.find('saml:Assertion', saml).find('saml:AttributeStatement', saml).append(a) # sign the newly created xml reference_uri = '_4ba3eca7-7f9f-4a77-9006-4e1fae8bee1b' with open("saml_post/static/saml_post/publickey.cer") as f: cert = f.read() with open("saml_post/static/saml_post/private.key") as f: key = f.read() ''' From the SAML Oasis docs: Signatures in SAML messages SHOULD NOT contain transforms other than the enveloped signature transform (with the identifier http://www.w3.org/2000/09/xmldsig#enveloped-signature) or the exclusive canonicalization transforms (with the identifier http://www.w3.org/2001/10/xml-exc-c14n# or http://www.w3.org/2001/10/xml-exc-c14n#WithComments). The default behavior for XMLSigner uses some other transforms so we need to specify the c14n_algorithm. ''' signer = XMLSigner(c14n_algorithm='http://www.w3.org/2001/10/xml-exc-c14n#', signature_algorithm="rsa-sha256", digest_algorithm="sha256", method=signxml.methods.enveloped) signed_root = signer.sign(root, key=key, cert=cert, reference_uri=reference_uri) return ET.tostring(signed_root, encoding='utf-8')
def test_reference_uris_and_custom_key_info(self): with open(os.path.join(os.path.dirname(__file__), "example.pem"), "rb") as fh: crt = fh.read() with open(os.path.join(os.path.dirname(__file__), "example.key"), "rb") as fh: key = fh.read() # Both ID and Id formats. XPath 1 doesn't have case insensitive attribute search for d in [ '''<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="responseId"> <saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="assertionId"> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="placeholder" /> </saml:Assertion> </samlp:Response>''', '''<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Id="responseId"> <saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" Id="assertionId"> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="placeholder" /> </saml:Assertion> <saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" Id="assertion2"> </saml:Assertion> </samlp:Response>''' ]: data = etree.fromstring(d) reference_uri = ["assertionId", "assertion2" ] if "assertion2" in d else "assertionId" signed_root = XMLSigner().sign(data, reference_uri=reference_uri, key=key, cert=crt) signed_data_root = XMLVerifier().verify( etree.tostring(signed_root), x509_cert=crt, expect_references=True)[1] ref = signed_root.xpath( '/samlp:Response/saml:Assertion/ds:Signature/ds:SignedInfo/ds:Reference', namespaces={ "ds": "http://www.w3.org/2000/09/xmldsig#", "saml": "urn:oasis:names:tc:SAML:2.0:assertion", "samlp": "urn:oasis:names:tc:SAML:2.0:protocol" }) self.assertEqual("assertionId", ref[0].attrib['URI'][1:]) self.assertEqual( "{urn:oasis:names:tc:SAML:2.0:assertion}Assertion", signed_data_root.tag) # Also test with detached signing ref_xpath = "/ds:Signature/ds:SignedInfo/ds:Reference" signer = XMLSigner(method=methods.detached) s = signer.sign(data, reference_uri=reference_uri, key=key, cert=crt) self.assertTrue( s.xpath(ref_xpath + "/ds:Transforms", namespaces=namespaces)) self.assertTrue( s.xpath(ref_xpath + "/ds:DigestMethod", namespaces=namespaces)) self.assertTrue( s.xpath(ref_xpath + "/ds:DigestValue", namespaces=namespaces)) self.assertTrue( s.xpath("/ds:Signature/ds:KeyInfo/ds:X509Data", namespaces=namespaces)) self.assertFalse( s.xpath("/ds:Signature/ds:KeyInfo/ds:KeyValue", namespaces=namespaces)) s2 = signer.sign(data, reference_uri=reference_uri, key=key, cert=crt, always_add_key_value=True) self.assertTrue( s2.xpath("/ds:Signature/ds:KeyInfo/ds:X509Data", namespaces=namespaces)) self.assertTrue( s2.xpath("/ds:Signature/ds:KeyInfo/ds:KeyValue", namespaces=namespaces)) # Test setting custom key info wsse_ns = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" with open( os.path.join(os.path.dirname(__file__), "wsse_keyinfo.xml")) as fh: custom_key_info = etree.fromstring(fh.read()) s3 = signer.sign(data, reference_uri=reference_uri, key=key, cert=crt, key_info=custom_key_info) self.assertTrue( s3.xpath( "/ds:Signature/ds:KeyInfo/wsse:SecurityTokenReference", namespaces=dict(namespaces, wsse=wsse_ns))) # Test setting both X509Data and KeyInfo s4 = XMLSigner().sign(data, reference_uri=reference_uri, key=key, cert=crt, always_add_key_value=True) with self.assertRaisesRegexp(InvalidInput, "Both X509Data and KeyValue found"): XMLVerifier().verify(s4, x509_cert=crt) expect_refs = etree.tostring(s4).decode().count("<ds:Reference") XMLVerifier().verify(s4, x509_cert=crt, ignore_ambiguous_key_info=True, expect_references=expect_refs)
class Assinatura: def __init__(self, certificado, chave, namespace): self.cert = certificado self.key = chave self.NAMESPACE = namespace self._assinador = XMLSigner( method=methods.detached, signature_algorithm="rsa-sha1", digest_algorithm='sha1', c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') def assinar_lote_rps(self, xml_lote_rps): root = etree.fromstring(xml_lote_rps.encode()) lista_rps = root.findall('./{0}LoteRps/{0}ListaRps/*'.format( self.NAMESPACE)) for rps in lista_rps: infrps = rps.find('{0}InfRps'.format(self.NAMESPACE)) reference_uri = infrps.attrib.get('id') assinatura = self._assinatura_xml(rps, reference_uri) rps.append(assinatura) lote_rps = root.find('{0}LoteRps'.format(self.NAMESPACE)) reference_uri = lote_rps.attrib.get('id') assinatura = self._assinatura_xml(root, reference_uri) root.append(assinatura) xml_lote_rps_assinado = etree.tostring(root, encoding='utf-8').decode() xml_lote_rps_assinado = xml_lote_rps_assinado.replace('ds:', '').replace( ':ds', '') return xml_lote_rps_assinado def assinar_cancelamento_nfse(self, xml_cancelamento_nfse): root = etree.fromstring(xml_cancelamento_nfse.encode()) pedido = root.find('{0}Pedido'.format(self.NAMESPACE)) inf_pedido = pedido.find('{0}InfPedidoCancelamento'.format( self.NAMESPACE)) reference_uri = inf_pedido.attrib.get('id') assinatura = self._assinatura_xml(pedido, reference_uri) pedido.append(assinatura) xml_pedido_cancelamento_assinado = etree.tostring( root, encoding='utf-8').decode() xml_pedido_cancelamento_assinado = xml_pedido_cancelamento_assinado.replace( 'ds:', '').replace(':ds', '') return xml_pedido_cancelamento_assinado def _assinatura_xml(self, data, reference_uri): assinatura = self._assinador.sign( data=data, key=self.key, cert=self.cert, reference_uri='#{}'.format(reference_uri)) return assinatura
def test_basic_signxml_statements(self): with self.assertRaisesRegexp(InvalidInput, "Unknown signature method"): signer = XMLSigner(method=None) with self.assertRaisesRegexp(InvalidInput, "must be an XML element"): XMLSigner().sign("x") digest_algs = {"sha1", "sha224", "sha256", "sha384", "sha512"} sig_algs = {"hmac", "dsa", "rsa", "ecdsa"} hash_algs = {"sha1", "sha256"} c14n_algs = { "http://www.w3.org/2001/10/xml-exc-c14n#", "http://www.w3.org/2001/10/xml-exc-c14n#WithComments", XMLSignatureProcessor.default_c14n_algorithm } all_methods = itertools.product(digest_algs, sig_algs, hash_algs, methods, c14n_algs) for digest_alg, sig_alg, hash_alg, method, c14n_alg in all_methods: data = [etree.parse(f).getroot() for f in self.example_xml_files] # FIXME: data.extend(stdlibElementTree.parse(f).getroot() for f in (self.example_xml_files) data.append( stdlibElementTree.parse(self.example_xml_files[0]).getroot()) data.append("x y \n z t\n я\n") for d in data: if isinstance(d, str) and method != methods.enveloping: continue print(digest_alg, sig_alg, hash_alg, c14n_alg, method, type(d)) reset_tree(d, method) signer = XMLSigner(method=method, signature_algorithm="-".join( [sig_alg, hash_alg]), digest_algorithm=digest_alg, c14n_algorithm=c14n_alg) signed = signer.sign(d, key=self.keys[sig_alg], reference_uri="URI" if method == methods.detached else None) # print(etree.tostring(signed)) hmac_key = self.keys["hmac"] if sig_alg == "hmac" else None verify_kwargs = dict(require_x509=False, hmac_key=hmac_key, validate_schema=True) if method == methods.detached: def resolver(uri): if isinstance(d, stdlibElementTree.Element): return etree.fromstring( stdlibElementTree.tostring(d)) else: return d verify_kwargs["uri_resolver"] = resolver signed_data = etree.tostring(signed) XMLVerifier().verify(signed_data, **verify_kwargs) XMLVerifier().verify(signed_data, parser=parser, **verify_kwargs) (_d, _x, _s) = XMLVerifier().verify(signed_data, id_attribute="Id", **verify_kwargs) if _x is not None: # Ensure the signature is not part of the signed data self.assertIsNone( _x.find( ".//{http://www.w3.org/2000/09/xmldsig#}Signature") ) self.assertNotEqual( _x.tag, "{http://www.w3.org/2000/09/xmldsig#}Signature") # Ensure the signature was returned self.assertEqual( _s.tag, "{http://www.w3.org/2000/09/xmldsig#}Signature") if method == methods.enveloping: with self.assertRaisesRegexp( InvalidInput, "Unable to resolve reference URI"): XMLVerifier().verify(signed_data, id_attribute="X", **verify_kwargs) with self.assertRaisesRegexp( InvalidInput, "Expected a X.509 certificate based signature"): XMLVerifier().verify( signed_data, hmac_key=hmac_key, uri_resolver=verify_kwargs.get("uri_resolver")) if method != methods.detached: with self.assertRaisesRegexp(InvalidSignature, "Digest mismatch"): mangled_sig = signed_data.replace( b"Austria", b"Mongolia").replace(b"x y", b"a b") XMLVerifier().verify(mangled_sig, **verify_kwargs) with self.assertRaises( cryptography.exceptions.InvalidSignature): mangled_sig = signed_data.replace(b"<ds:DigestValue>", b"<ds:DigestValue>!") XMLVerifier().verify(mangled_sig, **verify_kwargs) with self.assertRaises( cryptography.exceptions.InvalidSignature): sig_value = re.search( b"<ds:SignatureValue>(.+?)</ds:SignatureValue>", signed_data).group(1) mangled_sig = re.sub( b"<ds:SignatureValue>(.+?)</ds:SignatureValue>", b"<ds:SignatureValue>" + b64encode(b64decode(sig_value)[::-1]) + b"</ds:SignatureValue>", signed_data) XMLVerifier().verify(mangled_sig, **verify_kwargs) with self.assertRaises(etree.XMLSyntaxError): XMLVerifier().verify("", hmac_key=hmac_key, require_x509=False) if sig_alg == "hmac": with self.assertRaisesRegexp(InvalidSignature, "Signature mismatch"): verify_kwargs["hmac_key"] = b"SECRET" XMLVerifier().verify(signed_data, **verify_kwargs)
def get_feed(): user_name_token = username_password() signature = binary_signature_timestamp() client = Client('tweaked_xml/wsdl.xml', wsse=[user_name_token, signature], plugins=[WsAddressingPlugin()]) # client.set_ns_prefix('', 'http://information.gateway.ofsted.gov.uk/ispp') # client.set_ns_prefix('s', 'http://www.w3.org/2003/05/soap-envelope') client.set_ns_prefix('a', 'http://www.w3.org/2005/08/addressing') client.set_ns_prefix('u', 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd') parameters = { 'LocalAuthorityCode': 825 } # Add a "ReplyTo/Address" header = xsd.Element( '{http://www.w3.org/2005/08/addressing}ReplyTo', xsd.ComplexType([ xsd.Element( '{http://www.w3.org/2005/08/addressing}Address', xsd.String()), ]) ) header_value = header(Address='http://www.w3.org/2005/08/addressing/anonymous') # Request document envelope = client.create_message(client.service, 'GetLocalAuthorityChildcareRegister', localAuthorityRequest=parameters, _soapheaders=[header_value]) # # Update a few tricky values header_tag = envelope.find('{http://www.w3.org/2003/05/soap-envelope}Header') security_tag = header_tag.find('{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security') # Mark the Timestamp tag for signing: timestamp_tag = security_tag.find('{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp') timestamp_tag.attrib['{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Id']="_0" # De-duplicate and tweak the To tag for signing: for child_tag in header_tag: if child_tag.tag == '{http://www.w3.org/2005/08/addressing}To': to_tag = child_tag insert_index = header_tag.index(child_tag) header_tag.remove(child_tag) header_tag.insert(insert_index, to_tag) to_tag.attrib['{http://www.w3.org/2003/05/soap-envelope}mustUnderstand']="1" to_tag.attrib['{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Id']="_1" # Remove the standard signature so we can replace it with what's needed for this specific implementation: signature_tag = security_tag.find('{http://www.w3.org/2000/09/xmldsig#}Signature') signature_index = security_tag.index(signature_tag) binary_security_token_tag = security_tag.find('{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}BinarySecurityToken') security_tag.remove(signature_tag) security_tag.remove(binary_security_token_tag) # Re-sign in the way that's expected by this service: signer = XMLSigner( method=methods.detached, digest_algorithm='sha1', signature_algorithm='rsa-sha1', c14n_algorithm='http://www.w3.org/2001/10/xml-exc-c14n#' ) private = get_secret('private_key') public = get_secret('certificate') signature = signer.sign(envelope, key=private, cert=public, reference_uri=['_0', '_1']) security_tag.insert(signature_index, signature) # Add the signature to the document: xmlstr = str(etree.tostring(envelope, encoding='unicode', pretty_print=True)) print(f" *** Signed:\n {xmlstr}") for tag in security_tag: print(tag.tag) for subtag in tag: print(f' - {subtag.tag}') # header = envelope.find('{http://www.w3.org/2003/05/soap-envelope}Header') # security = header.find('{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security') # signature = security.find('{http://www.w3.org/2000/09/xmldsig#}Signature') # signature_value = signature.find('{http://www.w3.org/2000/09/xmldsig#}SignatureValue') # binary_security_token = security.find('{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}BinarySecurityToken') # # Reformat base-64 values without line-wrapping # # # (possible the server isn't reading them correctly otherwise) # nowrapping(signature_value) # nowrapping(binary_security_token) # # Sprinkle in some 'mustUnderstand' just in case # mustunderstanders = [ # '{http://www.w3.org/2005/08/addressing}Action', # '{http://www.w3.org/2005/08/addressing}To', # '{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security' # ] # for child in header: # if child.tag in mustunderstanders: # print(f"Adding mustUnderstand to {child.tag}") # child.attrib['{http://www.w3.org/2003/05/soap-envelope}mustUnderstand']="1" # # Temp: c14n test # print("...") # for child in header: # if child.tag == '{http://www.w3.org/2005/08/addressing}Action': # print(f"C14nning: {child.tag}") # print("...") # # Pop in a couple of missing ids # signer = XMLSigner( # method=methods.detached, # digest_algorithm='sha1', # signature_algorithm='rsa-sha1', # c14n_algorithm='http://www.w3.org/2001/10/xml-exc-c14n#' # ) # ref = 0 # for child in header: # if child.tag == '{http://www.w3.org/2005/08/addressing}To': # child.attrib['{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Id'] = "_1" # private = get_secret('private_key') # public = get_secret('certificate') # signed_root = signer.sign(child, key=private, cert=public, key_info='ouagadougou', reference_uri=f'_{ref}') # ref = ref + 1 # #signed_root = XMLSigner().sign(child, key=private, cert=public) # xmlstr = str(etree.tostring(signed_root, encoding='unicode', pretty_print=True)) # print(f" *** Signed:\n {xmlstr}") # for child in security: # if child.tag == '{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}UsernameToken': # child.attrib['{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Id'] = "_2" # # Delete duplicated elements # duplicates = ['{http://www.w3.org/2005/08/addressing}Action', '{http://www.w3.org/2005/08/addressing}To', '{http://www.w3.org/2005/08/addressing}MessageID'] # deduped = {} # insert_index = 0 # for child in header: # if child.tag in duplicates: # deduped[child.tag] = child # header.remove(child) # if child.tag == '{http://www.w3.org/2005/08/addressing}ReplyTo': # insert_index = header.index(child) # # Re-insert the de-duped elements # for child in deduped.values(): # insert_index = insert_index + 1 # header.insert(insert_index, child) # for child in header: # print(f' - {child.tag[child.tag.rindex("}")+1:]} {child.tag} --> {child.attrib}') # if child.tag=='{http://www.w3.org/2005/08/addressing}ReplyTo': # print(header.index(child)) # xmlstr = minidom.parseString(ET.tostring(node)).toprettyxml(indent=" ") #xmlstr = str(etree.tostring(signed, encoding='unicode', pretty_print=True)) # print(type(xmlstr)) # xmlstr=tweak(xmlstr) ##print(xmlstr) # if os.path.isdir('/output'): # with open('/output/actual1.xml', 'w+') as f: # f.write(xmlstr) # print("Saved generated XML message.") if os.path.isdir('../secrets/compare'): with open('../secrets/compare/actual1.xml', 'w+') as f: f.write(xmlstr) print("Saved generated XML message..............................") response = call_proxy(envelope) if response.status_code != 200: print(f"{response.status_code}: {response.text}") #return minidom.parseString(response.text) #ET.tostring(feed, encoding='unicode').toprettyxml(indent=" ") #return Response(f"{response.status_code} -- {response.text}"), 200 #return "Fin." return Response(response.text, mimetype='text/xml'), response.status_code