Django 1.8 (on Python 3) - Make a SOAP request with pysimplesoap - php

Since one week I'm trying to retrieve some datas from a Dolibarr application including Dolibarr's webservices.
In few words, I'm trying to make a soap request to retrieve user's informations.
At first, I tried to instantiate SoapClient with 'wsdl' and 'trace' parameters, in vain.. SoapClient's object was never been create !
Secondly, I made a made a classical SoapClient's object without 'wsdl', however I used : 'location', 'action', 'namespace', 'soap_ns', 'trace'; It was a success (I think) but It did't work when I called Client's call method.. My dolibarrkey did't match my key on the webservice, but their keys are the same (copy & paste).
For more explanations take a look to dolibarr api (to retrieve datas) with the xlm dataformat.
Link to getUser web service (click on getUser to show parameters):
http://barrdoli.yhapps.com/webservices/server_user.php
Link to xml dataformat (for the SOAP request maybe):
http://barrdoli.yhapps.com/webservices/server_user.php?wsdl
from pysimplesoap.client import SoapClient, SoapFault
import sys
def listThirdParties():
# create a simple consumer
try:
# client = SoapClient(
# "[MyAppDomain]/webservices/server_user.php")
# print(client)
# client = SoapClient(wsdl="[MyAppDomain]/webservices/server_user.php?wsdl", trace=True)
client = SoapClient(
location = "[myAppDomain]/webservices/server_user.php",
action = '[myAppDomain]/webservices/server_user.php?wsdl', # SOAPAction
namespace = "[myAppDomain]/webservices/server_user.php",
soap_ns='soap',
trace = True,
)
print("connected bitch")
except:
print("error connect")
message = dict()
message['use'] = "encoded"
message["namespace"] = "http://www.dolibarr.org/ns/"
message["encodingStyle"] = "http://schemas.xmlsoap.org/soap/encoding/"
message["message"] = "getUserRequest"
parts = dict()
auth = dict()
auth['dolibarrkey'] = '********************************'
auth['sourceapplication'] = 'WebServicesDolibarrUser'
auth['login'] = '********'
auth['password'] = '********'
auth['entity'] = ''
parts["authentication"] = auth
parts["id"] = 1
parts["ref"] = "ref"
parts["ref_ext"] = "ref_ext"
message["parts"] = parts
# call the remote method
response = client.call(method='getUser', kwargs=message)
# extract and convert the returned value
# result = response.getUser
# return int(result)
print(response)
pass
I've "BAD_VALUE_FOR_SECURITY_KEY" into a xlm response, I think it's my request which made with a bad xml dataformat..
shell response :
-------- RESPONSE -------
b'<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://www.dolibarr.org/ns/"><SOAP-ENV:Body><ns1:getUserResponse xmlns:ns1="http://barrdoli.yhapps.com/webservices/server_user.php"><result xsi:type="tns:result"><result_code xsi:type="xsd:string">BAD_VALUE_FOR_SECURITY_KEY</result_code><result_label xsi:type="xsd:string">Value provided into dolibarrkey entry field does not match security key defined in Webservice module setup</result_label></result><user xsi:nil="true" xsi:type="tns:user"/></ns1:getUserResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>'
I really want to know how should I do to make a working soap request with a clean xlm dataformat.
Thanks

Did you try to setup WebService Security (WSSE) with client object? Following examples are taken from https://code.google.com/p/pysimplesoap/wiki/SoapClient
client['wsse:Security'] = {
'wsse:UsernameToken': {
'wsse:Username': 'testwservice',
'wsse:Password': 'testwservicepsw',
}
}
or try to Setup AuthHeaderElement authentication header
client['AuthHeaderElement'] = {'username': 'mariano', 'password': 'clave'}

Related

How to translate PHP SoapClient request example to RoR?

