I am just playing around with the OpenID protocol. I am trying to send Discovery request and retrieve the XRDS document from google . When I try to do it from the terminal using the curl, I am getting the following output
curl --url "https://www.google.com/accounts/o8/id"
<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)">
<XRD>
<Service priority="0">
<Type>http://specs.openid.net/auth/2.0/server</Type>
<Type>http://openid.net/srv/ax/1.0</Type>
<Type>http://specs.openid.net/extensions/ui/1.0/mode/popup</Type>
<Type>http://specs.openid.net/extensions/ui/1.0/icon</Type>
<Type>http://specs.openid.net/extensions/pape/1.0</Type>
<URI>https://www.google.com/accounts/o8/ud</URI>
</Service>
</XRD>
</xrds:XRDS>
When I try to do the same from the ruby code, It gives me a 302 error and the url to which it has moved points to the same request url.
<HTML>
<HEAD>
<TITLE>Moved Temporarily</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>Moved Temporarily</H1>
The document has moved here.
</BODY>
</HTML>
Code
require 'net/http'
require 'net/https'
require 'uri'
http = Net::HTTP.new(uri.host, uri.port)
response = Net::HTTP.get_response(URI.parse("http://www.google.com/accounts/o8/id"))
puts "#{response.read_body}"
How to get the XRDS through the code and why is it showing different outputs. Can someone explain it?Thanks
Google expects the https protocol, though in your ruby example you use http, hence the 302 error. The following snippet should get you the xrds document:
require 'net/http'
require 'net/https'
require 'uri'
uri = URI.parse('https://www.google.com/accounts/o8/id')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
puts "#{response.read_body}"
As you can see, when you fetch the document from ruby, it returns 302 status code, which means that you should look for location header and follow it, like curl does.
Another answer suggested just hardcoding the valid url, but that isn't a correct solution, since Google could make it return 302 as well and move the document somewhere else.
Not to mention that you should perform full Yadis discovery instead of hoping that you'll get an XRDS document from the url (because, for example, Google might decide that it's a good location for explanation of OpenID, and move the XRDS somewhere else using X-XRDS-Location header).
Related
I am using trello api to attach an image to a card. the documentation says
require 'uri'
require 'net/http'
url = URI("https://api.trello.com/1/cards/id/attachments")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new(url)
response = http.request(request)
puts response.read_body
After putting my key and my token, I tried to upload a file and the binary data goes in the url itself, not only it seems too ugly but it also doesn't work because the request is really too long. I've tried using multipart and rest client gems from in my code to upload and attach a file to a trello card but everytime I get errors like bad request or SSL errors, can anyone please give me a piece of code that really works? thanks
actually I am sending the image data via AJAX (I'm generating it from a charjs view), so the data sent is binary, it would be better if the solution upload an image from binary data.
Their documentation does indeed encourage you to add the whole encoded file object into the URL, which I also find ugly. I wonder if it will work to add it into the POST body instead? Try this:
request = Net::HTTP::Post.new(url)
request.set_form_data({file: put_encoded_file_contents_here})
I have a very simple API, that I would like to make a POST to using ruby and NOT using a GEM just the built in libraries net/http, uri, and openssl if needed.
Anyway, I am using the code below to make a very simple POST request but am getting some VERY strange results and was hoping someone else has seen this.
I have also tested the same request below in POSTMAN and NodeJS and BOTH work as expected, the only one I can not get to work is Ruby.
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://somesite.dev/devices")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new(url)
request["key"] = '1234567'
response = http.request(request)
puts response.read_body
The result is something I have not seen before: I am getting the header key twice... So the log to the API shows a query like this:
SELECT * FROM device where key = '1234567, 1234567' LIMIT ...
As stated above I can make the same request via POSTMAN or NodeJS and get the correct result.
NOTE: Because I have a local copy of the API I can test locally BUT it's not SSL it's all over http. When making the request locally it works just fine. So from what I can tell this issue only presents it self when SSL is introduced.
Any help would be amazing! Thanks!!
Ruby Version 2.2.1
The issue was with something I did not list in my initial question. The API was using AWS API Gateway, and HTTP_PROXY was enabled on the method causing this strange issue. After I removed HTTP_PROXY the issue cleared up and the above code worked!
Versions:
Ruby 2.2.4
Rails 4.2
Omniauth-oauth2 1.3.1
Omniauth-bnet 1.1.0
Issue:
Trying to complete the authorization and token request process to Blizzard's Battle Net Community API. While I can get the authorization_code returned, when I attempt to construct a POST back to the token endpoint it keeps telling me that its an invalid request/internal server error or just returns back the following object: <Net::HTTPFound 302 Found readbody=true> which has a blank string for a response body. Details for how Blizzard recommends handling the OAuth 2 process are located here: Battle.net OAuth 2 Guide. The omniauth-bnet gem is the one Blizzard suggested but doesn't seem to handle the entire OAuth authorization and token process but I'll freely admit I'm brand new when it comes to anything OAuth related so I could be wrong.
Any help you all can provide would be very welcome!
Controller Code:
def index
client_id = ENV[BNET_CLIENT_ID]
client_secret = ENV[BNECT_CLIENT_SECRET]
uri = URI('https://us.battle.net/auth/token?
redirect_uri=https%3A%2F%2f127%2f0%2f0%2f1%3A3001%2Fauth%2Fbnet%2Fcallback
&grant_type=authorization_code
&code=' + params["code"])
req = Net::HTTP::Post.new(uri)
req.basic_auth(client_id, client_secret)
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') {|http| http.request(req)}
#bnet_response = res.body
end
Process:
Click link on index.html page which triggers the authorization process to start by sending a GET request to https://us.battle.net/oauth/authorize?client_id=&client_secret=&redirect_uri=&response_type=code
BNet API accepts the request and redirects user to Battle.Net Login screen
User authorizes app and is redirected (via redirect_uri) back to the index page with query parameters for the authorization_code
My app SHOULD make a POST request using the controller code above and the response should contain the actual access token.
This is just some hastily cobbled together code while I'm trying to get this working. I'll clean it up once I get over this little speed bump. I wouldn't hardcode the URI and such normally, just getting frustrated with things.
Things I've tried:
Using Rest-Client : There's a callback redirect that it can't handle apparently
Testing Postman : When using their OAuth 2 Authorization it works just fine, also works fine if I use Postman to get the authorization code (GET) and token (POST), so I'm assuming things work on the Blizz side and my code just sucks.
config/routes.rb
Rails.application.routes.draw do
root to: 'pages#index'
get '/auth/:provider/callback', to: 'pages#index'
end
I'm not familiar with the Battle.net API, however reading your process it seems you are getting an authorization code back from the redirect in the form of a query parameter (accessed by params[:code]) correct?
You also mention that this works using Postman indicating the flaw must be somewhere in the code.
I would suggest using the following snippet and let me know if it works. I would encourage using puts url after url = ... code to ensure the URI looks exactly as you want it (and has the correct code, client id, secret, redirect_uri).
require 'uri'
require 'net/http'
# Remember to change the redirect uri to match yours
redirect_uri = 'https://my-domain-name.com/auth/bnet/callback'
# Double check the environment variable names for BNET ID / Secret
url = URI("https://us.battle.net/oauth/token?redirect_uri=#{redirect_uri}&code=#{params[:code]}" \
"&grant_type=authorization_code&scope=wow.profile&client_id=#{ENV['BNET_CLIENT_ID']}" \
"&client_secret=#{ENV['BNET_CLIENT_SECRET']}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new(url)
response = http.request(request)
puts response.read_body
Ensure your domain is accessible over https as this seems to be required.
I've searched around a lot and seen various answers. Some seem like they may be outdated, and others use gems (omnicontacts) that I can't seem to get working with devise.
In my situation, I already get an oauth token from Google successfully. Now I'm trying to send a get request to the url given by Google to get all my contacts. I'm able to do this in Google's oauth2 playground, but not from my rails app.
Here is the relevant code:
require 'net/http'
require 'json'
class User < ActiveRecord::Base
def get_google_contacts(auth_token)
uri = URI.parse("https://www.google.com/m8/feeds/contacts/default/full?oauth_token=#{auth_token}&max-results=50000&alt=json")
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
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
contacts = JSON.parse(response.body)
puts contacts
end
end
Notebooks Controller: this is where I want a user to be able to access their contacts from Google.
def show
#contacts = current_user.get_google_contacts(current_user.oauth_token)
end
Here is the error log I get in my local:
JSON::ParserError in NotebooksController#show
746: unexpected token at '<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Error
401
(Client Error)!!1</title>
<p><b>401.</b>
<ins>That's an error.</ins></p>
<p>There was an error in your request.
<ins>That's all we know.</ins></p></body></html>'
I think I may be using incompatible techniques to parse the xml I get from Google into json, but that is basically what I want to do. The only Rails related documentation I found in Google API documentation was dated 2009, but it mentioned the gdata gem. Should I be using that?
Thank you so much for any help on this.
EDIT
This is the response I get from Google Oauth2 Playground on a 200 ok (https://developers.google.com/oauthplayground/):
Content-type: application/atom+xml; charset=UTF-8
-content-encoding: gzip
<?xml version='1.0' encoding='UTF-8'?><feed xmlns='http://www.w3.org/2005/Atom'
xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/'
xmlns:gContact='http://schemas.google.com/contact/2008'
xmlns:batch='http://schemas.google.com/gdata/batch' xmlns:gd='http://schemas.google.com/g/2005'>
<id>kaustubh.bhardwaj86#gmail.com</id><updated>2014-01-13T18:34:22.842Z</updated><category
scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/contact/2008#contact'/>
<title type='text'>Kaustubh Bhardwaj's Contacts</title>
EDIT #2
Ok, I've isolated my problem. I'm getting Net::HTTPUnauthorized on my get request. Here is the updated code for the get request I'm making to Google Contacts API:
uri = URI.parse("https://www.google.com/m8/feeds/contacts/default/full?max-results=50000")
# headers = { "access_token" => "#{auth_token}" }
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)
request.initialize_http_header({ "access_token" => "#{auth_token}" })
response = http.request(request)
puts response.code
puts response
That is the same url I am using in Google Oauth2 playground.
I suspect you're setting the token incorrectly. It is more normal to set it in an http header
Authorization: Bearer 0b79bab50daca910b000d4f1a2b675d604257e42
If you set it in the URL, I believe it's access_token=, rather than your oauth_token= but since I never use it this way, I might be wrong.
I am trying to query some XML from a hotel database using Ruby, and am getting the results:
403 Developer Inactive
I used the code:
require 'net/http'
url = URI.parse('URL of the HTTP query')
req = Net::HTTP::Get.new(url.path)
res = Net::HTTP.start(url.host, url.port) {|http|
http.request(req)
}
puts res.body
I would give the actual URL, but it contains the API key/etc...so I really cannot divulge it.
Is there anything wrong with the code or might it be on the company needing to activate the key?
Thanks
403 is the HTTP status code FORBIDDEN, which leads me to believe you have a problem authenticating your API request, maybe because of a wrong key or something.