rails pass soap basic auth with savon - ruby-on-rails

I'm trying to send soap request with basic authentication with savon gem
My soap server is set up with wash_out gem
class OrdersController < ApplicationController
soap_service namespace: 'sir:WashOut', wsse_username: SIRA[:auth][:username], wsse_password: SIRA[:auth][:password]
....
When i make a request to soap server via savon i get an error:
#client = Savon.client(
wsdl: "http://localhost:3000/orders/wsdl",
soap_header: { 'Username' =>SIRA[:auth][:username], 'Password' => SIRA[:auth][:password] }
)
#response = #client.call(:notify ).to_hash
On the last command i get an error
Savon::SOAPFault: (Server) Missing required UsernameToken

client = Savon.client(
wsdl: 'http://service.example.com?wsdl',
soap_header: {
"AuthenticateRequest" =>
{"apiKey" => "****** your api *********"}},
pretty_print_xml: true)
client.operations
response = client.call(:function)
Note: "apiKey" is my prams to authenticate, your can be different

I've tried this and it works!
#client = Savon.client(
wsdl: "http://localhost:3000/orders/wsdl",
wsse_auth: [SIRENA[:auth][:username], SIRENA[:auth][:password] ],
logger: Rails.logger
)
#response = #client.call(:notify, ).to_hash

For Savon 2. Basic authorization can be done as follows:
#client = Savon.client(
wsdl: "http://localhost:3000/orders/wsdl",
basic_auth: ["username", "password"]
)
#response = #client.call(:notify ).to_hash

Related

How to solve this error " (pre:svcFault) Service Fault"?