I'd like to use some web service via its API. In documentation I found an example request written with PHP SoapClient. But I am using RoR and I have no PHP experience. Could someone tell me how should I write the same in RoR, or at least translate it to plain HTTP terminology?
<?php
$soap = new SoapClient(“https://secure.przelewy24.pl/external/wsdl/service.php?wsdl”);
$test = $soap->TestAccess(“9999”, “anuniquekeyretrievedfromprzelewy24”);
if ($test)
echo ‘Access granted’;
else
echo ‘Access denied’;
?>
Edit: particularly I'd like to know what should I do with TestAccess method, because there's no methods in plain HTTP. Should I join this name with URL?
To make your life easier, check out a gem that allows you to simplify SOAP access, like savon.
Then the code could be translated as
# create a client for the service
client = Savon.client(wsdl: 'https://secure.przelewy24.pl/external/wsdl/service.php?wsdl')
This will automatically parse the possible methods to client that are offered in the SOAP API (defined in the WSDL). To list the possible operations, type
client.operations
In your case this will list
[:test_access, :trn_refund, :trn_by_session_id, :trn_full_by_session_id, :trn_list_by_date, :trn_list_by_batch, :trn_full_by_batch, :payment_methods, :currency_exchange, :refund_by_id, :trn_register, :trn_internal_register, :check_nip, :company_register, :company_update, :batch_list, :trn_dispatch, :charge_back, :trn_check_funds, :check_merchant_funds, :transfer_merchant_funds, :verify_transaction, :register_transaction, :deny_transaction, :batch_details]
Then to call the method, do the following
response = client.call(:test_access, message: { test_access_in: 9999 })
response = client.call(:test_access, message: {
test_access_in: 9999 }
test_access_out: "anuniquekeyretrievedfromprzelewy24"
)
response.body
=> {:test_access_response=>{:return=>false}}
this gets a result, but I have no idea what it means.
I've included an entire controller method that we use in production as an example but essentially you want to pass in your xml/wsdl request as the body of the HTTP request and then parse the response as xml, or what we used below which is rexml for easier traversing of the returned doc.
def get_chrome_styles
require 'net/http'
require 'net/https'
require 'rexml/document'
require 'rexml/formatters/pretty'
xml = '<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:description7b.services.chrome.com">
<soapenv:Header/>
<soapenv:Body>
<urn:StylesRequest modelId="' + params[:model_id] + '">
<urn:accountInfo number="[redacted]" secret="[redacted]" country="US" language="en" behalfOf="trace"/>
<!--Optional:-->
</urn:StylesRequest>
</soapenv:Body>
</soapenv:Envelope>'
base_url = 'http://services.chromedata.com/Description/7b?wsdl'
uri = URI.parse( base_url )
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new("/Description/7b?wsdl")
request.add_field('Content-Type', 'text/xml; charset=utf-8')
request.body = xml
response = http.request( request )
doc = REXML::Document.new(response.body)
options = []
doc.get_elements('//style').each do |division|
puts division
options << { :id => division.attributes['id'], :val => division.text }
end
respond_to do |format|
format.json { render :json => options.to_json }
end
end

soap query with php and wsdl to get result

I'm having trouble finding a good example of how to do a soap call with a wsdl in php.
I found this example, but it's tied to the google function:
doGoogleSearch
$hits = $soap->doGoogleSearch('your google key',$query,0,10,
true,'',false,'lang_en','','');
I found this example for a wsdl, but I'm not seeing where my query goes:
missingQuery
So basically, this is what I have so far, but there's a lot missing:
$wsdlDB = "htmlString?wsdl";
// xml string for login and query I know works in soapUI with $var
$query = "$query =
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tri="http://blah/dbOurs/">
<soapenv:Header/>
<soapenv:Body>
<tri:sendTransaction>
<loginName>unernm</loginName>
<loginPassword>pw</loginPassword>
...
</soapenv:Body>
</soapenv:Envelope>'
$result = "not sure where this ties in either";
$WSDL = new SOAP_WSDL($wsdlDB);
$soap = $WSDL->getProxy();
$hits = $soap->($query, $result);
//then I will extract $varAnswer from $result with regex probably
This is really unclear. Does anyone have any helpful info on how to submit the query to the DB with the WSDL? I shouldn't have to give the soap call a specific function to do the query with. It's supposed to get that from the wsdl definition.
Why not use the built in SoapClient. It will convert the input to the function into a Soap Message and extract the return message into an object; based on the WSDL.
A simple sample is shown below.
$blzCode = '10010424'; // Code to lookup
$wsdlDB = "http://www.thomas-bayer.com/axis2/services/BLZService?wsdl"; // WSDL URL
$client = new SoapClient($wsdlDB); // Create the client based on the WSDL
$returnValue = $client->GetBank(array('blz' => $blzCode)); // Pass in the Parameters to the call (Based on the WSDL's definition)
$bankDetails = $returnValue->details; // Extract the results
$bankName = $bankDetails->bezeichnung; // Extract some portion of the inner result
echo "Blz Code {$blzCode}'s bank name is {$bankName}" . PHP_EOL; // Do something with the data

OAuth signature_invalid error using PesaPal API with Ruby

I'm having a real nightmare trying to get the PesaPal API to work for me using Ruby...
I appreciate that it's probably not the most commonly used API but if there's anybody online here who has more experience using OAuth, and/or PHP experience who could offer a fresh pair of eyes I'd appreciate it.
So the PesaPal developer site is here: http://developer.pesapal.com
Their API docs don't give away too many clues about how to use OAuth with their site and I don't understand PHP well enough to be sure I've read their PHP sample correctly.
Here's my attempt at implementing this in Ruby:
require 'oauth'
require 'uri'
key = '<my sandbox key>'
sec = '<my sandbox secret>'
API_DOMAIN = 'https://demo.pesapal.com'
# An XML string of param data to include with our request
RAW_XML = %{<?xml version=\"1.0\" encoding=\"utf-8\"?><PesapalDirectOrderInfo xmlns:xsi=\"http://www.w3.org/2001/XMLSchemainstance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" Amount=\"12.34\" Description=\"Bob Test 1\" Type=\"MERCHANT\" Reference=\"808\" FirstName=\"Bo\" LastName=\"Tester\" Email=\"bodacious#bodacious.com\" xmlns=\"http://www.pesapal.com\" />}
# Escape the XML
#post_xml = URI.escape(RAW_XML)
# Create a new OAuth Consumer
#consumer = OAuth::Consumer.new(key, sec, {
site: API_DOMAIN,
scheme: :query_string
})
# The signed request object
#signed_request = #consumer.create_signed_request('get', "#{API_DOMAIN}/API/PostPesapalDirectOrderV4")
# Join the pesapal_request_data and oauth_callback with '&' for valid URL params
#params = {
oauth_callback: URI.escape('http://localhost:3000'),
pesapal_request_data: #post_xml,
}.map { |k,v| "#{k}=#{v}" }.join('&')
# This is the URL we should redirect to
puts redirect_url = "#{#signed_request.path}&#{#params}"
When I try to visit the URL returned by this code, I get: Problem: signature_invalid | Advice: > | back from the API.
Can anyone think of what I'm doing wrong here?
Thanks
Check out the pesapal RubyGem here ... https://rubygems.org/gems/pesapal ... it handles all that stuff for you.
I had the same problem and I solved it by creating a method to manually sign the url. create your own method to get the oauth_nonce like this.
def nonce
Array.new( 5 ) { rand(256) }.pack('C*').unpack('H*').first
end
The signature method looks like this:
def signature
key = percent_encode( #consumer_secret ) + '&' + percent_encode( #token_secret )
digest = OpenSSL::Digest::Digest.new( 'sha1' )
hmac = OpenSSL::HMAC.digest( digest, key, #base_str )
Base64.encode64( hmac ).chomp.gsub( /\n/, '' )
end
This is the #base_str instance variable:
#base_str = [#req_method,
percent_encode( req_url ),
percent_encode( query_string )
].join( '&' )
This is the query_string method:
def query_string
pairs = []
#params.sort.each { | key, val |
pairs.push( "#{ percent_encode( key ) }=#{ percent_encode( val.to_s ) }" )
}
pairs.join '&'
end
You can then use the signature method above to get the oauth_signature param to use in the resulting url
I know the OP was interested in a solution that addresses the Ruby domain, but I feel it may be helpful to note that I was getting a similar problem on PHP and the solution was to ensure I had no white space in the XML post data structure.
WRONG:
<?xml version="1.0" encoding="utf-8"?>
<PesapalDirectOrderInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
Amount="200"
Currency="KES"
Description="Computer Accessory"
Type="MERCHANT"
Reference="dd19f9ede4db6f0a13b7053111f02825"
FirstName="Stack"
LastName="Overflow"
Email="so#stackoverflow.com"
PhoneNumber=""
xmlns="http://www.pesapal.com" >
<lineitems>
<lineitem uniqueid="29"
particulars="Keyboard"
quantity="1"
unitcost="200"
subtotal="200.00" >
</lineitem>
</lineitems>
</PesapalDirectOrderInfo>
CORRECT:
<?xml version="1.0" encoding="utf-8"?><PesapalDirectOrderInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Amount="200" Currency="KES" Description="Computer Accessory" Type="MERCHANT" Reference="dd19f9ede4db6f0a13b7053111f02825" FirstName="Stack" LastName="Overflow" Email="so#stackoverflow.com" PhoneNumber="" xmlns="http://www.pesapal.com" ><lineitems><lineitem uniqueid="29" particulars="Keyboard" quantity="1" unitcost="200" subtotal="200.00" ></lineitem></lineitems></PesapalDirectOrderInfo>

