Python: Sending Raw XML via Suds (jurko) - python

I'm interfacing with a SOAP API, wherein a particular method requires a raw XML string as a parameter. Like so:
import suds.client as sudscl
client = sudscl.Client('http://host/ws.wsdl', location='http://host/ws')
session = 'test123'
options = '<rawXML><Item>Foobar</Item></rawXML>'
result = client.service.ExecuteSearch(session, options)
Pretty straight-forward. However, suds HTML-encodes the XML string I just sent in, like this:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns0="http://host/ws">
<SOAP-ENV:Header/>
<ns1:Body>
<ns0:ExecuteSearch>
<ns0:session>test123</ns0:session>
<ns0:options>
<rawXML&rt;<Item&rt;Foobar</Item&rt;</rawXML&rt;
</ns0:options>
</ns0:ExecuteSearch>
</ns1:Body>
</SOAP-ENV:Envelope>
Boo! Is there any way to get suds to pass in the XML string un-altered?
Thanks!

Ok, got it.
from suds.sax.text import Raw
import suds.client as sudscl
client = sudscl.Client('http://host/ws.wsdl', location='http://host/ws')
session = 'test123'
options = Raw('<rawXML><Item>Foobar</Item></rawXML>')
result = client.service.ExecuteSearch(session, options)

Related

How to use zeep to make SOAP requests in python

here is my xml:
<?xml version="1.0"?>
<soapenv:Envelope>
<soapenv:Header xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<wsse:Security soap:mustUnderstand="1" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-1" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>USERNAME</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">1234</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<root xmlns="http://xmlns.oracle.com/Enterprise/tools/schema/InfoRtRequest.v1">
<EMAIL>david</EMAIL>
</root>
</soapenv:Body>
</soapenv:Envelope>
here is my demo:
wsdl = ''
client = Client(
wsdl,
wsse=UsernameToken('USERNAME', '1234'))
response = client.service.get_method(
EMAIL='david')
it raised VadlidationError:
ValidationError: Missing element OPRID (root.OPRID)
I don't know why, please give me some help, thanks.
zeep is advanced library to handle SOAP communications in python. You should provide wsdl file, so that your issue can be better analyzed.
But by looking into the xml request you have provided, it seems the authentication is been done using headers and data is been sent in body. Similar to the usecase i have recently fixed. Refer my xml request of my use case below.
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Header>
<ns0:myheaders xmlns:ns0="xxxxxx_stackoverflow_mask_xxxxxx">
<ns0:username>xxxxxx_stackoverflow_mask_xxxxxx</ns0:username>
<ns0:password>xxxxxx_stackoverflow_mask_xxxxxx</ns0:password>
</ns0:myheaders>
</soap-env:Header>
<soap-env:Body>
<ns0:Search02c xmlns:ns0="xxxxxx_stackoverflow_mask_xxxxxx">
<ns0:name>
<ns0:title>Mr</ns0:title>
<ns0:forename>Srikanth</ns0:forename>
<ns0:surname>Badveli</ns0:surname>
</ns0:name>
</ns0:Search02c>
</soap-env:Body>
</soap-env:Envelope>
For the above xml, the code is as follows
from zeep import Client
header_credentials = {'username':'xxxxx','password':'xxxxx'}
tac_data = {'name': {'title':'xxxxx','forename':'xxxxx','surname':'xxxxx'}}
client = Client(wsdl=wsdl)
response = client.service.Search02c(tac_data, _soapheaders={'callcreditheaders':header_credentials})
In the above code, "Search02c" is the operation name for the service. Operation name can be found while inspecting the wsdl file. In my usecase "Search02c" accepts 2 arguments which are body and header."tac_data" is the dictionary of the xml body(not header) and "header_credentials" is the dictionary of the credentials. Your use case might accept single argument clubbing header and body. The arguments structure can be found after operation name in the inspected wsdl file.
You can find the operation name and its structure in the end of the output by running this in your command prompt.
python -mzeep wsdl_file_path.wsdl
The operation for my wsdl file is below.
Operations:
Search02c(searchDefinition: tac_data, _soapheaders={'headers': header_credentials}) -> outputResult: ns1:output
Remember, zeep only accepts dictionary as input data and provides dictionary as output. If you like to receive response as xml, use raw_response=True in the client settings.
For more information, please refer zeep documentation

change XML evelope settings in suds

