Savon 2.1.0 basic auth not functioning - ruby

I am trying to access a SOAP service which has the following charateristics:
1. WSDL is available without authentication
2. The service is accessible over https with basic_auth
3. According to the SOAP service, the "Authorization" header needs to be included in every request
Here is my code for construction the soap client:
#wsdl="https://example.com/table.do&WSDL"
#proxy="http://internal.proxy.com:8080"
#basic_auth=["user","pass"]
#headers={"Authorization" => "Basic"}
client = Savon.client do |globals|
globals.wsdl #wsdl
globals.proxy #proxy
globals.basic_auth #basic_auth
globals.headers #headers
end
Here is the client.globals.inspect:
#<Savon::GlobalOptions:0x0000000382c7a8 #options={:encoding=>"UTF-8",
:soap_version=>1, :namespaces=>{}, :logger=>#<Logger:0x0000000382c730 #progname=nil,
#level=0, #default_formatter=#<Logger::Formatter:0x0000000382c708
#datetime_format=nil>,
#formatter=nil, #logdev=#<Logger::LogDevice:0x0000000382c6b8 #shift_size=nil,
#shift_age=nil, #filename=nil, #dev=#<IO:<STDOUT>>,
#mutex=#<Logger::LogDevice::LogDeviceMutex:0x0000000382c690 #mon_owner=nil,
#mon_count=0, #mon_mutex=#<Mutex:0x0000000382c640>>>>, :log=>true, :filters=>[],
:pretty_print_xml=>false, :raise_errors=>true, :strip_namespaces=>true,
:convert_response_tags_to=>#<Proc:0x0000000382c5c8#/usr/local/rvm/gems/ruby-2.0.0-p0/gems/savon-2.1.0/lib/savon/options.rb:48 (lambda)>,
:wsdl=>"https://example.com/table.do&WSDL",
:proxy=>"http://internal.proxy.com:8080",
:basic_auth=>["user", "pass"],
:headers=>{"Authorization"=>"Basic"}}>
when i call:
client.call(:get, message: { sys_id: "67d2f77ed9377840c53fc6da9c094635" })
The service is returning:
DEBUG -- : HTTPI GET request to xseaddev.service-now.com (net_http)
INFO -- : SOAP request: https://xseaddev.service-now.com/change_task_list.do?displayvalue=all&SOAP
INFO -- : SOAPAction: "http://www.service-now.com/change_task/get", Content-Type: text/xml;charset=UTF-8, Content-Length: 408
DEBUG -- : <?xml version="1.0" encoding="UTF-8"?><env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://www.service-now.com" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ins0="http://www.service-now.com/change_task"><env:Body><ins0:get><tns:sysId>67d2f77ed9377840c53fc6da9c094635</tns:sysId></ins0:get></env:Body></env:Envelope>
DEBUG -- : HTTPI POST request to xseaddev.service-now.com (net_http)
INFO -- : SOAP response (status 401)
Am i constructing the client incorrectly? I don't see any authentication headers being sent on either the GET or PoST requests.
Do i need to add/remove anything to get this working? Your help would be appreciated.

I imagine you should be able to do the following:
client = Savon.client(endpoint: ENDPOINT, namespace: NAMESPACE, basic_auth: ["user", "password"])
(Or the same in block form).
Check this page under the "Authentication" heading: http://savonrb.com/version2/globals.html
(I am doing the same, but with a WSDL).

Related

invalid SOAP request needs experienced eye

