Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I set SOAP headers in pysimplesoap?

I received some example php code for calling a SOAP service which I now need to convert to Python. In the php code they set the headers as follows:

$auth = array();
$auth['token'] = 'xxx';
if ($auth) {
    // add auth header
    $this->clients[$module]->__setSoapHeaders(
        new SoapHeader(
            $namespace, 
            'auth', 
            $auth
        )
    );
}

So the auth header should look like this: ['token' => 'xxx']. I then loaded the wsdl into SoapUI, which gave me the following example xml:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sub="https://example.com/path/to/sub">
   <soapenv:Header>
      <sub:auth>
         <token>?</token>
         <!--Optional:-->
         <user_id>?</user_id>
         <!--Optional:-->
         <user_token>?</user_token>
      </sub:auth>
   </soapenv:Header>
   <soapenv:Body>
      <sub:customer_logos_pull>
         <!--Optional:-->
         <language>?</language>
         <!--Optional:-->
         <limit>?</limit>
         <!--Optional:-->
         <options_utc>?</options_utc>
      </sub:customer_logos_pull>
   </soapenv:Body>
</soapenv:Envelope>

In pysimplesoap I now try something like this:

from pysimplesoap.client import SoapClient

WSDL = 'https://example.com/some/path/sub.wsdl'
TOKEN = 'xxx'

client = SoapClient(wsdl=WSDL, trace=True)
client['auth'] = {'token': TOKEN}
print client.customer_logos_pull({})

but I get an error saying ExpatError: not well-formed (invalid token): line 1, column 0, which makes sense, because in the logged xml I see that the header is empty:

<soap:Header/>

I tried varying the code by including the sub: before auth like this: client['sub:auth'] = {'token': TOKEN}, but I get the same error.

Does anybody know what I'm doing wrong here? All tips are welcome!

like image 291
kramer65 Avatar asked Jun 01 '15 19:06

kramer65


People also ask

How do I add a SOAP header in WSDL?

You can add soap header information to method calls by decorating the methods in the proxy class generated from the wsdl with the SoapHeader attribute. For example wsdl.exe will generate client proxy class Reference. cs for the web service reference when you "Add Web Reference".

What is the requirement of SOAP header?

There is only one SOAP header section in a SOAP request. If the SOAP header element is present, it must be the first child element of the envelope element. SOAP headers can be input, output, or input and output, and you do not need to specify them in the WSDL file.

How do you make SOAP headers?

HeaderList hl = (HeaderList) messageContext. get(JAXWSProperties. INBOUND_HEADER_LIST_PROPERTY); which gives you access to all SOAP headers.


1 Answers

So I think we can solve this by using the suds library.

Here is a very basic example of how to send a SOAP request that includes headers:

Example:

from suds.sax.element import Element 

client = client(url) 
ssnns = ('ssn', 'http://namespaces/sessionid') 
ssn = Element('SessionID', ns=ssnns).setText('123') 
client.set_options(soapheaders=ssn)  
result = client.service.addPerson(person)

This is an example of how you'd send the following header:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP ENC="http://www.w3.org/2003/05/soap-encoding">
    <ssn:SessionID SOAP-ENV:mustUnderstand="true">123</ssn:SessionID>
 </SOAP-ENV:Header>

NB: I haven't actually tried this per se as I don't have access to any readily available SOAP/XML services I can test against!

So in your particular example you would do something like this:

>>> from suds.sax.element import Element
>>> subns = ("sub", "http://namespaces/sub")
>>> sub = Element("auth", ns=subns)
>>> token = Element("token").setText("?")
>>> user_id = Element("user_id").setText("?")
>>> user_token = Element("user_token").setText("?")
>>> sub.append(token)
Element (prefix=sub, name=auth)
>>> sub.append(user_id)
Element (prefix=sub, name=auth)
>>> sub.append(user_token)
Element (prefix=sub, name=auth)
>>> print(sub.str())
<sub:auth xmlns:sub="http://namespaces/sub">
   <token>?</token>
   <user_id>?</user_id>
   <user_token>?</user_token>
</sub:auth>

Then call set_options() on your client object:

client.set_options(soapheaders=sub)

And you can easily install suds using pip by running:

$ pip install suds
like image 118
James Mills Avatar answered Oct 23 '22 10:10

James Mills