I'm trying to acces a SOAP API. This works while using SOAP-UI as a test environment.
Now I want to implement it in Suds/Python. The actual request suds makes differs in the soap:Envelope element. I have no idea how to set it so it works.
The correct request made by SOAP-UI
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:plur="pluriform:works:datatypes:DagstatenApp-0">
<soap:Header/>
<soap:Body>
...
</soap:Body>
</soap:Envelope>
with the rather minimal python code:
from suds.client import Client
client = Client(url)
client.set_options(soapheaders=(user, passwd)
result = client.service.getWhatEver(arg1, arg2)
I get this:
<SOAP-ENV:Envelope xmlns:ns0="pluriform:works:datatypes:DagstatenApp-0" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<ns1:Body>
...
</ns1:Body>
</SOAP-ENV:Envelope>
Which if I copy-paste it in SOAP-UI. I get this error:
<soapenv12:Text xml:lang="EN">Systeemmelding 6EDB::4844 XML Type error (code 19060)
Systeemmelding 6EDB::4844 XML Type error (code 19060)
Error: Systeemmelding XML Type error (6EDB::4844)
XML Type mismatch. Expected tag [http://www.w3.org/2003/05/soap-envelope]Envelope, not [http://schemas.xmlsoap.org/soap/envelope/]Envelope. Error code App:19060
Error: Systeemmelding XML Type error (6EDB::4844)
element start ("SOAP-ENV:Envelope") rejected at 1, 240
Error code App:19060
Generic XML Import IMPL (6EDB::11267)
Generic XML Import (6EDB::9780)</soapenv12:Text>
I tried various examples like: Overwrite the Soap Envelope in Suds python
but they all add another namespace and do not seem to work. Any suggestions would be welcome.

Modify suds request to target SOAP

I am having a problem with python suds trying to create a proper Suds XML Request:
This is my suds Code (after a few trials):
from suds import *
from suds.client import Client
from suds.transport.http import HttpAuthenticated
import logging
url = 'http://ws/webservices/600/ws.asmx?wsdl'
soap_client = Client(url, location='http://ws/webservices/600/ws.asmx')
soap_client.set_options(port='GatewayWebServiceSoap')
person = soap_client.factory.create('checkIfExists')
person.UserID = 'toni.tester#anywhere.at'
person.SessionID = ''
eventService = soap_client.service.CustomerService(person)
print 'last received:'
print soap_client.last_received()
print '-------------------------------------'
print 'last sent:'
print soap_client.last_sent()
This is what my suds sends:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns0="http://service.example.at/gateway/v6.00" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<ns1:Body>
<ns0:Service>
<ns0:Service>
<ns0:SessionID></ns0:SessionID>
<ns0:UserID>toni.tester#anywhere.at</ns0:UserID>
</ns0:Service>
</ns0:Service>
</ns1:Body>
</SOAP-ENV:Envelope>
And this is what the WebService expects:
<?xml version="1.0" encoding="UTF-8"?>
<GATEWAY xmlns="urn:service-example-at:gateway:v4-00">
<Service>
<checkIfExists>
<SessionID></SessionID>
<UserID>test</UserID>
</checkIfExists>
</Service>
</GATEWAY>
My Questions:
How can I change SOAP-ENV:Envelope -> GATEWAY
How can I remove the namespaces ns1, ns0?
How can I remove the Body
If you really don't care about WSDL and stuff you can easily write request generator yourself since xml request is just a string template. That's what i did for my soapy needs.

Complex Type issue with SOAPpy

I'm trying to access a function defined in my WSDL from HP Server Automation, I'm able to get servers/etc, but not able to pull anything that takes a server reference specifically via SOAPpy.
import SOAPpy
from SOAPpy import WSDL
from SOAPpy import structType
SOAPpy.Config.debug=1
server = WSDL.Proxy('ServerService.wsdl')
serverRef = structType(name='self', typed=0)
serverRef._addItem('id',SOAPpy.longType(19250001))
print server.getCustAttr(serverRef,key='HPSW_ED_win32_diskspace',useScope=False)
The SOAP envelope generated from this code looks like this:
*** Outgoing SOAP ******************************************************
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsd2="http://www.w3.org/2000/10/XMLSchema"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/1999/XMLSchema"
>
<SOAP-ENV:Body>
<ns1:getCustAttr xmlns:ns1="http://server.opsware.com" SOAP-ENC:root="1">
<xsd:self>
<id xsi:type="xsd2:long">19250001</id>
</xsd:self>
<useScope xsi:type="xsd:boolean">False</useScope>
<key xsi:type="xsd:string">HPSW_ED_win32_diskspace</key>
</ns1:getCustAttr>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
And it should look like this ( runs successfully via SOAPUI):
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://server.opsware.com">
<soapenv:Header/>
<soapenv:Body>
<ser:getCustAttr soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<self xsi:type="ser:ServerRef">
<id xsi:type="xsd:long">19250001</id>
</self>
<key xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">HPSW_ED_win32_diskspace</key>
<useScope xsi:type="xsd:boolean">False</useScope>
</ser:getCustAttr>
</soapenv:Body>
</soapenv:Envelope>
I believe the issue is that the xsi:type="ser:ServerRef" is not set, and not really sure how to do that with SOAPpy...
there are two different types of soap styles(RPC literal and Document literal),looks like the mentioned soap server just supports RPC
i saw this problem with soappy and suds. after some tests and benchmarks,i found the problem.
ASP.NET and soappy. you need produce a rpc envelop with python instead document literal envelop style.
just ZSI(The Zolera Soap Infrastructure) works with asp.net and complex types.
this command generates the client proxy for you:
wsdl2py http://terraservice.net/TerraService.asmx?WSDL
and you can import generated modules in your code and use the web methods.

Add Header section to SOAP request using SOAPpy

I need to construct this SOAP query using python SOAPpy module:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<LicenseHeader xmlns="http://schemas.acme.eu/">
<LicenseKey>88888-88888-8888-8888-888888888888</LicenseKey>
</LicenseHeader>
</soap:Header>
<soap:Body>
<GetProductClassification xmlns="http://schemas.acme.eu/">
<GetProductClassificationRequest />
</GetProductClassification>
</soap:Body>
</soap:Envelope>
So I use this code:
from SOAPpy import WSDL
wsdlFile = 'https://example.comt/1.0/service.asmx?wsdl'
server = WSDL.Proxy(wsdlFile)
result = server.GetProductClassification();
The request generated is:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
>
<SOAP-ENV:Body>
<GetProductClassification SOAP-ENC:root="1">
</GetProductClassification>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
When I send request I get Object reference not set to an instance of an object. I think this might be because I don't have a header section with license key in my request.
How do I modify my code to add header section with LicenseHeader parameter?
I am not sure how to do this in SOAPpy but I do know how to do it in suds. SUDS does the same thing as SOAPpy but it is newer and is still supported. I don't think SOAPpy is supported anymore. Below show's the code to connect to a WSDL and send a soap request:
class MySudsClass():
def sudsFunction(self):
url = "http://10.10.10.10/mywsdl.wsdl"
# connects to WSDL file and stores location in variable 'client'
client = Client(url)
#I have no address set in the wsdl to the camera I connect to so I set it's location here
client.options.location = 'http:/10.10.10.11'
# Create 'xml_value' object to pass as an argument using the 'factory' namespace
xml_value = client.factory.create('some_value_in_your_xml_body')
#This send the SOAP request.
client.service.WSDLFunction(xml_value)
Put this in the script before you send the soap request and it will add any headers you want.
# Namespaces to be added to XML sent
wsa_ns = ('wsa', 'http://schemas.xmlsoap.org/ws/2004/08/addressing')
wsdp_ns = ('http://schemas.xmlsoap.orf/ws/2006/02/devprof')
# Field information for extra XML headers
message = 'mymessage'
address_txt = 'myheader_information'
# Soapheaders to be added to the XML code sent
# addPrefix allow's you to addc a extra namespace. If not needed remove it.
message_header = Element('MessageID', ns=wsa_ns).setText(message)
address_header = Element('Address', ns=wsa_ns).setText(address_txt).addPrefix(p='wsdp', u=wsdp_ns)
header_list = [message_header, address_header]
# Soapheaders being added to suds command
client.set_options(soapheaders=header_list)
This will allow you to add in wsa encding that makes the XML understand:
# Attribute to be added to the headers to make sure camera verifies information as correct
mustAttribute = Attribute('SOAP-ENV:mustUnderstand', 'true')
for x in header_list:
x.append(mustAttribute)
If you use something like this you will be able to add any headers, namespaces etc. I have used this and it worked perfectly.
To add the license header in SUDS add:
license_key = Element('LicenseKey', ns=some_namespace).setText('88888-88888-8888-8888-888888888888')
license_header = Element('LicenseHeader', ns=some_namespace).insert(license_key)
license_attribute = Attribute(xmlns, "http://schemas.acme.eu/")
license_header.append(license_attribute)

Categories