TLDR: the solution can be found here
I'm using savon to make requests against a SOAP service. I know... Gross.
Regardless, I'm having trouble making Savon behave. The SOAP provider has this validator, which takes the following inputs:
Web Service: ProductData
Version: 1.0.0
Operation: getProductSellable
Endpoint: https://psproductdata100-stg.pcna.online
When I use the validator, I enter this xml:
<GetProductSellableRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.promostandards.org/WSDL/ProductDataService/1.0.0/">
<wsVersion xmlns="http://www.promostandards.org/WSDL/ProductDataService/1.0.0/SharedObjects/">1.0.0</wsVersion>
</GetProductSellableRequest>
And I get this response body
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header />
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<GetProductSellableResponse xmlns="http://www.promostandards.org/WSDL/ProductDataService/1.0.0/">
<ErrorMessage xmlns="http://www.promostandards.org/WSDL/ProductDataService/1.0.0/SharedObjects/">
<code>110</code>
<description>Authentication Credentials Required</description>
</ErrorMessage>
</GetProductSellableResponse>
</s:Body>
</s:Envelope>
That response is valid because I did not provide my un/pw. If I do provide credentials, I get a full response. Below is a screenshot of that happening in my browser.
However, when I use Savon to make the same request
#!/usr/bin/env ruby
require 'savon'
require 'awesome_print'
require 'byebug'
require 'pry'
endpoint = 'https://psproductdata100-stg.pcna.online'
path = 'psProductData.svc?singleWsdl'
wsdl = "#{endpoint}/#{path}"
args = {
wsdl: wsdl,
log: true,
log_level: :debug,
pretty_print_xml: true,
element_form_default: :qualified
}
client = Savon.client(args) do
convert_request_keys_to :lower_camelcase
end
message = { ws_version: '1.0.0' }
response = client.call(:get_product_sellable) do
message(message)
end
ap response
The response does not come back as expected. The XML looks close to what was sent by the validator, but not exact.
Heres the request
D, [2018-04-26T18:01:00.471662 #89854] DEBUG -- : HTTPI /peer GET request to psproductdata100-stg.pcna.online (net_http)
I, [2018-04-26T18:01:00.979809 #89854] INFO -- : SOAP request: https://psproductdata100-stg.pcna.online/psProductData.svc
I, [2018-04-26T18:01:00.979886 #89854] INFO -- : SOAPAction: "getProductSellable", Content-Type: text/xml;charset=UTF-8, Content-Length: 501
D, [2018-04-26T18:01:00.980107 #89854] DEBUG -- : <?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://www.promostandards.org/WSDL/ProductDataService/1.0.0/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ins0="http://www.promostandards.org/WSDL/ProductDataService/1.0.0/SharedObjects/">
<env:Body>
<tns:GetProductSellableRequest>
<tns:wsVersion>1.0.0</tns:wsVersion>
</tns:GetProductSellableRequest>
</env:Body>
</env:Envelope>
And the response
D, [2018-04-26T18:01:00.980224 #89854] DEBUG -- : HTTPI /peer POST request to psproductdata100-stg.pcna.online (net_http)
I, [2018-04-26T18:01:01.650449 #89854] INFO -- : SOAP response (status 200)
D, [2018-04-26T18:01:01.650731 #89854] DEBUG -- : <?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<GetProductSellableResponse xmlns="http://www.promostandards.org/WSDL/ProductDataService/1.0.0/">
<ErrorMessage xmlns="http://www.promostandards.org/WSDL/ProductDataService/1.0.0/SharedObjects/">
<code>110</code>
<description>Version mismatch.</description>
</ErrorMessage>
</GetProductSellableResponse>
</s:Body>
</s:Envelope>
and the output from Savon
{
:get_product_sellable_response => {
:error_message => {
:code => "110",
:description => "Version mismatch.",
:#xmlns => "http://www.promostandards.org/WSDL/ProductDataService/1.0.0/SharedObjects/"
},
:#xmlns => "http://www.promostandards.org/WSDL/ProductDataService/1.0.0/"
},
:"#xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
:"#xmlns:xsd" => "http://www.w3.org/2001/XMLSchema"
}
Thanks to the other answers on this thread, I found this post. I read up on how namespaces work, as well as linked XSD files. By combining my new knowledge with that post, I was a able to build out something like this:
require 'savon'
require 'awesome_print'
require 'byebug'
require 'pry'
endpoint = 'https://psproductdata100-stg.pcna.online'
path = 'psProductData.svc?singleWsdl'
wsdl = "#{endpoint}/#{path}"
args = {
wsdl: wsdl,
log: false,
log_level: :debug,
pretty_print_xml: true,
element_form_default: :qualified
}
client = Savon.client(args) do
convert_request_keys_to :lower_camelcase
namespaces 'xmlns:shar' => 'http://www.promostandards.org/WSDL/ProductDataService/1.0.0/SharedObjects/'
end
message = {
'shar:wsVersion' => '1.0.0',
'shar:id' => 'REDACTED',
'shar:password' => 'REDACTED'
}
response = client.call(:get_product_sellable) do
message(message)
end
ap response.body[:get_product_sellable_response][:product_sellable_array][:product_sellable][0..2]
Now i'm more fun to talk to at dinner parties.
Similar problem with namespaces ruby savon and wsdl namespacing. I believe you have the same problem.
Additional Note: Try to use SOAP UI to debug, the generated XML from the WSDL and see the difference. Also change the XML to the XML generated from the code and validate the XML in SOAP UI. It will show the errors if any in SOAP UI, will make debugging faster and errors more understandable.
I believe your issue is a namespace problem. The wsVersion is within the shared object namespace "ins0". It is not in the "tns" namespace. Try changing your request to look like the following:
<env:Body>
<tns:GetProductSellableRequest>
<ins0:wsVersion>1.0.0</ins0:wsVersion>
</tns:GetProductSellableRequest>
</env:Body>

SOAP fault when integrating with Swedish BankId

I'm trying to integrate with BankId (it's a common authentication and signing service in Sweden). I'm using Savon Ruby SOAP client and trying to make requests to the BankId's testing API following their guidelines. When making a call to an 'authenticate' operation, I am getting the following error:
The given SOAPAction Authenticate does not match an operation
The SOAP request looks as such:
SOAP request: https://appapi.test.bankid.com/rp/v4
SOAPAction: "Authenticate", Content-Type: text/xml;charset=UTF-8, Content-Length: 384
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rp="http://bankid.com/RpService/v4.0.0/types/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<rp:AuthenticateRequest>
<personalNumber>12345678</personalNumber>
</rp:AuthenticateRequest>
</env:Body>
</env:Envelope>
I'm creating a session using the following details:
wsdl: 'https://appapi.test.bankid.com/rp/v4?wsdl'
namespace: 'http://bankid.com/RpService/v4.0.0/types/'
endpoint: 'https://appapi.test.bankid.com/rp/v4'
Here's the code:
> client = Savon.client(wsdl: 'https://appapi.test.bankid.com/rp/v4?wsdl', namespace: 'http://bankid.com/RpService/v4.0.0/types/', endpoint: 'https://appapi.test.bankid.com/rp/v4', ssl_cert_file: "XXXX/cert.pem", ssl_cert_key_file: "XXX/key.pem", ssl_cert_key_password: "qwerty123", pretty_print_xml: true, log_level: :debug, log: true)
> client.call(:authenticate, message: {personalNumber: '12345678'})
I should mention that I'm am not highly familiar with using SOAP API.
I just needed to explicitly say that soap_action header was not required.
> client = Savon.client(wsdl: 'https://appapi.test.bankid.com/rp/v4?wsdl', namespace: 'http://bankid.com/RpService/v4.0.0/types/', endpoint: 'https://appapi.test.bankid.com/rp/v4', ssl_cert_file: "XXXX/cert.pem", ssl_cert_key_file: "XXX/key.pem", ssl_cert_key_password: "qwerty123", pretty_print_xml: true, log_level: :debug, log: true)
> client.call(:authenticate, message: {personalNumber: '12345678'}, soap_action: '')

consume custom binding oracle WFC web service with ruby / savon

I am trying to consume a wfc web service with a non basicthttp binding with ruby and savon.
The provider of the WS implemented the oracle/wss11_username_token_with_message_protection_service_policy (which is described here
http://www.oracle.com/technetwork/articles/soa/oracle-msft-interoperate-183511.html)
If I understand correctly this policy is expecting some sort of encryption (according to this http://blog.raastech.com/2012/08/owsm-security-errors.html) due to the non basic http binding
The WS described actually goes over ssl which may be the root of all evil due to me implementing it poorly.
Is even possible to consume a WFC WS with non basic http binding with savon?
My background is ruby and rails, yet I am new to WS (and savon) and ssl usage.
Now the provider of the WS does not give much of support. Actually their outing is that they only provide support for implementations in java or .net (is that even possible given that it’s a WS and thus platform independent?).
In an attempt to run the fairly simple code which is the following
require 'savon'
client = Savon.client do
wsdl "https://apps.ika.gr/hospitalisationWSS_TEST-hospitalisationWSS_TEST-context-root/MainWSClassPort?WSDL"
wsse_auth "ΥΥΥΥ", "ΧΧΧΧ" # ALTERED
wsse_timestamp true
pretty_print_xml true
log_level :debug
ssl_verify_mode :none
ssl_cert_file "files/ika.cer" # provided by WS provider
end
save_admission_hl7_msg = "MSH|^~\&|||||201310111112||ADT^A13^ADT_A13|2013000012113|P|2.6|||||||||66645678912345678945|^^^^^^^^^10000\nEVN|A13|201310101122|||nosiliapap\nPID\nPV1||I|||||||||||||||||2013000012111|||||||||||||||||||||||||||||||2013000012113\n"
response = client.call(:save_admission_hl7,
:attributes => { :xmlns => "http://bean.intracom.com/" },
:message => { :arg0 => { :#xmlns=>'', :content! =>{ :hl7ADT => save_admission_hl7_msg } } } )
end
puts response.body
Ι get the following output
D, [2013-12-04T08:21:20.445549 #3088] DEBUG -- : HTTPI GET request to apps.ika.gr (httpclient)
I, [2013-12-04T08:21:22.074643 #3088] INFO -- : SOAP request: https://apps.ika.gr/hospitalisationWSS_TEST-hospitalisationWSS_TEST-context-root/MainWSClassPort
I, [2013-12-04T08:21:22.074643 #3088] INFO -- : SOAPAction: "saveAdmissionHl7", Content-Type: text/xml;charset=UTF-8, Content-Length: 1363
D, [2013-12-04T08:21:22.075643 #3088] DEBUG -- : <?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://bean.intracom.com/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="UsernameToken-1">
<wsse:Username>YYYY</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">XXXX</wsse:Password>
</wsse:UsernameToken>
<wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-2">
<wsu:Created>2013-12-04T06:21:22Z</wsu:Created>
<wsu:Expires>2013-12-04T06:22:22Z</wsu:Expires>
</wsu:Timestamp>
</wsse:Security>
</env:Header>
<env:Body>
<tns:saveAdmissionHl7 xmlns="http://bean.intracom.com/">
<arg0 xmlns="">
<hl7ADT>MSH|^~&|||||201310111112||ADT^A13^ADT_A13|2013000012113|P|2.6|||||||||66645678912345678945|^^^^^^^^^10000
EVN|A13|201310101122|||nosiliapap
PID
PV1||I|||||||||||||||||2013000012111|||||||||||||||||||||||||||||||2013000012113
</hl7ADT>
</arg0>
</tns:saveAdmissionHl7>
</env:Body>
</env:Envelope>
D, [2013-12-04T08:21:22.076643 #3088] DEBUG -- : HTTPI POST request to apps.ika.gr (httpclient)
I, [2013-12-04T08:21:22.472665 #3088] INFO -- : SOAP response (status 500)
D, [2013-12-04T08:21:22.473665 #3088] DEBUG -- : <?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:Fault xmlns:ns2="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns3="http://www.w3.org/2003/05/soap-envelope">
<faultcode xmlns:ns0="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">ns0:FailedCheck</faultcode>
<faultstring>FailedCheck : failure in security check</faultstring>
</ns2:Fault>
</S:Body>
</S:Envelope>
f:/rubystack/ruby/lib/ruby/gems/1.9.1/gems/savon-2.3.0/lib/savon/response.rb:85:in `raise_soap_and_http_errors!': (ns0:FailedCheck) FailedCheck : failure in security check (Savon::SOAPFault)
from f:/rubystack/ruby/lib/ruby/gems/1.9.1/gems/savon-2.3.0/lib/savon/response.rb:14:in `initialize'
from f:/rubystack/ruby/lib/ruby/gems/1.9.1/gems/savon-2.3.0/lib/savon/operation.rb:64:in `new'
from f:/rubystack/ruby/lib/ruby/gems/1.9.1/gems/savon-2.3.0/lib/savon/operation.rb:64:in `create_response'
from f:/rubystack/ruby/lib/ruby/gems/1.9.1/gems/savon-2.3.0/lib/savon/operation.rb:55:in `call'
from f:/rubystack/ruby/lib/ruby/gems/1.9.1/gems/savon-2.3.0/lib/savon/client.rb:36:in `call'
from eopyy.rb:82:in `<main>'
Now given my poor knowledge on WS's and SSL usage I cant figure out the error.
Is it the SSL? Should I use ssl_ca_cert_file instead of ssl_cert_file ? (obviously I tried that already). Do I need to use a key file also?
The provider actually provides a .jks file (next to the above "ika.cer" certificate) but also mentions that it should be used only within a java implementation (an not a .net). I already unpacked the jks file and attempted to use its contained certificates and files, unsuccesfully.
Any help, clues, tips, greatly appreciated.

Filtering with Quickbooks Online V2 returns 401 ErrorCode=003200, Empty body posts work perfectly

We're attempting to integrate with the QuickBooks Online V2 api using Ruby 1.9.3 (not RoR).
Using the API Explorer and the Employee endpoint documentation we were able to get a simple list of test employees by using the Google Signet OAuth Gem.
require 'signet'
require 'signet/oauth_1/client'
#intialize oauth1 client
#client = Signet::OAuth1::Client.new(
:temporary_credential_uri => "https://oauth.intuit.com/oauth/v1/get_request_token",
:authorization_uri => "https://appcenter.intuit.com/Connect/Begin",
:token_credential_uri => "https://oauth.intuit.com/oauth/v1/get_access_token",
:client_credential_key => 'qyprdPEfJqU7eOze0Fby9iYhrUS5DQ',
:client_credential_secret => 'fuXsasJo4TrTEd3Yhv4TeMUizmtguh0JioIB5r2I',
:callback => "http://localhost:3000/callback/general"
)
#client.token_credential_key = 'qyprdJUtDSk7owxVfZlq7JeWO1mtpHBkSMD5GhB02PwIC6N0'
#client.token_credential_secret = 'Rq2ekgQWWL9frZAKpcgWef291mR0J5HBE354u5F3'
#setup request
original_request = [
'POST',
'https://qbo.sbfinance.intuit.com/resource/employees/v2/791630875',
# we also tried this url 'https://qbo.intuit.com/qbo28/resource/employees/v2/791630875',
[
['Content-Type', 'application/x-www-form-urlencoded'],
],
[]
]
#execute request
response = #client.fetch_protected_resource(:request => original_request)
puts response.body
As you can see the request is pretty straight-forward.
However once we create a request with a Filter in the body, we get an HTML page with the following error: HTTP Status 401 - message=Exception authenticating OAuth; errorCode=003200; statusCode=401
#setup request
original_request = [
'POST',
'https://qbo.intuit.com/qbo28/resource/employees/v2/791630875',
#'https://qbo.sbfinance.intuit.com/resource/employees/v2/791630875',
[
['Content-Type', 'application/x-www-form-urlencoded'],
],
["Filter=Name :EQUALS: Doe"]
]
We're using the Google OAuth gem, and I've verified the signature generation to be correct using these tools: LinkedIn Oauth Test Console and Beginners guide to OAuth signing requests. They both verify that the signature that Signet is generating is correct for the body I provide.
I've looked at a few SO Questions:
QuickBooks Online querying with filter returns 401 everytime
Unable to create(POST) objects (Account, customer...) on QB Windows using IDS and Sync Manager
But nothing has worked. Any help would be appreciated, we're willing to use a third party gem such as quickeebooks but we would rather not. I assume I'm just missing something simple here.
Please provide me with the following items so I can verify a working answer:
Your request parameters, including uri, header, body and exact client and access tokens (developer app tokens only please, I'll need to verify that I can generate the exact same request, including signature)
You basestring used for generating the HMAC-SHA1 signature. it will look something like
POST&https%3A%2F%2Fqbo.intuit.com%2Fqbo28%2Fresource%2Femployees%2Fv2%2F7916308‌​75&Filter%3DName%2520%253AEQUALS%253A%2520David%2520Test%26oauth_consumer_key%3Dq‌​yprdPEfJqU7eOze0Fby9iYhrUS5DQ%26oauth_nonce%3D-1787433535548338293%26oauth_signat‌​ure_method%3DHMAC-SHA1%26oauth_timestamp%3D1380089100%26oauth_token%3DqyprdJUtDSk‌​7owxVfZlq7JeWO1mtpHBkSMD5GhB02PwIC6N0%26oauth_version%3D1.0
Your response, including header and body data
I had tried to use filter query with employee endpoint. It works fine.
EDIT - Sharing endpoint, filter and resultset related to Employee API Endpoint
https://qbo.intuit.com/qbo28/resource/employees/v2/791926875
Filter= Name :EQUALS: Manas Mukherjee
header - "Authorization: OAuth oauth_token="2eRrd7LhEtHrM1CrqWvy1kmSgeukEgFxW99E1xwhSsLCp1JB", oauth_consumer_key="qyprdXsaKh0a132eNs7NTJLufjfrzm", oauth_version="1.0", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1380084612", oauth_nonce="1556081845430558974", oauth_signature="IMjh%2FTx%2F7GMFDE6WQqZK8b6apjI%3D"[\r][\n]"
Content-Type: application/x-www-form-urlencoded
Data Set
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<qbo:SearchResults xmlns="http://www.intuit.com/sb/cdm/v2" xmlns:qbp="http://www.intuit.com/sb/cdm/qbopayroll/v1" xmlns:qbo="http://www.intuit.com/sb/cdm/qbo">
<qbo:CdmCollections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Employees">
<Employee>
<Id idDomain="QBO">20</Id>
<SyncToken>0</SyncToken>
<MetaData>
<CreateTime>2013-09-24T21:37:22-07:00</CreateTime>
<LastUpdatedTime>2013-09-24T21:37:22-07:00</LastUpdatedTime>
</MetaData>
<Name>Manas Mukherjee</Name>
<Address>
<Line1>ABC Str</Line1>
<City>London</City>
<PostalCode>4353543</PostalCode>
<GeoCode>LAT=51.5148382,LNG=-0.1264144</GeoCode>
</Address>
<GivenName>Manas</GivenName>
<MiddleName>Kr</MiddleName>
<FamilyName>Mukherjee</FamilyName>
<ShowAs>Manas Kr Mukherjee</ShowAs>
<BillableTime>false</BillableTime>
</Employee>
</qbo:CdmCollections>
<qbo:Count>1</qbo:Count>
<qbo:CurrentPage>1</qbo:CurrentPage>
</qbo:SearchResults>
OAuth header using your tokens
"Authorization: OAuth oauth_token="qyprdJUtDSk7owxVfZlq7JeWO1mtpHBkSMD5GhB02PwIC6N0", oauth_consumer_key="qyprdPEfJqU7eOze0Fby9iYhrUS5DQ", oauth_version="1.0", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1380089100", oauth_nonce="-1787433535548338293", oauth_signature="Vj67xMVhSKGjVSmGyOxt7SVv0i8%3D"[\r][\n]"
Endpoint - https://qbo.intuit.com/qbo28/resource/employees/v2/791630875
Post data to end point: Filter= Name :EQUALS: David Test
Content-Type: application/x-www-form-urlencoded
It works fine
Thanks
See this sample fiddler request with Filter for items in QBO. I cannot paste the fiddler log here. You can do it for similarly for Employee. The filters should go into the body and encode your header:
Request-
POST https://qbo.intuit.com/qbo1/resource/items/v2/723488155
HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Authorization: OAuth oauth_token="lvprdgF9q4mSQx5A6lKNm3NISXvwIpF16z",oauth_nonce="3740352e-20a4-4d45-af4f-2b783ee20e60",oauth_consumer_key="qyprd7I5WvVnPoiBh1ejZn",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1377106651",oauth_version="1.0",oauth_signature="1OAJXk5uH0sEpYpdhh%2BDMzjQFEs%3D"
Host: qbo.intuit.com
Content-Length: 28
Expect: 100-continue
PageNum=1&ResultsPerPage=100
Response Header-
HTTP/1.1 200 OK
Date: Wed, 21 Aug 2013 17:37:31 GMT
Server: Apache
Set-Cookie: qboeuid=10.129.32.5.1377106651774076; path=/; expires=Thu, 21-Aug-14 17:37:31 GMT; domain=.intuit.com
Set-Cookie: JSESSIONID=82DE11473B5246497B9FDCD8A6DA4C45.c1-pprdqboas30j; Path=/; Secure; HttpOnly
Vary: Accept-Encoding
Content-Type: application/xml;charset=UTF-8
Content-Length: 32525

Can't get Savon to form the right XML

I've used SOAP before but many, many years ago and try to stay clear if I can help it.
Short story...
Using "Soap Client" OS X app I can get the response I wish.
If I use client.request :foo_web_serivce, :language_count, :body => { :foo_app_id => "...", :session_id => "..." } then I get a Status 200 but my results are -1 as I believe the app_id is not recognised.
If I try to replicate the Soap Client call (<LanguageCount>) rather than Savon's call (<foo_web_service:LanguageCount>) then I get an Status 500.
Please advise and thanks in advance.
Long Story...
Using SOAP Client I can see that the correct request XML is:
User-Agent: Mac OS X; WebServicesCore (357)
Content-Type: text/xml
Host: redacted
Soapaction: http://tempuri.org/redacted/LanguageCount
<?xml version="1.0" encoding="utf-8"?>
<SOAP-ENV: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/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<LanguageCount xmlns="http://tempuri.org/">
<fooAppID xsi:type="xsd:string">12345678-1234-1234-1234-123456789123</fooAppID>
<sessionID xsi:type="xsd:string">12345678-1234-1234-1234-123456789123</sessionID>
</LanguageCount>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
However, when I try to do it in the console like so:
ruby-1.8.7-p302 > client = Savon::Client.new do |wsdl, http, wsse|
ruby-1.8.7-p302 > wsdl.document = "http://FooService.cloudapp.net/FooService.svc?wsdl"
ruby-1.8.7-p302 ?> end
=> #<Savon::Client:0x1055e2dc8 #http=#<HTTPI::Request:0x1055e2bc0>, #wsse=#<Savon::WSSE:0x1055e2b98>, #wsdl=#<Savon::WSDL::Document:0x1055e2c10 #request=#<HTTPI::Request:0x1055e2bc0>, #document="http://FooService.cloudapp.net/FooService.svc?wsdl">>
ruby-1.8.7-p302 >
ruby-1.8.7-p302 > client.request :language_count, :body => {:Foo_app_id => "12345678-1234-1234-1234-123456789123", :session_id => "12345678-1234-1234-1234-123456789123"}
Retrieving WSDL from: http://FooService.cloudapp.net/FooService.svc?wsdl
HTTPI executes HTTP GET using the net_http adapter
SOAP request: http://Fooservice.cloudapp.net/FooService.svc
SOAPAction: "LanguageCount", Content-Type: text/xml;charset=UTF-8
<?xml version="1.0" encoding="UTF-8"?><env:Envelope xmlns:wsdl="http://tempuri.org/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"><env:Body><LanguageCount><FooAppId>12345678-1234-1234-1234-123456789123</FooAppId><sessionId>12345678-1234-1234-1234-123456789123</sessionId></LanguageCount></env:Body></env:Envelope>
HTTPI executes HTTP POST using the net_http adapter
SOAP response (status 500):
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><s:Fault><faultcode xmlns:a="http://schemas.microsoft.com/ws/2005/05/addressing/none">a:ActionNotSupported</faultcode><faultstring xml:lang="en-US">The message with Action 'LanguageCount' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).</faultstring></s:Fault></s:Body></s:Envelope>
Savon::SOAP::Fault: (a:ActionNotSupported) The message with Action 'LanguageCount' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).
But when I use the namespace of foo_web_service, I get:
ruby-1.8.7-p302 > client = Savon::Client.new do |wsdl, http, wsse| ruby-1.8.7-p302 > wsdl.document = "http://FooService.cloudapp.net/FooService.svc?wsdl" ruby-1.8.7-p302 ?> end =>
#<Savon::Client:0x105882498 #http=#<HTTPI::Request:0x105882358>, #wsse=#<Savon::WSSE:0x105882330>, #wsdl=#<Savon::WSDL::Document:0x105882380 #request=#<HTTPI::Request:0x105882358>, #document="http://FooService.cloudapp.net/FooService.svc?wsdl">> ruby-1.8.7-p302 > ruby-1.8.7-p302 > client.request :Foo_web_service, :language_count, :body => {:Foo_app_id
=> "12345678-1234-1234-1234-123456789123", :session_id => "12345678-1234-1234-1234-123456789123"} Retrieving WSDL from: http://FooService.cloudapp.net/FooService.svc?wsdl HTTPI executes HTTP GET using the net_http adapter SOAP request: http://Fooservice.cloudapp.net/FooService.svc SOAPAction: "http://tempuri.org/FooService/LanguageCount", Content-Type: text/xml;charset=UTF-8 <?xml version="1.0" encoding="UTF-8"?><env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:Foo_web_service="http://tempuri.org/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"><env:Body><Foo_web_service:LanguageCount><FooAppId>12345678-1234-1234-1234-123456789123</FooAppId><sessionId>12345678-1234-1234-1234-123456789123</sessionId></Foo_web_service:LanguageCount></env:Body></env:Envelope> HTTPI executes HTTP POST using the net_http adapter SOAP response (status 200): <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><LanguageCountResponse xmlns="http://tempuri.org/"><LanguageCountResult>-1</LanguageCountResult></LanguageCountResponse></s:Body></s:Envelope>
=> #<Savon::SOAP::Response:0x105a2cca8 #http=#<HTTPI::Response:0x105a28ce8 #body="<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body><LanguageCountResponse xmlns=\"http://tempuri.org/\"><LanguageCountResult>-1</LanguageCountResult></LanguageCountResponse></s:Body></s:Envelope>", #raw_body="<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body><LanguageCountResponse xmlns=\"http://tempuri.org/\"><LanguageCountResult>-1</LanguageCountResult></LanguageCountResponse></s:Body></s:Envelope>", #code=200, #headers={"x-powered-by"=>"ASP.NET", "x-aspnet-version"=>"4.0.30319", "content-type"=>"text/xml; charset=utf-8", "date"=>"Sat, 02 Jul 2011 23:40:56 GMT", "server"=>"Microsoft-IIS/7.0", "content-length"=>"214", "cache-control"=>"private"}>, #soap_fault=Savon::SOAP::Fault, #http_error=Savon::HTTP::Error> ruby-1.8.7-p302 >
Long story short, I had to make 3 changes.
Changed response = client.request :language_count to
response = client.request "LanguageCount"
Added :xmlns => "http://tempuri.org/" to the end of the client.request call
Explicitly called the SOAPaction like: client.http.headers["SOAPAction"] = '"http://tempuri.org/FooService/LanguageCount"'
Hope this helps someone as I've been in SOAP hell for the weekend and hopefully I'll stop someone else being there.

Resources