OAuth with Digg API - ruby-on-rails

I'm attempting to get Rails to play nice with the Digg API's OAuth. I'm using the oauth gem (ruby one, not the rails one).
My code looks approximately like this:
#consumer = OAuth::Consumer.new(API_KEY, API_SECRET,
:scheme => :header,
:http_method => :post,
:oauth_callback => "http://locahost:3000",
:request_token_url => 'http://services.digg.com/1.0/endpoint?method=oauth.getRequestToken',
:access_token_url => 'http://services.digg.com/1.0/endpoint?method=oauth.getAccessToken',
:authorize_url => 'http://digg.com/oauth/authorize')
#request_token = DiggController.consumer.get_request_token({
:oauth_callback => "http://xx.xxx.xxx.x:3000/digg/callback"
}, {
'Content-Type' => 'application/x-www-form-urlencoded'
})
session[:request_token] = #request_token.token
session[:request_token_secret] = #request_token.secret
redirect_to #request_token.authorize_url
Which is by-the-book in terms of what the gem documentation gave me. However, Digg spits a "400 Bad Request" error back at me when #consumer.get_request_token is called. I can't figure out what I'm doing wrong. Any ideas?
Edit: Code updated and Wireshark output added. My error is now "401 Authorization Required".
Output from Wireshark:
POST /1.0/endpoint?method=oauth.getRequestToken HTTP/1.1
Accept: */*
Connection: close
User-Agent: OAuth gem v0.3.6
Content-Type: application/x-www-form-urlencoded
Authorization: OAuth oauth_nonce="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
oauth_callback="http%3A%2F%2Fxx.xxx.xxx.x%3A3000%2Fdigg%2Fcallback",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="1268687137",
oauth_consumer_key="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
oauth_signature="xxx%2Bxxxxxxxxxxxxxxx%2Fxxxxxxx%3D", oauth_version="1.0"
Content-Length: 48
Host: services.digg.com
Content-Type=application%2fx-www-form-urlencoded
HTTP/1.1 401 Authorization Required
Date: Mon, 15 Mar 2010 21:05:37 GMT
Server: Apache
X-Powered-By: PHP/5.2.9-digg8
Cache-control: private
X-RateLimit-Current: 1
X-RateLimit-Max: 1000
X-RateLimit-Reset: 3600
X-Digg-Api-Version: 1.0
Accept-Ranges: bytes
Content-Length: 111
Keep-Alive: timeout=5, max=9998
Connection: Keep-Alive
Content-Type: text/xml;charset=utf-8
<?xml version="1.0" encoding="UTF-8"?>
<error code="5001" message="Invalid
signature" timestamp="1268687137"/>

Incidentally, the callback parameter should not be localhost:3000 but rather your public IP address (making sure to also open up port 3000 for external connections in your computer and/or router firewall(s)), or be left to the default (out-of-band.)
Examine the contents of the OAuth::Unauthorized exception which gets thrown (or use a sniffer such as tcpdump or Wireshark) to get additional details about the HTTP 400 error (they are probably having issues with some of your parameters.)

Related

Ruby Rest-client keeps correcting the uri

I'm using rest-client to make a post request to a certain address. Unfortunately rest-client keeps correcting the web adres from 'https' to 'http'. Which then gives back an error.
I already looked at the documentation whether this maybe was a setting for the gem. Anyone knows how I can 'force' rest-client to access the desired address.
Thx in advance!
used code is:
uri = 'https://sandbox.api.online.unit4.nl/V19/OAuth/Token'
payload = {
code: params[:code],
client_id: '#{#client_id}',
client_secret: '#{#client_secret}',
redirect_uri: '#{#client_redirect_url}',
grant_type: 'authorization_code'
}
response = RestClient::Request.execute(method: :post, url: uri, headers: {params: payload})
curl:
> GET /V19/OAuth/Token HTTP/1.1
> Host: sandbox.api.online.unit4.nl
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 400 Bad Request
< content-length: 27
< content-type: application/json; charset=utf-8
< date: Wed, 06 Dec 2017 15:21:44 GMT
< p3p: CP="NON CUR OTPi OUR NOR UNI"
< server: Microsoft-IIS/7.5
< x-aspnetmvc-version: 5.2
< cache-control: no-cache, no-store, max-age=0, must-revalidate
< access-control-allow-origin: *
< x-powered-by: ASP.NET
< x-aspnet-version: 4.0.30319
< pragma: no-cache
< Set-Cookie: PD_STATEFUL_88eb7504-dfe9-11e2-8624-005056af4a32=sandbox.api.online.unit4.nl; Path=/
< Set-Cookie: LB_online_unit4=1493375404.20480.0000; path=/
Could be that your variables aren't getting interpolated. With single quotes '#{#variable}' doesn't work. Try switching the single quotes to double quotes ('' => ""). What is happening is that instead of sending the actual client id and secret, you are sending the string #{#client_id}.
Try
uri = 'https://sandbox.api.online.unit4.nl/V19/OAuth/Token'
payload = {
code: params[:code],
client_id: #client_id,
client_secret: #client_secret,
redirect_uri: #client_redirect_url,
grant_type: 'authorization_code'
}
response = RestClient::Request.execute(method: :post, url: uri, headers: {params: payload})

string interpolation in Get URI with httparty issue

So I was using the splunk rest api to generate the search id thorugh post and then get the search results through a get request.
I am using httpparty, & this is my post and get request as follows:
def sid
self.class.post(
"/services/search/jobs",
headers: {'Content-Type' => 'application/json'},
basic_auth: #auth
).parsed_response
end
The generated sid looks like this:
1503402217.608
I make the necessary get request as follows:
def results(sid)
self.class.get(
"/services/search/jobs/#{sid}/results/",
headers: {'Content-Type' => 'application/json', 'Accept' => 'text/html'},
basic_auth: #auth
)
end
The above request gives a 204 no content.
However if I manually paste the sid in my code and run it, i get results back.
for eg: "/services/search/jobs/1503402217.608/results/"
So my question is how can interpolate the above to get results back.
EDIT: my dyamic get request looks this in the console:
<- "GET /services/search/jobs/1503402217.608/results/ HTTP/1.1\r\nContent-Type: application/json\r\nAccept: text/html\r\nAuthorization: Basic something==\r\nConnection: close\r\nHost: server:8089\r\n\r\n"
-> "HTTP/1.1 204 No Content\r\n"
-> "Date: Tue, 22 Aug 2017 11:43:37 GMT\r\n"
-> "Expires: Thu, 26 Oct 1978 00:00:00 GMT\r\n"
-> "Cache-Control: no-store, no-cache, must-revalidate, max-age=0\r\n"
-> "Content-Length: 0\r\n"
-> "Vary: Cookie, Authorization\r\n"
-> "Connection: Close\r\n"
-> "X-Frame-Options: SAMEORIGIN\r\n"
-> "Server: Splunkd\r\n"
-> "\r\n"
EDIT: Just so you know, this how i am parsing the sid in the first place before sending it as an argument to the GET request:
sid.parsed_response["sid"]

Grape API service response 400 bad request at Rails 4 when I sending a json request to it using curl

I don't know how to solve the 400 bad request that API service gives back to me. All I need are receiving json responses from API service, and the API service could communicate with many-type devices.
I'm building an all-json-request API service according to tutorial of Grape gem at GitHub.com https://github.com/ruby-grape/grape and GitHub.io http://intridea.github.io/grape/docs/index.html . After I sending a json request to the API service: localhost:3000/specified_vegetables using curl, which is construct with Grape gem version 0.8.0 and located at new empty Rails 4.1.1 project, the API service give back the response:
* Trying ::1...
* connect to ::1 port 3000 failed: Connection refused
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET /specified_vegetables/ HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.43.0
> Accept: application/json
> Content-Type:application/json
> Content-Length: 55
>
* upload completely sent off: 55 out of 55 bytes
< HTTP/1.1 400 Bad Request
< Content-Type: application/json
< Content-Length: 56
< Cache-Control: no-cache
< X-Request-Id: 87231177-b8f8-4084-b0ef-19445fa42fab
< X-Runtime: 0.220101
< Server: WEBrick/1.3.1 (Ruby/2.2.1/2015-02-26)
< Date: Thu, 01 Oct 2015 13:35:46 GMT
< Connection: Keep-Alive
<
* Connection #0 to host localhost left intact
{"error":"transaction_date is missing, name is missing"}
My curl request command: curl -H 'Accept: application/json' -H 'Content-Type:application/json' -X GET http://localhost:3000/specified_vegetables/ -d '{"transaction_date" : "20131031", "name" : "金針筍"}' -v
In my database, there is one record matched the conditions I've queried.
The log of rails server runs and it also includes the curl request:
=> Booting WEBrick
=> Rails 4.1.1 application starting in development on http://0.0.0.0:3000
=> Run `rails server -h` for more startup options
=> Notice: server is listening on all interfaces (0.0.0.0). Consider using 127.0.0.1 (--binding option)
=> Ctrl-C to shutdown server
[2015-10-01 21:35:43] INFO WEBrick 1.3.1
[2015-10-01 21:35:43] INFO ruby 2.2.1 (2015-02-26) [x86_64-darwin10]
[2015-10-01 21:35:43] INFO WEBrick::HTTPServer#start: pid=27004 port=3000
Started GET "/specified_vegetables/" for 127.0.0.1 at 2015-10-01 21:35:46 +0800
The following are my environment settings and codes.
The directory structure of API files in rails app:
RailsApp.root/app/api/agriculture_transaction/base.rb
RailsApp.root/app/api/agriculture_transaction/v1/specified_vegetables.rb
Code of base.rb:
module AgricultureTransaction
class Base < Grape::API
format :json
version 'v1'
mount AgricultureTransaction::V1::SpecifiedVegetables
mount AgricultureTransaction::V1::OverviewVegetables
end
end
Code of specified_vegetables.rb
module AgricultureTransaction
module V1
class SpecifiedVegetables < Grape::API
format :json
default_format :json
version 'v1', using: :header, vendor: 'twitter'
resource :specified_vegetables do
desc "Get all transaction prices of all items today."
get :today do
SpecifiedVegetable.where(transaction_date: Date.today).find_in_batches do |vegetables|
vegetables
end
end
desc "Get transaction prices of delegated item in a delegated day."
params do
requires :transaction_date, type: Date, desc: 'code'
requires :name, type: String
end
get do
SpecifiedVegetable.where(transaction_date: params[:transaction_date], name: params[:name]).find_in_batches do |vegetables|
vegetables
end
end
end
end
end
end
The only one model in Rails app is SpecifiedVegetable.rb:
class SpecifiedVegetable < ActiveRecord::Base
self.table_name = "specified_vegetable"
end
In config/application.rb file, I add two lines in rails Application class:
config.paths.add "app/api", glob: "**/*.rb"
config.autoload_paths += Dir["#{Rails.root}/app/api/*"]
In config/routes.rb file, I add one line in Rails.application.routes.draw:
mount AgricultureTransaction::Base => '/'
Above of all are information I could provide. Please help me to solve this problem or give me some keywords to search. I've find some articles, but they could not help me.

