Brian
Brian

Reputation: 97

Changing the service URL when accessing SOAP via a proxy using Zeep

Within my application, I need to access an internal (corporate) Soap API. For this access I have used Zeep so far. But now the access has to go through a proxy and the actual address of the API has to be converted to a virtual address of the proxy.

Creating the Zeep client also works correctly and I can access the WSDL files. However, the problem occurs when calling the respective service, because Zeep takes the corresponding URL from the WSDL file and this does not match the virtual address of the proxy.

I'll try to illustrate the problem below with my concrete code:

Assuming the address of the SOAP API is https://original-soap/wsdl?service=<service_name>.

In the proxy there is a mapping from https://origial-soap to http://virtual-soap.

So the address Zeep should use then is http://virtual-soap/wsdl?service=<service_name>.

I initialize my Zeep client as follows:

from requests.auth import HTTPBasicAuth
from requests import Session
from zeep import Client
from zeep.transports import Transport
from zeep.helpers import serialize_object

session = Session()
session.proxies = {
    'http': 'http://<proxy_host>:<proxy_port>',
    'https': 'http://<proxy_host>:<proxy_port>',
}
proxy_header = {
    "Proxy-Authorization": "Bearer <proxy_access_token>"
}
session.headers.update(proxy_header)
session.verify = False
session.auth = HTTPBasicAuth(<soap_user>, <soap_password>)
transport = Transport(session=session)

client = Client(wsdl='http://virtual-saop/wsdl?service=<service_name>', transport=transport)

print('CLIENT INITIALIZED') # <-- This print command is executed

soap_result = client.service['<service_function_name>'](<function parameters>) # <-- Connectivity errors occur here

So my question is how I can also change the URL that Zeep uses when calling the service so that the virtual address is used here as well.

Thanks for any help in advance!

Thanks to @Bogdan, I solved the problem using the following code for the service initialization:

service = client.create_service(
    client.service._binding.name, client.service._binding_options['address'].replace('https://original-soap:443', 'http://virtual-soap:80', 1)
)

Upvotes: 2

Views: 1040

Answers (1)

Bogdan
Bogdan

Reputation: 24590

There is another way to create the ServiceProxy that's supposed to do that.

See the documentation at https://docs.python-zeep.org/en/master/client.html#creating-new-serviceproxy-objects

The default ServiceProxy instance is created using the address in the WSDL, but the above way of creating the ServiceProxy allows more control on the address.

The value for {http://my-target-namespace-here}myBinding is your binding identifier. If you do a python -mzeep https://original-soap/wsdl you should get an output like this one (I'm using some online example here for demonstration purposes, since I don't have access to your WSDL):

> python -mzeep http://www.dneonline.com/calculator.asmx?WSDL

    
Prefixes:
     xsd: http://www.w3.org/2001/XMLSchema
     ns0: http://tempuri.org/

Global elements:
     ns0:Add(intA: xsd:int, intB: xsd:int)
     ns0:AddResponse(AddResult: xsd:int)
     ns0:Divide(intA: xsd:int, intB: xsd:int)
     ns0:DivideResponse(DivideResult: xsd:int)
     ns0:Multiply(intA: xsd:int, intB: xsd:int)
     ns0:MultiplyResponse(MultiplyResult: xsd:int)
     ns0:Subtract(intA: xsd:int, intB: xsd:int)
     ns0:SubtractResponse(SubtractResult: xsd:int)
     

Global types:
     xsd:anyType
     xsd:ENTITIES
     xsd:ENTITY
     xsd:ID
     xsd:IDREF
     xsd:IDREFS
     xsd:NCName
     xsd:NMTOKEN
     xsd:NMTOKENS
     xsd:NOTATION
     xsd:Name
     xsd:QName
     xsd:anySimpleType
     xsd:anyURI
     xsd:base64Binary
     xsd:boolean
     xsd:byte
     xsd:date
     xsd:dateTime
     xsd:decimal
     xsd:double
     xsd:duration
     xsd:float
     xsd:gDay
     xsd:gMonth
     xsd:gMonthDay
     xsd:gYear
     xsd:gYearMonth
     xsd:hexBinary
     xsd:int
     xsd:integer
     xsd:language
     xsd:long
     xsd:negativeInteger
     xsd:nonNegativeInteger
     xsd:nonPositiveInteger
     xsd:normalizedString
     xsd:positiveInteger
     xsd:short
     xsd:string
     xsd:time
     xsd:token
     xsd:unsignedByte
     xsd:unsignedInt
     xsd:unsignedLong
     xsd:unsignedShort

Bindings:
     Soap11Binding: {http://tempuri.org/}CalculatorSoap
     Soap12Binding: {http://tempuri.org/}CalculatorSoap12

Service: Calculator
     Port: CalculatorSoap (Soap11Binding: {http://tempuri.org/}CalculatorSoap)
         Operations:
            Add(intA: xsd:int, intB: xsd:int) -> AddResult: xsd:int
            Divide(intA: xsd:int, intB: xsd:int) -> DivideResult: xsd:int
            Multiply(intA: xsd:int, intB: xsd:int) -> MultiplyResult: xsd:int
            Subtract(intA: xsd:int, intB: xsd:int) -> SubtractResult: xsd:int

     Port: CalculatorSoap12 (Soap12Binding: {http://tempuri.org/}CalculatorSoap12)
         Operations:
            Add(intA: xsd:int, intB: xsd:int) -> AddResult: xsd:int
            Divide(intA: xsd:int, intB: xsd:int) -> DivideResult: xsd:int
            Multiply(intA: xsd:int, intB: xsd:int) -> MultiplyResult: xsd:int
            Subtract(intA: xsd:int, intB: xsd:int) -> SubtractResult: xsd:int

If you look at the result of this when running the command on your WSDL, you will see a "Bindings" section. That's from where you get the value, which most likely will be the one for the Soap11Binding (most services will provide just one binding, this one provides two, one for each version of the SOAP protocol).

For the http://my-endpoint.com/acceptance/ in the documentation, you should replace your new SOAP address (i.e. the new place where you want to send the service request now). Judging from your example, this should be http://virtual-soap/something, where something is the original path from the original SOAP address that's inside the WSDL (again, since I don't have access to you WSDL, you should look to see which part of the address you need to replace, and which stays the same).

As for what operation you want to call, that doesn't changes. You call it the same way. The same methods are there because you don't change the service contract, you just change where you want to send the request to.

Upvotes: 1

Related Questions