Executing curl through Ruby script - ruby

I'm trying to execute curl through Ruby script using two different methods and have some errors in both.
First method is using shell command
#!/usr/bin/ruby
`curl --cacert RepoCert --location --request POST 'https://test-service/rest/services/request/' --header 'Authorization: Basic amkkdksmmkk3XCf45DffSa23Ert' --header 'Content-Type: application/json' --data-binary "{ \"serviceID\": \"3\", \"TypeId\": \"52\", \"requestFieldValues\": { \"summary\": \"summary\", \"description\": \"something\", \"prority\": { \"id\": \"1\"}, \"customfield\": \"5\" }} "`
and I have an error
"Unexpected character (\u0027s\u0027 (code 115)): was expecting double-quote to start field name\n at [Source: com.itlab.jira.plugins.extender.helper.RequestWrapper$5db70c75; line:1, column:5]"
Also tried using Ruby Net::HTTP (code generated from https://jhawthorn.github.io/curl-to-ruby/)
require 'net/http'
require 'uri'
require 'json'
uri = URI.parse("https://test-service/rest/services/request/")
request = Net::HTTP::Post.new(uri)
request.content_type = "application/json"
request["Authorization"] = "Basic amkkdksmmkk3XCf45DffSa23Ert"
request.body = JSON.dump({
"serviceID" => "3",
"TypeId" => "52",
"requestFieldValues" => {
"summary" => "summary",
"description" => "something",
"prority" => {
"id" => "1"
},
"customfield" => "5"
}
})
req_options = {
use_ssl: uri.scheme == "https",
}
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
and I get
/usr/share/ruby/net/http.rb:921:in `connect': SSL_connect returned=1 errno=0 state=error: certificate verify failed (OpenSSL::SSL::SSLError)
The problem is I have to use certificate authorization in this case so I can't ignore it.
Curl executed form command line is working fine. Any idea how to fix one of those methods (or both)?

Thanks guys for trying to help but I figure it out using Net::HTTP. I leave comment here if someone ever looked for a similar case.
require 'net/http'
require 'uri'
require 'json'
uri = URI.parse("https://test-service/rest/services/request/")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
http.ca_file = "/directory/to/cert/file"
request = Net::HTTP::Post.new(uri.request_uri)
request.content_type = "application/json"
request["Authorization"] = "Basic amkkdksmmkk3XCf45DffSa23Ert"
request.body = JSON.dump({
"serviceID" => "3",
"TypeId" => "52",
"requestFieldValues" => {
"summary" => "summary",
"description" => "something",
"prority" => {
"id" => "1"
},
"customfield" => "5"
}
})
response = http.request(request)

Related

make a request using curl, equivalent to a REST_CLIENT request

I'm using the following request in Curl
curl -X GET -k -H 'Content-Type: application/json' -H 'Authorization: Bearer XXXXXXX' -H 'RowId: 100' -i 'https://url.xxx/row'
and the request using REST_CLIENT (2.1.0):
RestClient::Request.execute(:url => "https://url.xxx/row", :method => :get, :verify_ssl => false, :headers => {:content_type => "application/json", :Authorization => "Bearer XXXXXXX", :RowId => 100})
RestClient::NotFound: 404 Not Found
The first one (Curl) is working, but the equivalent request in RestClient does not.
The problem is that rest-client is not passing all headers:
{:content_type => "application/json", :Authorization => "Bearer XXXXXXX", :RowId => 100}
only content_type and Authorization are used, the others are not taken when request is sending
There is a similar issue with net/http:
require 'net/http'
uri = URI('https://url.xxx/row')
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true
https.verify_mode = OpenSSL::SSL::VERIFY_NONE
https.ssl_version = :TLSv1
req = Net::HTTP::Get.new uri
req['content_type'] = 'application/json'
req['Authorization'] = "Bearer #{token}"
req['RowId'] = 100
res = https.request req
puts res.body
Any suggestions ?
Thx
rest-client will return 404 error in multiple cases not only for not found errors
the best way here is to return and check the server's response
as per their documentation: https://github.com/rest-client/rest-client#exceptions-see-httpwwww3orgprotocolsrfc2616rfc2616-sec10html
>> RestClient.get 'http://example.com/nonexistent'
Exception: RestClient::NotFound: 404 Not Found
>> begin
RestClient.get 'http://example.com/nonexistent'
rescue RestClient::ExceptionWithResponse => e
e.response
end
=> <RestClient::Response 404 "<!doctype h...">
probably also try to call e.response.body to check the error

How to use httparty instead of net/http or curl

I have a curl request which works
curl -X GET -k 'https://APIADDRESSHERE' -u 'USERNAME:PASSWORD' -H 'Content-Type: application/json'
I can also get this working in ruby:
require 'net/http'
require 'uri'
require 'openssl'
uri = URI.parse("https://APIADDRESSHERE")
request = Net::HTTP::Get.new(uri)
request.basic_auth("USERNAME", "PASSWORD")
request.content_type = "application/json"
req_options = {
use_ssl: uri.scheme == "https",
verify_mode: OpenSSL::SSL::VERIFY_NONE,
}
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
However when I try this with httparty I keep getting a 401 error saying:
An Authentication object was not found in the SecurityContext This request requires HTTP authentication.
I have tried a lot of variations of the following but I'm stuck.
response = HTTParty.get('https://APIURLHERE', {"headers": { "Authorization:" => "BASE64ENCODEDUSERNAMEANDPASSWORD", "Content-Type" => "application/json" }})
Have you tried the following?
response = HTTParty.get('https://APIURLHERE', headers: { "Authorization:" => "BASE64ENCODEDUSERNAMEANDPASSWORD", "Content-Type" => "application/json" })
Ok I made a simple mistake somewhere along the way because the original solution from the similar post worked... Dont know how it didnt work 50 times last time I was working on this but it was clearly an error on my part somewhere.

How to convert curl to Ruby Net::HTTP with -X GET -G options?

I was using https://jhawthorn.github.io/curl-to-ruby/ to convert curl commands to Net::HTTP code. However the following cannot be converted using the jhawthorn resource:
curl -H "Content-type: application/json" -H "Authorization: Token token=$PAGERDUTY_ACCESS_KEY" -X GET -G --data-urlencode "since=2017-01-16" --data-urlencode "until=2017-01-17" "https://company.pagerduty.com/api/v1/schedules"
I have described my exact problem in this github issue: https://github.com/jhawthorn/curl-to-ruby/issues/8
This is my current function that uses the Net::HTTP gem:
#!/usr/bin/env ruby
require 'json'
require 'net/http'
require 'uri'
def get_pagerduty_hash(ending='')
uri = URI.parse("https://company.pagerduty.com/api/v1/schedules#{ending}")
request = Net::HTTP::Get.new(uri)
request.content_type = "application/json"
request["Authorization"] = "Token token=#{ENV['PAGERDUTY_ACCESS_KEY']}"
req_options = {
use_ssl: uri.scheme == "https",
}
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
return JSON.parse(response.body).to_hash
end
How can I change this to correctly use the date part of the original curl command:
-X GET -G --data-urlencode "since=2017-01-16" --data-urlencode "until=2017-01-17"
You have to use the URI.encode_www_form function:
#!/usr/bin/env ruby
require 'json'
require 'net/http'
require 'uri'
def get_pagerduty_hash(ending='')
uri = URI.parse("https://company.pagerduty.com/api/v1/schedules#{ending}")
params = { :since => '2017-01-16', :until => '2017-01-17' }
uri.query = URI.encode_www_form(params)
request = Net::HTTP::Get.new(uri)
request.content_type = "application/json"
request["Authorization"] = "Token token=#{ENV['PAGERDUTY_ACCESS_KEY']}"
req_options = {
use_ssl: uri.scheme == "https",
}
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
return JSON.parse(response.body).to_hash
end
urlencode means that the data is encoded in the URL
url = URI.parse('http://example.com')
url.query = "since=2017-01-16&until=2017-01-17"
puts url
# => http://example.com?since=2017-01-16&until=2017-01-17

Ruby https POST with headers and auth error

I'm trying to sent a post request that like so based on curl:
curl -XPOST -H content-type:application/json -d "{\"date\":\"2012-07-02\",\"aaaa\":\"bbbbb\", \"cccc\" : \"\[\"dddd\",\"eeee\",\"fffff\"\]\"}" URI -u USERNAME:PASSWORD
In Ruby:
#toSend = {
"date" => "2012-07-02",
"aaaa" => "bbbbb",
"cccc" => ["dddd","eeee","fffff"]
}.to_json
uri = URI.parse("https:/...")
https = Net::HTTP.new(uri.host,uri.port)
https.use_ssl = true
req = Net::HTTP::Post.new(uri.path, initheader = {'Content-Type' =>'application/json'})
req.body = "[ #{#toSend} ]"
req.basic_auth options[:username].to_s, options[:password].to_s
post = https.request(req)
For some reason the auth isn't getting attached what could be wrong with this?
I suspect your request to be run before you even add the auth parameters.
I would go this way:
require 'net/http'
require 'uri'
url = URI.parse('https://....')
req = Net::HTTP::Post.new(url.path)
req.basic_auth options[:username].to_s, options[:password].to_s
req.use_ssl = true
req.form_data({"date" => "2012-07-02", "aaaa" => "bbbbb", "cccc" => ["dddd","eeee","fffff"]})
resp = Net::HTTP.new(url.host, url.port).start {|http| http.request(req) }

HTTPs Request in Ruby with parameters

I'm trying to pull data from a RESTful JSON web service which uses https. They provided a Curl example which works no problem; however, I'm trying to run the query in Ruby and I'm not a Ruby developer.
Any help much appreciated!
cURL example:
curl -G "https://api.example.com/v1/query/" \
-H "Accept: application/vnd.example.v1+hal+json" \
-u "$API_KEY:$API_SECRET" \
-d "app_id=$APP_ID" \
-d "days=3" \
-d "metrics=users" \
-d "dimensions=day"
My attempt in Ruby which is resulting in a HTTPUnauthorized 401:
require 'net/https'
require 'uri'
# prepare request
uri = URI.parse("https://api.example.com/v1/query/")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(uri.request_uri, {
'Accept' => 'application/vnd.example.v1+hal+json',
'api_key' => 'api_secret',
'app_id' => 'app_id',
'days' => '3',
'metrics' => 'users',
'dimensions' => 'day'})
response = http.request(request)
response.body
response.status
response["header-here"] # All headers are lowercase
# Analyze the response
if response.code != "200"
puts "Error (status-code: #{response.code})\n#{response.body}"
print 0
else
print 1
end
** Update **
As per feedback below, I've installed Typhoeus and updated the request. Now I'm getting through. Thanks all!
request = Typhoeus::Request.new(
"https://api.example.com/v1/query/",
userpwd: "key:secret",
params: {
app_id: "appid",
days: "3",
metrics: "users",
dimensions: "day"
},
headers: {
Accept: "application/vnd.example.v1+hal+json"
}
)
First you need to realize that:
'Accept' => 'application/vnd.example.v1+hal+json'
is a header, not a parameter.
Also:
$API_KEY:$API_SECRET
is basic HTTP authentication, not a parameter.
Then, take my advice and go with a better Ruby HTTP client:
https://github.com/lostisland/faraday (preferred, a wrapper for the bellow)
https://github.com/typhoeus/typhoeus
https://github.com/geemus/excon
Update:
Try the following from IRB:
Typhoeus::Config.verbose = true # this is useful for debugging, remove it once everything is ok.
request = Typhoeus::Request.get(
"https://api.example.com/v1/query/",
userpwd: "key:secret",
params: {
app_id: "appid",
days: "3",
metrics: "users",
dimensions: "day"
},
headers: {
Accept: "application/vnd.example.v1+hal+json"
}
)
curl's -u sends the Authorization header. so your 'api_key' => 'api_secret', should be replaced with this one(once again, its http header, not parameter).
"Authorization" => "Basic ".Base64.encode64("api_key:api_secret")
## require "base64"

Resources