building a php object equal to xml tag

i am developing an app in php it pulls data from Reuters API i am trying to add the request parameters before making SOAP call , i have the xml which must be generated from my request it must look like this :
<HeadlineMLRequest>
<Filter>
<MetaDataConstraint class="companies" xmlns="http://schemas.reuters.com/ns/2006/04/14/rmds/webservices/news/filter">
<Value>MSFT.O</Value>
</MetaDataConstraint>
</Filter>
</HeadlineMLRequest>
when i build my request parameter object i tried this
protected function getRequest() {
$retval->HeadlineMLRequest->MaxCount = 10;
$retval->HeadlineMLRequest->Filter->MetaDataConstraint->class = "companies";
$retval->HeadlineMLRequest->Filter->MetaDataConstraint->Value = "MSFT.O";
return $retval;
}
but when i echo last xml request i find it like this
<ns1:headlinemlrequest>
<ns1:maxcount>
10
</ns1:maxcount>
<ns1:filter>
<ns2:metadataconstraint class="companies">
<ns2:value>
</ns2:value>
</ns2:metadataconstraint>
</ns1:filter>
if you notice Value is empty although i set it with "MSFT.O" , any help please?
Complex requests with php soap are not well documented and most examples show only basic techniques.
Try the following:
$metaData = '<MetaDataConstraint class="companies" xmlns="http://schemas.reuters.com/ns/2006/04/14/rmds/webservices/news/filter">
<Value>MSFT.O</Value>
</MetaDataConstraint>';
$xmlvar = new SoapVar($metaData, XSD_ANYXML);
$retval->HeadlineMLRequest->Filter->MetaDataConstraint = $xmlVar;