Rspec test for GZIPed response

I recently enabled GZIP on my Rails 4 app following this Thoughtbot blog post and I also have added use Rack::Deflater to my config.ru file as suggested by this post. My Rails app seems to be serving compressed content, but when I test for it using RSpec the test fails because response.headers['Content-Encoding'] is nil.
Here is my application.rb:
module MyApp
class Application < Rails::Application
# Turn on GZIP compression
config.middleware.use Rack::Deflater
end
end
Here is my spec:
require 'rails_helper'
describe GeneralController, type: :controller, focus: true do
it "a visitor has a browser that supports compression" do
['deflate', 'gzip', 'deflate,gzip', 'gzip,deflate'].each do |compression_method|
get 'about', {}, {'HTTP_ACCEPT_ENCODING' => compression_method }
binding.pry
expect(response.headers['Content-Encoding']).to be
end
end
it "a visitor's browser does not support compression" do
get 'about'
expect(response.headers['Content-Encoding']).to_not be
end
end
When I run curl --head -H "Accept-Encoding: gzip" http://localhost:3000/ I get the following output:
HTTP/1.1 200 OK
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Ua-Compatible: chrome=1
Content-Type: text/html; charset=utf-8
Vary: Accept-Encoding
Content-Encoding: gzip
Etag: "f7e364f21dbb81b9580cd39e308a7c15"
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: 3f018f27-40ab-4a87-a836-67fdd6bd5b6e
X-Runtime: 0.067748
Server: WEBrick/1.3.1 (Ruby/2.0.0/2014-02-24)
When I load the site and look at the Network tab of the inspector I can see that the response size is smaller than before, but my test still fails. I'm not sure if I'm missing a step here with my test or if there is an issue with my implementation of Rack::Deflater.
As #andy-waite pointed, RSpec controller specs are not aware of middleware, but that's why, since RSpec 2.6 we have request specs.
Request specs are, according to the docs:
designed to drive behavior through the full stack
Therefore, using RSpec > 2.6 request specs, your code should look like:
require 'rails_helper'
describe GeneralController, type: :request, focus: true do
it "a visitor has a browser that supports compression" do
['deflate', 'gzip', 'deflate,gzip', 'gzip,deflate'].each do |compression_method|
get 'about', {}, {'HTTP_ACCEPT_ENCODING' => compression_method }
binding.pry
expect(response.headers['Content-Encoding']).to be
end
end
it "a visitor's browser does not support compression" do
get 'about'
expect(response.headers['Content-Encoding']).to_not be
end
end
RSpec controller specs are wrapped around Rails functional tests, which are not aware of middleware:
Making Rails tests aware of Rack middleware outside Rails's internal chain