I am trying to call a SOAP api using Savon gem. I am getting the following error: "(pre:svcFault) Service Fault"
I created both the header and message for the request.
Here is the request sent from SoapUI: SoapUI request.
i am getting a true response from SoapUI.
My code is shown below:
class SoapApi
require 'savon'
def self.initialize
header = {
"ebmCID" => "9366498d-bc79-4fad-be2b-fa1a0e84241a",
"ebmMID" => "9366498d-bc79-4fad-be2b-fa1a0e84241a",
"ebmRTID" => "9366498d-bc79-4fad-be2b-fa1a0e84241a",
"ebmSID" => "FMobile-FCUBS",
"ebmTimestamp" => "2019-06-10T12:27:46.1623586Z",
}
message = {
customerId: '00653473'
}
client = Savon.client(
:wsdl => "https://192.168.176.103:8012/tevs/pp.pm.evs.Customer_1.2?wsdl",
:ssl_verify_mode => :none
)
response = client.call(
:get_account_list,
:soap_header => header,
:message => message
)
return response
end
end
And here i am calling the above method:
#index.html.erb
<%=
SoapApi.initialize
puts #response
%>
Where you able to create a valid call using SoapUI (https://www.soapui.org.)? Try this first and make it work.
Next create a call from a plain ruby script - without Rails - which sends the same functional XML as you did in SoapUI before.
Third embed this code into your RoR application.
You can put the following in your client definition for better logging:
client = Savon.client(
:wsdl => "https://192.168.176.103:8012/tevs/pp.pm.evs.Customer_1.2?wsdl",
:ssl_verify_mode => :none,
log: true,
log_level: :debug,
pretty_print_xml: true
)
Compare the output with your working SoapUI example.

How to access data requested by Post method in rails

Am trying to access data from a certain API using POST method but it returns back the actual list of params that I sent. Here is my code I don't know whether am doing this right, I will be glad for your help.
This is my controller
#Request access token from ExactApi
params = {
"code" => "#{code}",
"redirect_uri" => '/auth/exact/callback',
"grant_type" => "authorization_code",
"client_id" => "{CLIENT_ID}",
"client_secret" => "CLIENT_SECRET"
}
uri = URI.parse('https://start.exactonline.nl/api/oauth2/token')
#Encode the url into /x-www-form-urlencoded
uri.query = URI.encode_www_form(params)
#Transform http protocol into a secure protocol[https]
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE # You should use VERIFY_PEER in production
#Send the request to the ExactApi and return the received data
res = Net::HTTP::Post.new(uri.request_uri)
res.set_form_data(params)
puts "Received:: "+ res.body.to_yaml
Output
code[CODE]&redirect_uri=%2Fauth%2Fexact%2Fcallback&grant_type=authorization_code&client_id=CLIENT_ID&client_secret=SECRET_ID
How can I access the actual data returned from API?
require "net/http"
require "uri"
uri = URI.parse('https://start.exactonline.nl/api/oauth2/token')
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE # You should use VERIFY_PEER in production
request.set_form_data({
"code" => "#{code}",
"redirect_uri" => '/auth/exact/callback',
"grant_type" => "authorization_code",
"client_id" => CLIENT_ID,
"client_secret" => CLIENT_SECRET
})
response = http.request(request)
http://www.rubyinside.com/nethttp-cheat-sheet-2940.html
However I would use Omniauth instead of reinventing the Oauth wheel. Its pretty hard to get right. If you cannot find a ready made provider then creating a custom provider is pretty simple:
require 'omniauth-oauth2'
module OmniAuth
module Strategies
class ExactOnline < OmniAuth::Strategies::OAuth2
# change the class name and the :name option to match your application name
option :name, :exactonile
option :client_options, {
:site => "https://start.exactonline.nl",
:authorize_url => "/api/oauth2/token"
}
uid { raw_info["id"] }
info do
{
:email => raw_info["email"]
# and anything else you want to return to your API consumers
}
end
def raw_info
#raw_info ||= access_token.get('/api/v1/me.json').parsed
end
end
end
end
You are using puts which outputs to the server console. I'm confused where the output is. You should set yourself up a view with the same name as the controller action your block of code is within, for example if this is the index action:
def index
params= { your_hash_keys: "value" }
end
Then you should have an index.html.erb inside the app/views/controller_name/ In your controller instead of puts "Received:: "+ res.body.to_yaml use #debug = "Received:: "+ res.body.to_yaml and inside your view do something to output it like <%= #debug.inspect %>
Alternatively, and not recommended is to render inline in the controller:
render inline: "Received:: " + res.body.to_yaml
Layouts and Rendering with inline
You also should rename your params variable, since that is used by Rails for the incoming parameters. All in all I think a tutorial on MVC would be a good place to start.

Rails email using Postmark API on Heroku -- connection reset by peer

I have multiple bruises today, trying to learn two things at once... the API for Postmark and Rails HTTP requests.
Goal: Use Postmark add-on for Heroku to send production email.
I am trying to combine this article on HTTP requests...
http://docs.ruby-lang.org/en/2.0.0/Net/HTTP.html
... with this API reference for Postmark...
http://developer.postmarkapp.com/developer-send-api.html
Unfortunately, the examples from Postmark are done in curl and I have not succeeded in translating them into a HTTP request. I suspect the problem centers around the headers -- the parts of the transmission other than the body.
The rescue clause seen in the code below traps the error 'connection reset by peer'. At this point I don't know if I am even close to the right format for the headers that provide Postmark authentication.
I have the proper server token (in the config entry) and the From email has been given the required Postmark signature.
def send_production_email(email_address, subject, email_body)
# Use API to interact with Heroku add-on Postmark
# http://developer.postmarkapp.com/developer-send-api.html
uri = URI('https://api.postmarkapp.com/email')
# Form the request
req = Net::HTTP::Post.new(uri)
# Set request headers -- SUSPECT THIS IS WRONG
req['Accept'] = 'application/json'
req['Content-Type'] = 'application/json'
req['X-Postmark-Server-Token'] = Rails.application.config.postmark_token
rbody ={
'From' => 'Support <michael#mydomain.com>',
'To' => email_address,
'Subject' => subject,
'HtmlBody' => wrap_html(email_body),
'TextBody' => email_body
}.to_json
req.body = rbody
# Send the request, waiting for the response
begin
response = Net::HTTP.new(uri.host, uri.port).start {|http| http.request(req) }
rescue Exception => e
logthis("http request error: #{e.message}")
return
end
# ...parsing section omitted since I do not get that far...
end
A second attempt was formatted this way, but results in the same peer reset error:
rbody ={
'From' => 'Support <michael#disambiguator.com>', # TODO: replace email when domain is live
'To' => email_address,
'Subject' => subject,
'HtmlBody' => wrap_html(email_body),
'TextBody' => email_body
}.to_json
uri = URI('https://api.postmarkapp.com/email')
http = Net::HTTP.new(uri.host, uri.port)
# http.use_ssl = true
request = Net::HTTP::Post.new(uri.path, {'Content-Type' => 'application/json', 'Accept' => 'application/json', 'X-Postmark-Server-Token' => Rails.application.config.postmark_token})
request.body = rbody
# Send the request, waiting for the response
begin
response = http.request(request)
rescue Exception => e
logthis("http request error: #{e.message}")
return
end
I am grateful for any guidance!
I’m a Wildbit’s employee and the maintainer of the official Postmark Ruby gem.
The "connection reset by peer" error is the result of you trying to send an unencrypted HTTP request to an endpoint expecting secure communication via HTTPS. So, if you change this line:
Net::HTTP.new(uri.host, uri.port).start {|http| http.request(req) }
to:
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
response = http.start { |http| http.request(req) }
then you should be able to receive a response from the API. I see that you have this line in the second example, but it is commented. Since you’re doing this as an exercise, I’d like to add that when using net/http you don’t usually have to work with the underlying classes like Net::HTTP::Post. It’s generally simpler to use the higher level API provided by instances of the Net::HTTP class. Here is an example of how your method could be simplified by using it:
def send_production_email(email_address, subject, email_body)
uri = URI('https://api.postmarkapp.com/email')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
headers = {'Accept' => 'application/json',
'Content-Type' => 'application/json',
'X-Postmark-Server-Token' => Rails.application.config.postmark_token}
payload = {'From' => 'tema#wildbit.com',
'To' => email_address,
'Subject' => subject,
'HtmlBody' => email_body,
'TextBody' => email_body}
http.post(uri.request_uri, payload.to_json, headers)
rescue => e
puts "http request error: #{e.message}"
end
And, if you’re interested in how net/http is used in the official Postmark Ruby gem, check out the HttpClient class’ source.

Ruby: Savon AddressFilter mismatch at the EndpointDispatcher SOAP API

I am new to SOAP and I am having lots of trouble with Savon.
The API I am trying to access has really simplistic documentation: http://www.sona-systems.com/support/docs/sona_api_docs.pdf
When making a call, the API expects authentication in the parameters being sent. Here is my code:
client = Savon.client(
wsdl: "https://school.sona-systems.com/services/SonaAPI.svc?singleWsdl",
soap_header: {'To:' => "http://www.sona-systems.com/"},
pretty_print_xml: true,
soap_version: 2
)
response = client.call(:get_study_list) do
message username: "foo", password: "bar"
end
I am getting the following error:
Savon::SOAPFault: (s:Sender) The message with To '' cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher. Check that the sender and receiver's EndpointAddresses agree.
what is the soap_header: suppose to do?
I also cannot get to the url you provided. you should add log: true, log_level: :debug to your client definition to get more information.
try this:
client = Savon.client(
wsdl: "https://kellogg-elab.sona-systems.com/services/SonaAPI.svc?wsdl",
pretty_print_xml: true,
log: true,
log_level: :debug
)
puts client.operations
# then call a method of the service like this
resp = client.call(:get_study_list,
message: {username: "foo", password: "bar"}
)

Use Rails Logger with Savon gem

I have the following code:
def soap_client
soap_client = Savon.client(
wsdl: "https://api.five9.com/wsadmin/AdminWebService?wsdl&user=apiloader#daxko.com",
namespace: "http://service.admin.ws.five9.com/",
headers: {"Authorization" => "Basic #{#realm}"},
env_namespace: :soapenv,
namespace_identifier: :ser,
ssl_verify_mode: :none,
logger: Rails.logger,
log: true
)
end
This works and logs everything to my console window. However, it doesn't actually log anything to the Rails.logger...
How can I use the default Rails.logger with Savon?
EDIT
I am using savon (2.3.2).

Resources