diff --git a/src/zeep/wsse/signature.py b/src/zeep/wsse/signature.py index c4aec758e..80fff1058 100644 --- a/src/zeep/wsse/signature.py +++ b/src/zeep/wsse/signature.py @@ -49,6 +49,7 @@ def __init__( self, key_data, cert_data, + cert_public_to_verify_response=None, password=None, signature_method=None, digest_method=None, @@ -57,6 +58,7 @@ def __init__( self.key_data = key_data self.cert_data = cert_data + self.cert_public_to_verify_response = cert_public_to_verify_response self.password = password self.digest_method = digest_method self.signature_method = signature_method @@ -69,8 +71,9 @@ def apply(self, envelope, headers): return envelope, headers def verify(self, envelope): - key = _make_verify_key(self.cert_data) - _verify_envelope_with_key(envelope, key) + if self.cert_public_to_verify_response: + key = _make_verify_key(self.cert_public_to_verify_response) + _verify_envelope_with_key(envelope, key) return envelope @@ -81,13 +84,17 @@ def __init__( self, key_file, certfile, + cert_public_to_verify_response=None, password=None, signature_method=None, digest_method=None, ): + if cert_public_to_verify_response: + cert_public_to_verify_response = _read_file(cert_public_to_verify_response) super().__init__( _read_file(key_file), _read_file(certfile), + cert_public_to_verify_response, password, signature_method, digest_method, diff --git a/tests/public_cert_to_verify_response.crt b/tests/public_cert_to_verify_response.crt new file mode 100644 index 000000000..41b3cbc88 --- /dev/null +++ b/tests/public_cert_to_verify_response.crt @@ -0,0 +1,50 @@ +-----BEGIN CERTIFICATE----- +MIII+jCCBuKgAwIBAgIDEKTKMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJF +UzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xOjA4BgNVBAsMMU5aWiBaaXVydGFnaXJp +IHB1Ymxpa29hIC0gQ2VydGlmaWNhZG8gcHVibGljbyBTQ0kxRjBEBgNVBAMMPUhl +cnJpdGFyIGV0YSBFcmFrdW5kZWVuIENBIC0gQ0EgZGUgQ2l1ZGFkYW5vcyB5IEVu +dGlkYWRlcyAoNCkwHhcNMjEwNzEzMDYzOTQ3WhcNMjQwNzEzMDYzOTQ3WjCBvTFJ +MEcGA1UEAxNASU5GT1JNQVRJS0EgWkVSQklUWlVFTiBGT1JVIEVMS0FSVEVBLVNP +Q0lFREFEIEZPUkFMIERFIFNFUlZJQ0lPUzELMAkGA1UEBhMCRVMxSTBHBgNVBAoT +QElORk9STUFUSUtBIFpFUkJJVFpVRU4gRk9SVSBFTEtBUlRFQS1TT0NJRURBRCBG +T1JBTCBERSBTRVJWSUNJT1MxGDAWBgNVBGETD1ZBVEVTLUEyMDQ1Njk3NjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIx7C+vnXIIOtInXW1chLNE6A+aJ +EIh6MHijL0nd2cfkHWpTwHedOJC7432bjw56LUvuFmBBIWOXPN17ZtM6RLT5Vwh9 +JALEgAy9XgW2mq0rcnuz2Y+hHzX5BQ/oTeMoXoJhuqdXHiedmzuUxr+FFGP32Tfd +G6VtOi7gBIxcskUrRxKZ81basyu+iArkHWrpBo2wFLX8KPnebW58vXe09G90Sy5b +bpkms4YdpqrZ4ducOrtSciruRfFuzDfdGjRmcj/z91HF5wlcaVHRxzk37uROhCoV +anuZv8yY1pCrLR2AmFgx1ov6fFWHuNIukXB2CUc8gXNn5ZiFyYvhkfZLJfkCAwEA +AaOCBBUwggQRMIHHBgNVHRIEgb8wgbyGFWh0dHA6Ly93d3cuaXplbnBlLmNvbYEP +aW5mb0BpemVucGUuY29tpIGRMIGOMUcwRQYDVQQKDD5JWkVOUEUgUy5BLiAtIENJ +RiBBMDEzMzcyNjAtUk1lcmMuVml0b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFD +MEEGA1UECQw6QXZkYSBkZWwgTWVkaXRlcnJhbmVvIEV0b3JiaWRlYSAxNCAtIDAx +MDEwIFZpdG9yaWEtR2FzdGVpejAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0lBBYwFAYI +KwYBBQUHAwIGCCsGAQUFBwMEMB0GA1UdDgQWBBTj9KoPA1N0P16WdZmN++ruPdnk +IDAfBgNVHSMEGDAWgBSkFx1OZdfvh5Uuf464dcsFi9OMfTCCASkGA1UdIASCASAw +ggEcMIIBDQYJKwYBBAHzOQILMIH/MCUGCCsGAQUFBwIBFhlodHRwOi8vd3d3Lml6 +ZW5wZS5ldXMvY3BzMIHVBggrBgEFBQcCAjCByAyBxUtvbnRzdWx0YSB3d3cuaXpl +bnBlLmV1cy1lbiBiYWxkaW50emFrIGV0YSBrb25kaXppb2FrIHppdXJ0YWdpcmlh +biBmaWRhdHUgZWRvIGVyYWJpbGkgYXVycmV0aWsgLSBDb25zdWx0ZSBlbiB3d3cu +aXplbnBlLmV1cyBsb3MgdMOpcm1pbm9zIHkgY29uZGljaW9uZXMgYW50ZXMgZGUg +dXRpbGl6YXIgbyBjb25maWFyIGVuIGVsIGNlcnRpZmljYWRvMAkGBwQAi+xAAQEw +gZ8GCCsGAQUFBwEBBIGSMIGPMCIGCCsGAQUFBzABhhZodHRwOi8vb2NzcC5pemVu +cGUuY29tMGkGCCsGAQUFBzAChl1odHRwOi8vd3d3Lml6ZW5wZS5ldXMvY29udGVu +aWRvcy9pbmZvcm1hY2lvbi9jYXNfaXplbnBlL2VzX2Nhcy9hZGp1bnRvcy9DQ0VF +Ul9jZXJ0X3NoYTI1Ni5jcnQwgdEGCCsGAQUFBwEDBIHEMIHBMAgGBgQAjkYBATAL +BgYEAI5GAQMCAQ8wfAYGBACORgEFMHIwJBYeaHR0cHM6Ly93d3cuaXplbnBlLmV1 +cy9wZHMvZW4vEwJlbjAkFh5odHRwczovL3d3dy5pemVucGUuZXVzL3Bkcy9ldS8T +AmV1MCQWHmh0dHBzOi8vd3d3Lml6ZW5wZS5ldXMvcGRzL2VzLxMCZXMwEwYGBACO +RgEGMAkGBwQAjkYBBgIwFQYIKwYBBQUHCwIwCQYHBACL7EkBAjAzBgNVHR8ELDAq +MCigJqAkhiJodHRwOi8vY3JsLml6ZW5wZS5jb20vY2dpLWJpbi9jcmwyMA0GCSqG +SIb3DQEBCwUAA4ICAQBzZuzz61om3tQtgxa/X30NQczZ8D4OBp9DBUNX2GBmNhy3 +8zoorr9WHX5pqySjP3PnhX7mk6+IFxvOZy/joSBcGHpyoh02on7Zzao/SV+T8VMZ +ZpIBsgMuY/oxJ2/L+cY+1q3IQcP5Bxb+7518eGMZ5HDmnaGggT9WtBXA6Qy6iP75 +mohxaq938LLesuVOyBr/oGVMTZSyboz0D2WZkBodRwhzhOcCL64GaVTkHV+sx40j +LShE+tp8fxh9sXiVdwE3FQHOUAfoH+23cDsI37lQ/ZjbmZVXbP9XR2iQ+c/TQC3v +dtF1IaSL1pGjbqrV0Hxn+LSuHmSSJBlFLhRgIzctNtDM1Dr3BQ9gRNshgvrOYXWd ++IPMpU6EnlE1eLuwYIvyVgX6AuVMldWS68dIKXBqnfeesQ7L/KU/4htqZKNznb51 +ZGBw/PcpJFjuY4nfNd+YnEvwXSJbjOz+E+jfXfSMxSnHJnm5rblNpft5RceMPsFd +X5Rt+sOWAWqMGPSeJLdJlaQOz5ThLr3uvSlJrE6LJNF/vp5gYSA08cgrYBh38Ul9 +ocKCJt7hrR64tBgX242pA3F8bD4Hory8IzWojqJAH0wnf0xCJwFJMyl0OI/WakJP +ZfFGhGgNLyfsAbLEZX7Lo9oXYmBVnjN3j7Q4G5NOvsiFcgW7gMdnzg/Rjt1d7Q== +-----END CERTIFICATE----- diff --git a/tests/responses_examples/response_signed.xml b/tests/responses_examples/response_signed.xml new file mode 100644 index 000000000..992081298 --- /dev/null +++ b/tests/responses_examples/response_signed.xml @@ -0,0 +1,37 @@ +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 + + + + + + + + +bQM8HrMFPhywqYuqXMAZSaYvQIM= + + + + + + +pelvAc4x6QHNNe98pdEELilM7js= + + + + + + +ZC3VPHde8wrvgOfI7ZU4T28fhz8= + + + +VLg1gujs/OX7cIFqydTg4cobj5ESCULxLR6VmanHGzarWDg9M7xvCPrBOrVSG0cbGQof+r80E2MK +4FkrXg+0s1uIo1WDOB+OVQVtakd17LlEssn2ip0oyEZrCSfCCKKIxrNhTCmyDzAFIh9Ibn06+Fo3 +wLg30N3IIa5vVsZ/p1QWkjpNpZHM35kMymfRmrIeo0ADfKJIgfqz11MRq49qLXpwX9pFsPHX/Q/s +HJzvFw1PMlX89rPpuuCTdyZ08HXF68HtdLJHuwWGSmnr3aKK3KO/uE9IOs/4qmmvIq3Y0/AzYwl+ +boyI9xeHL4//sZNe1/uWg7EKn1b8LvWvJQ8Atw== + + + + +2022-11-08T14:40:48.040Z2022-11-08T14:41:47.040Z0Correcto/Zuzena2022-0005660481200Erregistratua / Registrada4100Ezeztapena ez da eskatu / No solicita anulación \ No newline at end of file diff --git a/tests/test_wsse_verify_response.py b/tests/test_wsse_verify_response.py new file mode 100644 index 000000000..9205975a3 --- /dev/null +++ b/tests/test_wsse_verify_response.py @@ -0,0 +1,39 @@ +import os +import sys + +import pytest +import zeep +from zeep.wsse.signature import xmlsec as xmlsec_installed +import requests_mock +from zeep.wsse.signature import Signature +from zeep import helpers + + +KEY_FILE = os.path.join(os.path.dirname(os.path.realpath(__file__)), "cert_valid.pem") +PUBLIC_CERT_TO_VERIFY_RESP = os.path.join(os.path.dirname(os.path.realpath(__file__)), "public_cert_to_verify_response.crt") +WSDL_FILE = os.path.join(os.path.dirname(os.path.realpath(__file__)), "wsdl_files/wsdl_to_verify_response.wsdl") +RESPONSE_XML = os.path.join(os.path.dirname(os.path.realpath(__file__)), "responses_examples/response_signed.xml") + +skip_if_no_xmlsec = pytest.mark.skipif( + sys.platform == "win32", reason="does not run on windows" +) and pytest.mark.skipif( + xmlsec_installed is None, reason="xmlsec library not installed" +) + + +@skip_if_no_xmlsec +def test_wsse_verify_response(): + """ + 1 - We assume that the answer from any server from any company is signed. + 2 - We have a public certificate of any company to verify signed responses. + """ + sig = Signature(key_file=KEY_FILE, certfile=KEY_FILE, cert_public_to_verify_response=PUBLIC_CERT_TO_VERIFY_RESP) + client = zeep.Client(wsdl=WSDL_FILE, wsse=sig) + response_ = open(RESPONSE_XML, "r") + response = response_.read() + with requests_mock.mock() as m: + m.post('https://webservice.face.gob.es', text=response, status_code=200) + result = client.service.consultarFactura('2022-000566048') + resp_exp = {"resultado": {"codigo": "0", "descripcion": "Correcto/Zuzena", "codigoSeguimiento": None}, "factura": {"numeroRegistro": "2022-000566048", "tramitacion": {"codigo": "1200", "descripcion": "Erregistratua / Registrada", "motivo": None}, "anulacion": {"codigo": "4100", "descripcion": "Ezeztapena ez da eskatu / No solicita anulación", "motivo": None}}} + resp = helpers.serialize_object(result, dict) + assert resp_exp == resp \ No newline at end of file diff --git a/tests/wsdl_files/wsdl_to_verify_response.wsdl b/tests/wsdl_files/wsdl_to_verify_response.wsdl new file mode 100644 index 000000000..741e90718 --- /dev/null +++ b/tests/wsdl_files/wsdl_to_verify_response.wsdl @@ -0,0 +1,688 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file