Updating XML with PHP and returning to .NET Web Service dataset with SOAP

I am using PHP5 and Codeigniter to connect to a .NET web service through SOAP requests. I'm having trouble making an update to that dataset. This is my first experience working with Codeigniter (although doesn't factor here much), SOAP, PHP SimpleXML class, and .NET web services in general. For example, this is to update a user profile. I don't have any problems getting responses but I'm unsure how to update this based on the user's edits to the profile.
My string from the dumping request is this (Note: I'm concerned with the 0, which is the start of the dataset. The 1111 is username and the next 1111 is a password)
11111111 0RandyFloydGM1955-11-05T00:00:00-04:00317787129131789770001910 E. Markwood AvenueIndianapolisIN46227falsefalse
This gives me a 400 Bad Request error. It seems obvious that is due to the space between the 0 and the last 1. By doing htmlspecialchars() I see that it looks like it is the xml declaration isn't needed.
<?xml version="1.0"?> <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml- msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1"><dsEmployee xmlns="http://SHSSrv/dsEmployee.xsd"><Employee diffgr:id="Employee1" msdata:rowOrder="0"><EmplId>0</EmplId><FirstName>Randy</FirstName><LastName>Floyd</LastName><MI>G</MI><Sex>M</Sex><DOB>1955-11-05T00:00:00-04:00</DOB><HomePhoneArea>317</HomePhoneArea><HomePhone>7871291</HomePhone><WorkPhoneArea>317</WorkPhoneArea><WorkPhone>8977000</WorkPhone><Address1>1920 E. Markwood Avenue</Address1><Address2/><City>Indianapolis</City><St>IN</St><ZIP>46227</ZIP><ReceiveNewsLetter>false</ReceiveNewsLetter><PagerArea/><PagerNo/><EmailAddress>randy#test.com</EmailAddress><SpanishContact>false</SpanishContact></Employee></dsEmployee></diffgr:diffgram>
Taking the original response and just sending it back as update works like this.
111111110RandyFloydGM1955-11-05T00:00:00-04:00317787129131789770001910 E. Markwood AvenueIndianapolisIN46227falsefalse
And with htmlspecialchars() looks like this (No XML declaration):
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml- msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1"><dsEmployee xmlns="http://SHSSrv/dsEmployee.xsd"><Employee diffgr:id="Employee1" msdata:rowOrder="0"><EmplId>0</EmplId><FirstName>Randy</FirstName><LastName>Floyd</LastName><MI>G</MI><Sex>M</Sex><DOB>1955-11-05T00:00:00-04:00</DOB><HomePhoneArea>317</HomePhoneArea><HomePhone>7871291</HomePhone><WorkPhoneArea>317</WorkPhoneArea><WorkPhone>8977000</WorkPhone><Address1>1920 E. Markwood Avenue</Address1><Address2/><City>Indianapolis</City><St>IN</St><ZIP>46227</ZIP><ReceiveNewsLetter>false</ReceiveNewsLetter><PagerArea/><PagerNo/><EmailAddress>randy#test.com</EmailAddress><SpanishContact>false</SpanishContact></Employee></dsEmployee></diffgr:diffgram>
Here is the code:
function employee_update_request()
{
ini_set( 'soap.wsdl_cache_ttl' , 0 );
//Get XML from the Employee Profile Request
$response = $this->employee_profile_request();
//Turn the string into an object to manipulate
$dataset = simplexml_load_string($response->any);
//Manipulate some data from the update form
$dataset->dsEmployee->Employee->EmailAddress = "randy#test.com";
$dataset->dsEmployee->Employee->Address1 = "1920 E. Markwood Avenue";
$any = $dataset->saveXML();
//Add back the string to the original response object returned from web service
$response->any = $any;
//Get username and password for the params
$username = $this->session->userdata('username');
$password = $this->session->userdata('password');
$params = array('sUserId' => $username, 'sPassword' => $password, 'dsEmployee' => $response);
//SOAP Options
$options = array(
'soap_version'=>SOAP_1_1,
'exceptions'=> 0,
'trace'=> 1,
'uri' => "http://www.w3.org/2003/05/soap-envelope"
);
//New soap client with options
$client = new SoapClient('http://localhost/SHSSRV/SHSSrv.asmx?WSDL', $options);
//Request the employee profile fromt the webservice, passing in credentials
$update_request = $client->EmployeeUpdateRequest($params);
$update_response = $update_request->EmployeeUpdateRequestResult;
return $update_response;
}
I really need help, I need to figure out how best to make updates to this data. Am I able to get the declaration stripped out somehow, or should I request that the .NET web service be changed in some way? I don't have access directly to that but I can talk to the developer if there is a better way all together.
Thanks!
I've solved this by doing this. I'd love to know if there is a better way though.
$no_xml_doctype = str_replace('<?xml version="1.0"?>' , '' , $any);
$trimmed = trim($no_xml_doctype);
$response->any = $trimmed;
//Get username and password for the params
$username = rtrim($this->session->userdata('username'));
$password = rtrim($this->session->userdata('password'));
$params = array('sUserId' => $username, 'sPassword' => $password, 'dsEmployee' => $response);

Categories