Ruby https POST with headers and auth error - ruby

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) }

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

Ruby API (RabbitMQ create user)

Started working on Ruby a week back. Writing an API to connect to RabbitMQ messaging queue. The command line for adding a new user works.
$ curl -i -u guest:guest -H "content-type:application/json" -XPUT -d'{"password":"pwd","tags":"administrator"}' http://localhost:15672/api/users/username
I need to make this Http Put request from Ruby. The following is my code:
def test_add_user
uri = URI.parse('http://localhost:15672/api/users/karthik/')
uri.to_s
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Put.new(uri.path)
request.basic_auth 'guest', 'guest'
request['Content-Type'] = 'application/json'
request['Accept'] = 'application/json'
request.set_form_data({'password' => 'secret', 'tags' => 'management'})
http.start do |http|
res = http.request(request)
puts res
end
end
This is the result I get
o.test_add_user
#<Net::HTTPUnsupportedMediaType:0x007fd7fb6fe1d8>
=> nil
Does Media type exception relate with Content-Type?
Only application/json is allowed
Should I use anything like to_json? If yes, where should it be used? Thanks in advance.
Regards
Karthik
Thank you Hector and ptd. Fixed it. Attached the working code for future reference.
def test_add_user
uri = URI.parse('http://localhost:15672/api/users/Test1/')
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Put.new(uri.path)
request.basic_auth 'guest', 'guest'
request['Content-Type'] = 'application/json'
request['Accept'] = 'application/json'
request.body = {'password' => 'secret', 'tags' => 'management'}.to_json
http.start do |http|
res = http.request(request)
puts res
end
end
Adds a new user to the RabbitMQ queue

team city api returns json example

I'm struggling with getting results from the team city api in JSON
require 'open-uri'
url = ".../app/rest/buildQueue/"
c = Curl::Easy.new(url) do |curl|
curl.headers["Content-type"] = "application/json"
curl.http_auth_types = :basic
curl.username = 'user'
curl.password = 'password'
end
c.perform
puts c.body_str
I get a bunch of xml text
You need to use the Accept header to control the response type:
e.g (command line)
curl --url http://xxx/app/rest/buildQueue/ -H Accept:"application/json"
Documentation Reference
also you can use "net/http"
require 'net/http'
require 'uri'
url = URI('http://localhost:8111/httpAuth/app/rest/agents')
req = Net::HTTP::Get.new(url)
req['Accept'] = 'application/json'
req.basic_auth 'admin', 'admin'
res = Net::HTTP.start(url.hostname, url.port) {|http|
http.request(req)
}
puts res.body

How to POST to exchange a 23andme auth code for a token

The 23andme web site has an API and they give the following instructions:
Send a POST /token/ request with these parameters (client_id and client_secret are on your dashboard):
curl https://api.23andme.com/token/
-d client_id=xxx \
-d client_secret=yyy \
-d grant_type=authorization_code \
-d code=zzz \
-d "redirect_uri=https://localhost:5000/receive_code/"
-d "scope=basic%20rs3094315"
If successful, you'll get a 200 JSON response like this:
{"access_token":"89822b93d2",
"token_type":"bearer",
"expires_in": 86400,
"refresh_token":"33c53cd7bb",
"scope":"rs3094315 basic"}
So, here's what I tried, but it didn't work. I know Ruby, but have never used net/http or uri.
def self.get_token(code)
uri = URI.parse("https://api.23andme.com/token")
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true
request = Net::HTTP::Post.new(uri.path)
request["client_id"] = 'my client id goes here'
request["client_secret"] = 'my client secret goes here'
request["grant_type"] = 'authorization_code'
request["code"] = code
request["redirect_uri"] = 'http://localhost:3000'
request["scope"] = 'names basic haplogroups relatives'
response = https.request(request)
return response.to_s
end
You are doing it right using curl with the -d option to set the parameter in the body of the POST request. However, with the Net::HTTP::Post object, the syntax request["key"] = value is used to set the headers of the Http object.
Use set_form_data to set all the parameters into the body of the POST request.
For example, use it in this way:
request.set_form_data({"client_id" => "my client id goes here", "code" => code})
The following will clarify the above:
$ > request["client_id"] = 'my client id goes here'
# => "my client id goes here"
$ > request.body
# => nil # body is nil!!!
$ > request.each_header { |e| p e }
# "client_id"
# => {"client_id"=>["my client id goes here"]}
$ > request.set_form_data("client_secret" => 'my client secret goes here')
# => "application/x-www-form-urlencoded"
$ > request.body
# => "client_secret=my+client+secret+goes+here" # body contains the added param!!!
I just wanted to post the code that worked. Thanks to Rafa.
def self.get_token(code)
uri = URI.parse("https://api.23andme.com/token")
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true
https.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new(uri.path,
initheader = {'Content-Type' =>'application/json'})
request.set_form_data({"client_id" => 'my client id',
"client_secret" => 'my client secret',
"grant_type" => 'authorization_code',
"code" => code,
"redirect_uri" => 'http://localhost:3000/receive_code/',
"scope" => 'names basic haplogroups relatives'})
response = https.request(request)
data = JSON.load response.read_body
return data["access_token"]
end

