Reputation: 36767
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
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
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
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