how to pass Security header in savon 2.7 with Rails 4 - ruby-on-rails

my require header is
<SOAP-ENV:Header xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:Security SOAP-ENV:mustUnderstand="1">
<wsse:UsernameToken>
<wsse:Username>123</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>
</SOAP-ENV:Header>
this is my message :
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:dictionary:com.test.webservices">
<soapenv:Body>
<urn:getPIN/>
</soapenv:Body>
</soapenv:Envelope>
my code
soap_header = {
"wsse:Security" => {
"#soapenv:mustUnderstand" => 1,
"wsse:UsernameToken" =>{
"Username" => "123",
"Password" => "1234",
"digest" => false
}
}
}
client = Savon.client(wsdl: #wsdl, log: true,:ssl_verify_mode => :none,:soap_header=> soap_header)
response = client.call :getPIN, xml: #message
how to pass header in Savon 2.7 we not able to access services please help us.

Try this please (found on Savon 2 documentation):
Savon.client(wsse_auth: ["123", "1234"])

The soap endpoint I was contacting was very picky and I had this same problem. (wsse_auth did not work)
I solved this by modifying your answer slightly.
soap_header = {
"wsse:Security" => {
"#soapenv: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" =>{
"wsse:Username" => "123",
"wsse:Password" => "12345",
}
}
}
The problem was the missing soapenv:mustUnderstand="1"

Related

savon multiple namespace in body

I am new to Savon2
and passing wsdl url to the Savon.Client, and getting proper response in header, but I am not getting how to pass multiple namespace to the body:
Savon.client(wsdl: 'https://someUrl.com/abcd?wsdl', ssl_verify_mode: :none, pretty_print_xml: true, log: true, env_namespace: :soapenv, namespace_identifier: nil) do
wsse_auth("api_demo_account", "somePassword", :digest)
end
client.call(:operation_name, message: {
"api01Req" => [{"shipCode" => 'ABC', "shipAmount" => 1123,
"countryCode" => "USA"}
]},
'attributes' => { "xmlns" => "http://someUrl.com" })
and it is generating code for body like this:
<soapenv:Body>
<operationName xmlns="http://someUrl.com">
<xmlns:api01Req>
<shipCode>ABC</shipCode>
<shipAmount>1123</shipAmount>
<countryCode>USA</countryCode>
</xmlns:api01Req>
</operationName>
</soapenv:Body>
But I need a request like this:
<soapenv:Body>
<operationName xmlns="http://someUrl.com">
<api01Req>
<ns1:shipCode xmlns:ns1="http://someOtherUrl.com">ABC
</ns1:shipCode>
<ns2:shipAmount xmlns:ns2="http://someOtherUrl.com">1123
</ns2:shipAmount>
<ns3:countryCode xmlns:ns3="http://someOtherUrl.com">USA
</ns3:countryCode>
</api01Req>
</getTotalPostage>
</soapenv:Body>
like here it is generating ns1, ns2, ns3, etc along with xmlns:ns1, xmlns:ns2, etc.. different URL's, how should I modify the code to get like above request.

Why request sending error Savon::SOAPFault: (ns1:SecurityError)

I am getting this error from the SOAP actions integration.
Savon::SOAPFault: (ns1:SecurityError) A security error was encountered when verifying the message
my Savon client look like this:
client = Savon.client(wsdl: "https://212.154.167.194:9443/esf-web/ws/api1/SessionService?wsdl",
ssl_verify_mode: :none,
env_namespace: :soapenv,
pretty_print_xml: true,
namespace_identifier: :nam,
env_namespace: :soapenv,
namespaces: { "xmlns:nam" => "namespace.esf" },
:raise_errors => true,
log: true,
#loglevel: :debug,
pretty_print_xml: true)
message = {
"createSessionRequest" =>
{
"tin" => "placeholder",
"x509Certificate" => "placeholder"
}
}
and generated responce
response = client.call(:create_session, message: {:tin => 'XXXX', :x509Certificate => 'xxxxxx'})
The XML code should be here:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:esf="esf">
<soapenv:Header>
<wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-664678CEF9FFC67AD214168421472821">
<wsse:Username>123456789011</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security></soapenv:Header>
<soapenv:Body>
<esf:createSessionRequest>
<tin>?</tin>
<!--Optional:-->
<projectCode>?</projectCode>
<x509Certificate>?</x509Certificate>
</esf:createSessionRequest>
</soapenv:Body>
</soapenv:Envelope>
Please help
In the xml you have the following username and password
<wsse:Username>123456789011</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
Where do you set those username and password?
Read the guide so that you can follow their steps to configure Savon:
response = client.call(:authenticate, message: { username: "luke", password: "secret" })

Can't specify header in SOAP call using Savon

When calling to an API for retrieving labels for post parcels I get frustrated with how hard it is to set up a SOAP call with ruby.
I know that the following works from a sandbox environment:
this is the SHOULD BE call
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://postnl.nl/cif/services/BarcodeWebService/IBarcodeWebService/GenerateBarcode</Action>
<Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:Username>devc_!R4xc8p9</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">098fd559930983af31ef6630a0bb0c1974156561</wsse:Password>
</wsse:UsernameToken>
</Security>
</s:Header>
<s:Body>
<GenerateBarcode xmlns:d6p1="http://postnl.nl/cif/domain/BarcodeWebService/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://postnl.nl/cif/services/BarcodeWebService/">
<d6p1:Message>
<d6p1:MessageID>5</d6p1:MessageID>
<d6p1:MessageTimeStamp>28-06-2017 14:15:41</d6p1:MessageTimeStamp>
</d6p1:Message>
<d6p1:Customer>
<d6p1:CustomerCode>DEVC</d6p1:CustomerCode>
<d6p1:CustomerNumber>11223344</d6p1:CustomerNumber>
</d6p1:Customer>
<d6p1:Barcode>
<d6p1:Type>3S</d6p1:Type>
<d6p1:Range>DEVC</d6p1:Range>
<d6p1:Serie>1000000-2000000</d6p1:Serie>
</d6p1:Barcode>
</GenerateBarcode>
</s:Body>
</s:Envelope>
EDIT
As sugested I used build_request to inspect how my request looks. It actually looks like this:
<?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:wsdl="http://tempuri.org/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header>
<Username>devc_!R4xc8p9</Username
<Password>098fd559930983af31ef6630a0bb0c1974156561</Password>
</env:Header>
<env:Body><wsdl:GenerateBarcode><CustomerCode>DEVC</CustomerCode>
<CustomerNumber>11223344</CustomerNumber>
<Type>3S</Type>
<Range>DEVC</Range>
<Serie>1000000-2000000</Serie>
</wsdl:GenerateBarcode>
</env:Body>
</env:Envelope>
Comparing that with the xml above, it becomes clear that stuff is off. How to handle nesting?
This is when I build it myself like:
#client = Savon.client(
:convert_request_keys_to => :camelcase,
:raise_errors => false,
:pretty_print_xml => true,
:wsdl => 'https://testservice.postnl.com/CIF_SB/BarcodeWebService/1_1/?wsdl',
:headers => {
'Username' => 'devc_!R4xc8p9',
'Password' => '098fd559930983af31ef6630a0bb0c1974156561'
})
#response = #client.call(:generate_barcode) do
soap_header "Username" => 'devc_!R4xc8p9',
"Password" => '098fd559930983af31ef6630a0bb0c1974156561'
message customer_code: 'DEVC',
customer_number: 11223344,
type: '3S',
range: 'DEVC',
serie: '1000000-2000000'
end
I know my connection works, but also get back:
{:fault=>{:faultcode=>"s:CIF Framework Message Interceptor",
:faultstring=>"Check CIFException in the detail section", :detail=>
{:cif_exception=>{:errors=>{:exception_data=>{:description=>nil,
:error_msg=>"Username/password is not specified.",
:error_number=>"3"}},
:#xmlns=>"http://postnl.nl/cif/services/common/",
:"#xmlns:i"=>"http://www.w3.org/2001/XMLSchema-instance"}}}}
So already in my header stuff goes wrong. Username/password is not specified. I've tried several combinations and I don't get why.
Update
#client = Savon.client(
:env_namespace => :s,
# :namespace_identifier => :none, # :none doesn't work... gets interpreted literary. Out-commeting gives wsdl:GenerateBarcode
:convert_request_keys_to => :camelcase,
:raise_errors => false,
:pretty_print_xml => true,
:endpoint => 'https://testservice.postnl.com/CIF_SB/BarcodeWebService/1_1/BarcodeWebService.svc',
:wsdl => 'https://testservice.postnl.com/CIF_SB/BarcodeWebService/1_1/?wsdl')
soap_header = {
"Security" => {
"UsernameToken" => {
"Username" => 'devc_!R4xc8p9',
"Password" => '098fd559930983af31ef6630a0bb0c1974156561'
}
}
}
message = {
"d6p1:Customer" => {
"d6p1:CustomerCode" => 'DEVC',
"d6p1:CustomerNumber" => 11223344
},
"d6p1:Barcode" => {
"d6p1:Type" => '3S',
"d6p1:Range" => 'DEVC',
"d6p1:Serie" => '1000000-2000000'
}
}
#request = #client.build_request(:generate_barcode) do
soap_header soap_header
message message
end
#response = #client.call(:generate_barcode) do
soap_header soap_header
message message
Which builds the following request:
<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:s="http://tempuri.org/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Security>
<UsernameToken>
<Username>devc_!R4xc8p9</Username
<Password>098fd559930983af31ef6630a0bb0c1974156561</Password>
</UsernameToken>
</Security>
</s:Header>
<s:Body>
<wsdl:GenerateBarcode>
<d6p1:Customer>
<d6p1:CustomerCode>DEVC</d6p1:CustomerCode
<d6p1:CustomerNumber>11223344</d6p1:CustomerNumber>
</d6p1:Customer>
<d6p1:Barcode>
<d6p1:Type>3S</d6p1:Type>
<d6p1:Range>DEVC</d6p1:Range>
<d6p1:Serie>1000000-2000000</d6p1:Serie>
</d6p1:Barcode></s:GenerateBarcode>
</s:Body>
For as of yet, I get errors adding the wsse: namespace straight in the soap_header hash.
EDIT 2
<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:wsdl="http://tempuri.org/"
xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://postnl.nl/cif/services/BarcodeWebService/IBarcodeWebService/GenerateBarcode
</Action>
<Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<UsernameToken>
<Username>devc_!R4xc8p9</Username>
<Password>xxxxxxxx</Password>
</UsernameToken>
</Security>
</s:Header>
<s:Body>
<wsdl:GenerateBarcode>
<d6p1:Customer>
<d6p1:CustomerCode>DEVC</d6p1:CustomerCode>
<d6p1:CustomerNumber>11223344</d6p1:CustomerNumber>
</d6p1:Customer>
<d6p1:Barcode>
<d6p1:Type>3S</d6p1:Type>
<d6p1:Range>DEVC</d6p1:Range>
<d6p1:Serie>1000000-2000000</d6p1:Serie>
</d6p1:Barcode>
</wsdl:GenerateBarcode>
</s:Body>
</s:Envelope>
Comparing this to my should be call it seems that my <s:envelope ...> tag has too much information.
I'll make a follow up question of this probably.
EDIT 3
I restarted at Complex SOAP call in Ruby on Rails using Savon gets weird around the envelope and main operation
The Message hash, should be nested in the same way as the call expects it something like
#client = Savon.client(
:convert_request_keys_to => :camelcase,
:raise_errors => false,
:pretty_print_xml => true,
:wsdl => 'https://testservice.postnl.com/CIF_SB/BarcodeWebService/1_1/?wsdl',
:headers => {
'Username' => 'devc_!R4xc8p9',
'Password' => '098fd559930983af31ef6630a0bb0c1974156561'
})
#response = #client.call(:generate_barcode) do
soap_header "Security" => {
"UsernameToken" => {
"Username" => 'devc_!R4xc8p9',
"Password" => '098fd559930983af31ef6630a0bb0c1974156561'
}
}
message "GenerateBarcode" => {
"Message" => {
"MessageID" => 5, #might be different
"MessageTime" => Time.now, #might be different depending on use case
},
"Customer" => {
"CustomerCode" => 'DEVC',
"CustomerNumber" => 11223344
},
"Barcode" => {
"Type" => '3S',
"Range" => 'DEVC',
"Serie" => '1000000-2000000'
}
}
end
EDIT
Referencing this page it looks like you can add the action tag and elements like this
'Action' => "http://postnl.nl/cif/services/BarcodeWebService/IBarcodeWebService/GenerateBarcode",
:attributes! => {
"s:mustUnderstand" => "1",
"xmlns" => "http://schemas.microsoft.com/ws/2005/05/addressing/none"
}
Referencing this page it looks like you can set the namespaces directly "wsse:UsernameToken" instead of "UsernameToken"
which should result in the following
#client = Savon.client(
:convert_request_keys_to => :camelcase,
:raise_errors => false,
:pretty_print_xml => true,
:wsdl => 'https://testservice.postnl.com/CIF_SB/BarcodeWebService/1_1/?wsdl',
:headers => {
'Username' => 'devc_!R4xc8p9',
'Password' => '098fd559930983af31ef6630a0bb0c1974156561'
})
#response = #client.call(:generate_barcode) do
soap_header "Security" => {
"wsse:UsernameToken" => {
"wsse:Username" => 'devc_!R4xc8p9',
"wsse:Password" => '098fd559930983af31ef6630a0bb0c1974156561'
}
"Action" => "http://postnl.nl/cif/services/BarcodeWebService/IBarcodeWebService/GenerateBarcode",
:attributes! => {
"s:mustUnderstand" => "1",
"xmlns" => "http://schemas.microsoft.com/ws/2005/05/addressing/none"
}
}
message "GenerateBarcode" => {
"Message" => {
"MessageID" => 5, #might be different
"MessageTime" => Time.now, #might be different depending on use case
},
"Customer" => {
"CustomerCode" => 'DEVC',
"CustomerNumber" => 11223344
},
"Barcode" => {
"Type" => '3S',
"Range" => 'DEVC',
"Serie" => '1000000-2000000'
}
}
end