from_remote_tag sent request http post instead of ajax XMLHTTP request

I define a submit button with form_remote_tag,
<div class="form_row">
<% form_remote_tag :url => {:controller => '/group', :action => 'addgroup'}, :update => 'activitypage' do %>
<%= submit_tag "Add!", :class => "submit" %>
<% end %>
I used fiddler and confirm the rails code was translated into ajax request,
u003Cform action=\"/group/addgroup\" method=\"post\" onsubmit=\"new Ajax.Request('/group/addgroup', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\"\u003E\n \u003Cinput class=\"submit\" name=\"commit\" type=\"submit\" value=\"Add!\" /\u003E\n \u003C/form\u003E\n \u003C/div\u003E\n\u003C/fieldset\u003E \n\u003C/form\u003E\n");
$("activitypage").visualEffect("highlight");
however, when I clicked the button, the client (IE 8) browser actually sent out a http post request (see below) instead of XMLHTTPRequest, thus my javascript reponse was declined. Any idea? Thanks in advance.
POST http://192.168.1.31:3000/group/addgroup HTTP/1.1
Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, application/x-ms-application, application/x-ms-xbap, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-silverlight, /
Referer: http://192.168.1.31:3000/mywebapp
Accept-Language: en-us
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB6.5; .NET CLR 1.0.3705; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: 192.168.1.31:3000
Content-Length: 84
Connection: Keep-Alive
Pragma: no-cache
Cookie: remember_me=1; _session_id=2ba880449df83115d15bab29b3c8ab30; authorization_token=6419794165b8169cfff54053bddb40c9f0405782
Who declined the response?
Your browser shouldn't ever send a XMLHTTPRequest as the actual HTTP method. Your choices are limited to GET and POST (plus HEAD, PUT, DELETE).
An AJAX request should actually set a header that then gets check:
'X-Requested-With' = 'XMLHttpRequest'
The actual HTTP method used will be GET or POST.
when the server sent back a javascript page for ajax page replacement, the browser pop a window for file download due to unaccepted page format. I expected that the submit button will send a ajax request with accepting javascript page. But it didnot. Why?
below is the response from server after receiving the submit request?
HTTP/1.1 200 OK
Connection: close
Date: Wed, 18 Aug 2010 02:26:31 GMT
Set-Cookie: _session_id=2ba880449df83115d15bab29b3c8ab30; path=/
Status: 200 OK
X-Runtime: 0.71081
ETag: "c4825b6e144b125ce655259083a12eff"
Cache-Control: private, max-age=0, must-revalidate
Server: Mongrel 1.1.5
Content-Type: text/javascript; charset=utf-8
Content-Length: 17195
try {
Element.update("activitypage", "\u003Ch1\u003EGroup\u003C/h1\u003E\n\u003Cscript src=\"/javascripts/prototype.js?1258680672\" type=\"text/javascript\"\u003E\u003C/script\u003E\n\u003Cscript src=\"/javascripts/effects.js?1258680672\" type=\"text/javascript\"\u003E\u003C/script\u003E\n\u003Cscript src=\"/javascripts/dragdrop.js?1258680672\" type=\"text/javascript\"\u003E\u003C/script\u003E\n\u003Cscript src=\"/javascripts/controls.js?1258680672\" type=\"text/javascript\"\u003E\u003C/script\u003E\n\u003Cscript src=\"/javascripts/application.js?1258680672\" type=\"text/javascript\"\u003E\u003C/script\u003E\n\u003Cbr\u003E\n\n\u003Ctable border=\"0\" ....

Resources