Ruby https POST with headers

How can I make a Https post with a header in Ruby with a json?
I have tried:
uri = URI.parse("https://...")
https = Net::HTTP.new(uri.host,uri.port)
req = Net::HTTP::Post.new(uri.path)
req['foo'] = bar
res = https.request(req)
puts res.body
The problem it was a json. This solve my problem. Anyway, my question was not clear, so the bounty goes to Juri
require 'uri'
require 'net/http'
require 'net/https'
require 'json'
#toSend = {
"date" => "2012-07-02",
"aaaa" => "bbbbb",
"cccc" => "dddd"
}.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['foo'] = 'bar'
req.body = "[ #{#toSend} ]"
res = https.request(req)
puts "Response #{res.code} #{res.message}: #{res.body}"
Try:
require 'net/http'
require 'net/https'
uri = URI.parse("https://...")
https = Net::HTTP.new(uri.host,uri.port)
https.use_ssl = true
req = Net::HTTP::Post.new(uri.path)
req['foo'] = bar
res = https.request(req)
puts res.body
Here's a cleaner way to use Net::HTTP. If you just want to get the response and throw other objects away this is quite useful.
require 'net/http'
require 'json'
uri = URI("https://example.com/path")
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
req = Net::HTTP::Post.new(uri)
req['Content-Type'] = 'application/json'
# The body needs to be a JSON string, use whatever you know to parse Hash to JSON
req.body = {a: 1}.to_json
http.request(req)
end
# The "res" is what you need, get content from "res.body". It's a JSON string too.
A secure-by-default example:
require 'net/http'
require 'net/https'
req = Net::HTTP::Post.new("/some/page.json", {'Content-Type' =>'application/json'})
req.body = your_post_body_json_or_whatever
http = Net::HTTP.new('www.example.com', 443)
http.use_ssl = true
http.ssl_version = :TLSv1 # ruby >= 2.0 supports :TLSv1_1 and :TLSv1_2.
# SSLv3 is broken at time of writing (POODLE), and it's old anyway.
http.verify_mode = OpenSSL::SSL::VERIFY_PEER # please don't use verify_none.
# if you want to verify a server is from a certain signing authority,
# (self-signed certs, for example), do this:
http.ca_file = 'my-signing-authority.crt'
response = http.start {|http| http.request(req) }
Its working, you can pass data and header like this:
header = {header part}
data = {"a"=> "123"}
uri = URI.parse("https://anyurl.com")
https = Net::HTTP.new(uri.host,uri.port)
https.use_ssl = true
req = Net::HTTP::Post.new(uri.path, header)
req.body = data.to_json
res = https.request(req)
puts "Response #{res.code} #{res.message}: #{res.body}"

Resources