OpenSSL::SSL::SSLError in Rails while raising HTTP REQUEST - ruby-on-rails

I am getting OpenSSL::SSL::SSLError while making one http_request. Please find the code mentioned below.
require 'net/http'
uri = URI.parse("http://webaddress.com")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new("/v1.1/auth")
request.add_field('Content-Type', 'application/json')
request.body = {"auth_token"=>"abcd" ,"employee" => {"method" => "add_employee"}}
response = http.request(request)
It's throwing following error :
SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: unknown protocol
Please let me know why this error is coming? and what could be the reason for this error.

Related

Request with -curl

I would like to run a curl command to request data from an API, but I'm not sure of how to do it. To transform curl request into ruby code, I'm using curl to ruby, which is great by the way.
Following the doc API, I have this :
Step 1 (Get your token) :
curl -X POST https://api.monkey-locky.com/login_check -d _username={usr}
-d _password={pwd}
I have translated this by :
require 'net/http'
require 'uri'
uri = URI.parse("https://api.monkey-locky.com/login_check")
request = Net::HTTP::Post.new(uri)
request.set_form_data(
"_password" => "my_secret_pass",
"_username" => "my#mail.co",
)
req_options = {
use_ssl: uri.scheme == "https",
}
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
print response.body
This request give me an Token to use the API.
Step 2 (Verify if the token is working) :
curl -H "Authorization: Bearer [TOKEN]" https://api.monkeylocky.com/bookings
I have translated this by :
require 'net/http'
require 'uri'
uri = URI.parse("https://api.monkeylocky.com/bookings")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer [TOKEN]"
req_options = {
use_ssl: uri.scheme == "https",
}
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
But this script is rendering an error like this :
`rescue in block in connect': Failed to open TCP connection to
api.monkeylocky.com:443 (getaddrinfo: nodename nor servname provided,
or not known) (SocketError)
I'm not very comfortable with CURL, I'm just starting to use these request. So I'm not sure of what I'm doing right now. Any suggestion about that ?
You're sending the first request to https://api.monkey-locky.com but the URL in the second request is https://api.monkeylocky.com (no dash)

curl to Ruby request for connecting to wheniwork

Back story
I've spent a few days on the Ruby gem for wheniwork, and it's been a nightmare. To make a long story short, the gem had a dependency of an older version of activesupport and I basically forked their repo and made a compatible version for my ruby project. I was able to create a new gem and attempted to use it, but I was getting the following json message:
{"error"=>"User login required for this resource.", "code"=>1000}
The username, password, and api key were set. What I basically need to do is access our account on wheniwork, and retrieve data.
This is an example using the curl command
curl https://api.wheniwork.com/2/login \
--data '{"username":"user#example.com","password":"*******"}' \
-H "W-Key: iworksoharditsnotfunny"
Essentially, I would get some kind of return object from wheniwork that would contain the token. I'd use this token for future requests to the wheniwork site.
To (Ruby)
A new attempt to translate this to Ruby
require 'net/http'
data = {'credentials' => {'username' => 'XXXXX#XXXXX.com','password' => 'XXXXX', 'W-Key' => '111111111XXXXX'}}
uri = URI.parse("https://api.wheniwork.com/2/login/")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new(uri.path, initheader = {'Content-Type' =>'application/json'})
request.add_field('Content-Type', 'application/json')
request.body = data.to_json
response = http.request(request)
Result:
#<Net::HTTPUnauthorized 401 Unauthorized readbody=true>
If you have any idea or clue (or basically anything that would help me here), I would appreciate it beyond words. Thanks!
Got it!! The major issue(s) were that the api key and (username+password) combo are two separate pieces.
I was so close the entire time, but here it is:
data = {'username' => 'XXXX#XXXXXXX.com','password' => 'XXXXX'}
uri = URI.parse("https://api.wheniwork.com/2/login/")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new(uri.path)
request.add_field('W-Key', 'XXXXXXXXXXXXX')
request.body = data.to_json
response = http.request(request)
puts JSON.parse(response.body)

NET::HTTP call fails from ssl when in rails envrionment

I have some code that makes a few Net::HTTP calls some over https This code works fine when used in irb
however, when used from rails or the rails console I get an error:
OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
from /Users/kevzettler/.rbenv/versions/2.0.0-p353/lib/ruby/2.0.0/net/http.rb:918:in `connect'
I avoided the issue by passing a SSL verification manually like following code.
uri = URI(#url)
req = Net::HTTP::Get.new(uri.path)
response = Net::HTTP.start(
uri.host, uri.port,
:use_ssl => uri.scheme == 'https',
:verify_mode => OpenSSL::SSL::VERIFY_NONE) do |https|
https.request(req)
end
Quoted from here: https://github.com/matsubo/web_update_checker/blob/master/lib/web_update_checker.rb#L44

Retrieve PEM cert: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed

As many others I've got the error with Ruby: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed.
I downloaded a cacert.pem and tried to add it like this:
require 'net/http'
# create a path to the file "C:\RailsInstaller\cacert.pem"
cacert_file = File.join(%w{c: RailsInstaller cacert.pem})
Net::HTTP.start("curl.haxx.se") do |http|
resp = http.get("/ca/cacert.pem")
if resp.code == "200"
open(cacert_file, "wb") { |file| file.write(resp.body) }
puts "\n\nA bundle of certificate authorities has been installed to"
puts "C:\\RailsInstaller\\cacert.pem\n"
puts "* Please set SSL_CERT_FILE in your current command prompt session with:"
puts " set SSL_CERT_FILE=C:\\RailsInstaller\\cacert.pem"
puts "* To make this a permanent setting, add it to Environment Variables"
puts " under Control Panel -> Advanced -> Environment Variables"
else
abort "\n\n>>>> A cacert.pem bundle could not be downloaded."
end
end
And like this:
require 'open-uri'
require 'net/https'
module Net
class HTTP
alias_method :original_use_ssl=, :use_ssl=
def use_ssl=(flag)
self.ca_file = Rails.root.join('lib/ca-bundle.crt')
self.verify_mode = OpenSSL::SSL::VERIFY_PEER
self.original_use_ssl = flag
end
end
end
I even tried to cancel the check:
require 'faraday'
module Faraday
class Adapter
class NetHttp < Faraday::Adapter
def call(env)
super
is_ssl = env[:url].scheme == 'https'
http = net_http_class(env).new(env[:url].host, env[:url].port || (is_ssl ? 443 : 80))
if http.use_ssl = is_ssl
ssl = env[:ssl]
if ssl[:verify] == false
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
else
http.verify_mode = OpenSSL::SSL::VERIFY_NONE # <= PATCH or HACK ssl[:verify]
end
http.cert = ssl[:client_cert] if ssl[:client_cert]
http.key = ssl[:client_key] if ssl[:client_key]
http.ca_file = ssl[:ca_file] if ssl[:ca_file]
end
req = env[:request]
http.read_timeout = net.open_timeout = req[:timeout] if req[:timeout]
http.open_timeout = req[:open_timeout] if req[:open_timeout]
full_path = full_path_for(env[:url].path, env[:url].query, env[:url].fragment)
http_req = Net::HTTPGenericRequest.new(
env[:method].to_s.upcase, # request method
(env[:body] ? true : false), # is there data
true, # does net/http love you, true or false?
full_path, # request uri path
env[:request_headers]) # request headers
if env[:body].respond_to?(:read)
http_req.body_stream = env[:body]
env[:body] = nil
end
http_resp = http.request http_req, env[:body]
resp_headers = {}
http_resp.each_header do |key, value|
resp_headers[key] = value
end
env.update \
:status => http_resp.code.to_i,
:response_headers => resp_headers,
:body => http_resp.body
#app.call env
rescue Errno::ECONNREFUSED
raise Error::ConnectionFailed.new(Errno::ECONNREFUSED)
end
def net_http_class(env)
if proxy = env[:request][:proxy]
Net::HTTP::Proxy(proxy[:uri].host, proxy[:uri].port, proxy[:user], proxy[:password])
else
Net::HTTP
end
end
end
end
end
But no luck (and not the way you want to fix this). Weird thing is that it works sometimes.
Now I'm trying this, but have trouble finding the certificates:
require 'net/http'
url = URI.parse('https://www.xpiron.com/schedule')
req = Net::HTTP::Get.new(url.path)
sock = Net::HTTP.new(url.host, 443)
sock.use_ssl = true
store = OpenSSL::X509::Store.new
store.add_cert OpenSSL::X509::Certificate.new(File.new('addtrust_ca.pem'))
store.add_cert OpenSSL::X509::Certificate.new(File.new('utn.pem'))
store.add_cert OpenSSL::X509::Certificate.new(File.new('user_first_ca.pem'))
store.add_cert OpenSSL::X509::Certificate.new(File.new('xpiron.pem'))
sock.cert_store = store
sock.start do |http|
response = http.request(req)
end
So I opened the https://myserver.com/Request.ashxrequest in chrome, clicked on the little lock-icon to get the certificate details. But I can't find any PEM files to export. I can see that it's a COMODO certificate. I don't own the server, so I got to find a solution for this on my side.
you can disable certificate verification for a given instance of Net::HTTP:
stock.verify_mode = OpenSSL::SSL::VERIFY_NONE
or you can disable SSL verification globally in your process using:
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
Note: Ruby interpreter will give you warning that constant is already initialized. Sometimes you might get hard error. if that's the case you can unassign constant and initialize it again using following code:
OpenSSL::SSL.send(:remove_const, :VERIFY_PEER)
OpenSSL::SSL.const_set(:VERIFY_PEER, OpenSSL::SSL::VERIFY_NONE)
This is not a perfect solution for your problem, but if security is not a big cocern, you can use above methods to bypass SSL Cert verification. You will still have encrypted secure connection to server.

heroku is given a 403 forbidden for a New::HTTP.new ... any idea why?

uri = URI.parse("https://cloudfront.amazonaws.com/2010-08-01/distribution/#{config['cloud_dist_id']}/invalidation")
req = Net::HTTP::Post.new(uri.path)
req.initialize_http_header({
'x-amz-date' => date,
'Content-Type' => 'text/xml',
'Authorization' => "AWS %s:%s" % [config['access_key_id'], Base64.encode64(digest.digest)]
})
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
res = http.request(req)
When I output:
puts http.inspect
puts res.inspect
Locally it works fine:
#<Net::HTTP cloudfront.amazonaws.com:443 open=false>
#<Net::HTTPCreated 201 Created readbody=true>
But on heroku:
#<Net::HTTPForbidden 403 Forbidden readbody=true>
Failed 403
Any idea why this is failing on heroku. Why it's forbidden? Thanks
Heroku adds additional output headers your application is not aware of at the moment of signing your request.
Try to explicitly limit scope of headers which participate in signature, there are some options in AWS API for this
make it test with heroku console.
It should work as i am using same thing but using HTTParty.
Thanks

Resources