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
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})
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"]
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.
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
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\" ....