soulcheck
soulcheck

Reputation: 36767

Accessing response soap header using suds

I have a soap 1.1/1.2 web service I'm trying to access using suds.

Unfortunately the service puts authentication token in response soap header.

Is it possible to access the header somehow?

I know one can set a custom soap header in the request, but that's not what I'm looking for.

Upvotes: 2

Views: 2669

Answers (3)

Wagner Cipriano
Wagner Cipriano

Reputation: 1427

The Towr's class plugin works well, but it has a problem when do you have more then one obj in Soapheader Response. His code get only the first object.

Here is the code to improvement the Towr's class:

class HeaderPlugin(MessagePlugin):
    def __init__(self):
        self.document = None

    def parsed(self, context):
        self.document = context.reply

    def get_headers(self, method):
        Result = {}
        method = method.method
        binding = method.binding.output
        SHeaderElem = binding.headpart_types(method, False)

        envns = ('SOAP-ENV', 'http://schemas.xmlsoap.org/soap/envelope/')
        soapenv = self.document.getChild('Envelope', envns)
        soapheaders = soapenv.getChild('Header', envns)
        SHeaderNodes = soapheaders.children

        for Elem in SHeaderElem:
            for Node in SHeaderNodes:
                if(Node.name == Elem.name):
                    ElemRes = Elem.resolve(nobuiltin=True)
                    NodeRes = binding.unmarshaller().process(Node, ElemRes)
                    Result[Elem.name] = NodeRes
        return Result
    #

To understand better, see the example. If do you receive this Soap Response:

<soap-env:Envelope xmlns:eb="http://www.ebxml.org/namespaces/messageHeader" xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"  xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/12/secext">
    <soap-env:Header>
        <eb:MessageHeader eb:version="1.0" soap-env:mustUnderstand="1">
            <!-- -->
        </eb:MessageHeader>
        <wsse:Security>
            <!-- -->
        </wsse:Security>
    </soap-env:Header>
    <soap-env:Body>
        <!-- -->
    </soap-env:Body>
</soap-env:Envelope>

The function get_headers will return a dict like this:

SoapHeadersResp = {'MessageHeader':MessageHeaderObj, 'Security':SecurityObj}

To use this class just follow the same steps that Towr said, replacing his HeaderPlugin class with this one.

Upvotes: 0

towr
towr

Reputation: 4167

I've been using the (still maintained) suds-jurko branch, and ran into trouble because client.last_received() was removed early after it was forked. So I had to figure out an alternative way to access the headers.

Fortunately, you can use a message plugin to store the parsed document, and then later access the headers via the plugin. For added convenience, instead of working with raw values from the xml document, you can process the headers based on the service-method, to get a correctly typed/structured value.

from suds.plugin import MessagePlugin

class HeaderPlugin(MessagePlugin):
    def __init__(self):
        self.document = None

    def parsed(self, context):
        self.document = context.reply

    def get_headers(self, method):
        method = method.method
        binding = method.binding.output
        rtypes = binding.headpart_types(method, False)

        envns = ('SOAP-ENV', 'http://schemas.xmlsoap.org/soap/envelope/')
        soapenv = self.document.getChild('Envelope', envns)
        soapheaders = soapenv.getChild('Header', envns)
        nodes = soapheaders.children
        if len(nodes):
            resolved = rtypes[0].resolve(nobuiltin=True)
            return binding.unmarshaller().process(nodes[0], resolved)
        return None

usage:

from suds.client import Client

hp = HeaderPlugin()
client = Client(wsdl, plugins=[hp])

response = client.service.LoremIpsum()
headers = hp.get_headers(client.service.LoremIpsum)

example output:

>>> headers
(AuthenticationResponseHeader){
   sessionKey = "a631cd00-c6be-416f-9bd3-dbcd322e0848"
   validUntil = 2030-01-01 01:01:01.123456+01:00
 }
>>> headers.validUntil
datetime.datetime(2030, 1, 1, 1, 1, 1, 123456, tzinfo=<suds.sax.date.FixedOffsetTimezone object at 0x7f7347856be0>)

Upvotes: 4

fkl
fkl

Reputation: 5535

You can do something like

print client.last_received().getChild("soap:Envelope").getChild("soap:Header")
.getChild("ResponseHeader").getChild("resultCode").getText()

The above reads a field resultCode in the soap header. You have to do this for each field. This was a back door left to read headers as much as i know.

For details look at soap headers with suds

Upvotes: 2

Related Questions