Savon SOAP Request not working

I'm using Savon gem in my Rails app and I need to submit my form fields to Equifax.
Here's the Equifax XML:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v3="http://eid.equifax.com/soap/schema/canada/v3">
<soapenv:Header/>
<soapenv:Body>
<v3:InitialRequest>
<v3:Identity>
<v3:Name>
<v3:FirstName>Michael</v3:FirstName>
<v3:LastName>Smith</v3:LastName>
</v3:Name>
<!--1 to 3 repetitions:-->
<v3:Address timeAtAddress="72" addressType="current">
<v3:HybridAddress>
<!--1 to 6 repetitions:-->
<v3:AddressLine>1028 Summerville</v3:AddressLine>
<v3:City>Vancouver</v3:City>
<v3:Province>BC</v3:Province>
<v3:PostalCode>V7B0A8</v3:PostalCode>
</v3:HybridAddress>
</v3:Address>
<!--Optional:-->
<v3:DateOfBirth>
<v3:Day>26</v3:Day>
<v3:Month>08</v3:Month>
<v3:Year>1984</v3:Year>
</v3:DateOfBirth>
<v3:PhoneNumber phoneType="current">
<v3:PhoneNumber>6045556666</v3:PhoneNumber>
</v3:PhoneNumber>
</v3:Identity>
<v3:ProcessingOptions>
<v3:Language>English</v3:Language>
</v3:ProcessingOptions>
</v3:InitialRequest>
</soapenv:Body>
</soapenv:Envelope>
This is my Ruby code making the SOAP Request.
<%= client.call(:start_transaction, message: { "v3:InitialRequest" => { "v3:Identity" => { "v3:Name" => { "v3:FirstName" => "michael", "v3:LastName" => "Smith"}, "v3:Address" => {"v3:AddressLine" => "233 Cambie St", "v3:City" => "Vancouve", "v3:Province" => "BC", "v3:PostalCode" => "V6B0E8"}, "v3:DateOfBirth" => {"v3:Day" => "26", "v3:Month" => "08", "v3:Year" => "1984"}, "v3:PhoneNumber" => {"v3:PhoneNumber" => "6048885555"}}}, attributes: { "v3:Address" => { "timeAtAddress" => "72", "addressType" => "current"}}) %>
The error message that is returned: (soap:Client) Error reading XMLStreamReader.
Can someone point me in the right direction?
Please try the below way by sending one string of that xml
xml_str = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:v3="http://eid.equifax.com/soap/schema/canada/v3"><soapenv:Header/><soapenv:Body><v3:InitialRequest><v3:Identity><v3:Name><v3:FirstName>Michael</v3:FirstName><v3:LastName>Smith</v3:LastName></v3:Name><!--1 to 3 repetitions:--><v3:Address timeAtAddress="72" addressType="current"><v3:HybridAddress><v3:AddressLine>1028 Summerville</v3:AddressLine><v3:City>Vancouver</v3:City><v3:Province>BC</v3:Province><v3:PostalCode>V7B0A8</v3:PostalCode></v3:HybridAddress></v3:Address><v3:DateOfBirth><v3:Day>26</v3:Day><v3:Month>08</v3:Month><v3:Year>1984</v3:Year></v3:DateOfBirth><v3:PhoneNumber phoneType="current"><v3:PhoneNumber>6045556666</v3:PhoneNumber></v3:PhoneNumber></v3:Identity><v3:ProcessingOptions><v3:Language>English</v3:Language></v3:ProcessingOptions></v3:InitialRequest></soapenv:Body></soapenv:Envelope>'
client.call(:start_transaction, xml: xml_str)
Remember you can use here document to made the xml string but the string should not consis "\n

Rails 3.1 Savon soap request giving Timeout::Error: Timeout::Error ut using curl i get response

I am having trouble to construct the soap client using savon in rails 3.1. But i am able to successfully get the response when i try to make the request from the curl command line.
My curl request from command line look like this
curl -d #Downloads/test.xml -H "content-type: text/xml;charset=UTF-8" -H "SOAPAction: http://services.bamnetworks.com/registration/identityPoint/create" "https://qaservices.bamnetworks.com/ws/services/IdentityPointService" -v
From which i got a perfect response like this.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Header /><soapenv:Body><identityPoint_create_response xmlns="http://services.bamnetworks.com/registration/types/1.6"><status><code>-2000</code><message> [Duplicate credential constraint violated] [com.bamnetworks.registration.types.exception.DuplicateCredentialException]</message><exceptionClass>com.bamnetworks.registration.types.exception.DuplicateCredentialException</exceptionClass>
But when i try to make a request from Savon client every time i am getting the
HTTPI executes HTTP POST using the net_http adapter
Timeout::Error: Timeout::Error
My Savon request look like this
client = Savon::Client.new do |wsdl, http|
http.auth.ssl.verify_mode = :none
wsdl.document = "https://qaservices.bamnetworks.com/ws/services/IdentityPointService?wsdl"
end
begin
response = client.request :ns, :identityPoint_create_request do |soap, wsdl, http|
http.headers['SOAPAction'] = 'http://services.bamnetworks.com/registration/identityPoint/create'
http.headers = { "Content-Length" => "0", "Connection" => "Keep-Alive" }
soap.namespaces["xmlns:ns0"]="http://services.bamnetworks.com/application/types/1.0"
soap.header = {
"ns0:appCredentials" => {
"ns0:name"=>"XXXXXXX",
"ns0:password"=>"XXXXXXXXX"
}
}
soap.body ={
:identification => {
:email => {
:address => "mlb_user#mlb.com"
},
:password => { :address => { :id => 44 } }
},
:profileProperty => {
:name => "birthDay",
:value => "17"
},
:profileProperty => {
:name => "birthMonth",
:value => "8"
},
:profileProperty => {
:name => "birthYear",
:value => "1986"
},
:attributes! => { :identification => { :type => "email-password" } }
}
end
I dont know where i am making the mistake. If anybody help me in this to figure it out.
Thanks!
This may be soap server issue try to comment line:
http.headers = { "Content-Length" => "0", "Connection" => "Keep-Alive" }

Resources