How can I Authenticate a http web request with a certificate? - ruby-on-rails

I need to be able to send a http get request to a web service that requires clients to authenticate with a specific certificate. The .net code looks like this:
if (certificate != null)
request.ClientCertificates.Add(certificate);
return request;
I havent been able to figure out the equivalent in rails. Any suggestions?

If using basic net/https, then it's quite simple:
require 'net/https'
require 'uri'
uri = URI.parse(ARGV[0] || 'https://localhost/')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true if uri.scheme == "https" # enable SSL/TLS
http.key = pkey #Sets an OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
http.cert= cert #Sets an OpenSSL::X509::Certificate object as client certificate
http.start {
http.request_get(uri.path) {|res|
print res.body
}
}
If you have them combined, you'll have to massage them using some openssl utility methods.
For a custom http client you should read the docs for the ruby openssl library for the gory details.
But in a nutshell, something like this should work:
ctx = OpenSSL::SSL::SSLContext.new
ctx.key = private_key_file
ctx.cert = certificate_file
..and then supply the context to your connection.

Related

Read a private file from Github in Ruby

Looked at this for initial solutions. However, the file I want to reference in my rails project is in a private file. When I perform the following code:
uri = URI("https://.../config.yml")
file = Net::HTTP.get(uri)
config = YAML.load(file)
The 'file' has the contents of the sign-in page of github. Is it possible to pass credentials to access this private repo's file? Additionally, is this safe to do?
You have to set the credentials via a header. Something like this should work
token = "123"
req = Net::HTTP::Get.new(uri)
req['Authorization'] = "Token #{token}"
res = Net::HTTP.start(uri.hostname, uri.port) {|http|
http.request(req)
}
Otherwise I also suggest to just use the Github client library Octokit.

Ruby on rails HTTP request issue

I am an newbie to Ruby on Rails. I have a url which points to a JSON output. When I ran the URL directly like http://user:pass#myurl.com/json, I am getting the response without any authendication. However http://myurl.com/json requires a username and password through a standard apache pop up authentication box. I have tried to access this URL from my rails controller like the following:
result = JSON.parse(open("http://user:pass#myurl.com/json").read)
When I try to do, I just get an error which says ArgumentError, userinfo not supported. [RFC3986]
Also I have tried the below one. I am getting a 401-Unauthorized error
open("http://...", :http_basic_authentication=>[user, password])
How can I make a request that works in this case. Any help would be appreciated.
You need to use Net::HTTP (or some other HTTP client).
require 'net/http'
require 'uri'
require 'json'
uri = URI('http://myurl.com/json')
req = Net::HTTP::Get.new( uri )
req.basic_auth 'user', 'pass'
res = Net::HTTP.start(uri.hostname, uri.port) {|http|
http.request(req)
}
result = JSON.parse(res.body)
puts result

API call using Net::HTTP throwing Net::HTTPBadResponse error

I am working on rails environment. I am using Net::HTTP module for calling an external API and getting the response. This is working fine in my local host. But in staging it throwing an Net::HTTPBadResponse error. My staging is SSL enabled. This is the difference. Providing the code snippet and error below.
parameters = {'VirtualNumber' => '09845xxxxxx','Number[]' => "09878xxxxxx" }
x = Net::HTTP.post_form(URI.parse("https://example.com"), parameters)
Error:
Net::HTTPBadResponse (wrong status line: "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">")
The successful result will be in XML format. Can any one help me to solve this.
Thank You,
Regards
The issue was calling the API from ssl enabled site. So while calling the API we need to enable the ssl. And along with that need to provide basic authentication.
parameters = {'VirtualNumber' => '09845xxxxxx','Number[]' => "09878xxxxxx" }
url = URI.parse("https://example.com")
request = Net::HTTP::Post.new(url.path)
request.basic_auth "user", "pass"
request.set_form_data(parameters)
sock = Net::HTTP.new(url.host, url.port)
if url.scheme == 'https'
sock.use_ssl = true
end
response = sock.start {|http| http.request(request) }

Making an API call over SSL in Ruby

I have a method that works just fine for calls to non-ssl apis, but it gives me the following error response whenever I request https-only apis:
757: unexpected token at '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
Reason: You're speaking plain HTTP to an SSL-enabled server port.<br />
Instead use the HTTPS scheme to access this URL, please.<br />
</p>
</body></html>
The method is fairly straightforward:
def my_service_api_call(path = nil, query = nil)
my_service_api_key = ENV["MY_SERVICE_KEY"]
api_path = "#{path}/?api_key=#{my_service_api_key}&#{query}"
url = URI.parse(api_path)
req = Net::HTTP::Get.new(api_path)
res = Net::HTTP.start(url.host, url.port) { |http| http.request(req) }
JSON.parse(res.body)["results"]
end
This works great over http but fails over https-only. Is there an equivalent way to do HTTPS requests?
There's a more elegant way to reuse your instance of Net::HTTP and enable requests over HTTPS:
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE # Sets the HTTPS verify mode
#data = http.get(uri.request_uri)
Notice the use of use_ssl. From the documentation:
Turn on/off SSL. This flag must be set before starting session. If you change use_ssl value after session started, a Net::HTTP object raises IOError.
Note also that the usage of VERIFY_NONE is controversial, since it doesn't force the validity of of certificates to be checked. For many applications and users, this will not bear any negative ramifications. In cases where certificate validity should be checked, this post suggests the following:
Securely transfer the correct certificate and update the default certificate store or set the ca file instead.
You need to set use_ssl to true:
like this:
http = Net::HTTP.new(uri.hostname, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
http.ssl_version = :SSLv3

Ruby on Rails HTTPS Post Bad Request

Greetings all.
My application works with a remote server. Server uses https
authorization of the certificate. I have following code to authorize and
sends request:
uri = URI.parse("https://db1-test.content.ertelecom.ru/")
http = Net::HTTP.new(uri.host, '443')
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
http.ca_file = File.join(File.dirname("public/certificate.pem"),
"certificate.pem")
http.start do |http|
req =
Net::HTTP::Get.new("/cgi-bin/expr/export.get_pay_systems?partner_id=1003")
responce = http.request(req)
resp = responce.body
end
this code works well, I get the data from the server. BUT when I try to
make POST request:
http.start do |http|
req =
Net::HTTP::Post.new("/cgi-bin/expr/payment_transactions.verify_order",
params)
responce = http.request(req)
resp = responce.body
end
I get an error from the server:
Your browser sent a request that this server could not understand.
Request header field is missing ':' separator.
what is that be? I tried to find a solution, but to no avail. the
Internet caught the message that it could be antivirus, but I'm on
Linux. I will be glad to any thoughts!
You're not filling the header data.
You could either use the Net::HTTP.post_form method to create your request or populate the form_data yourself.
post_form solution:
req = NET::HTTP.post_form("/cgi-bin/expr/payment_transactions.verify_order", params)
manual form_data population
req =
Net::HTTP::Post.new("/cgi-bin/expr/payment_transactions.verify_order")
req.set_form_data(params)

Resources