HTTParty with Proxy - ruby

I am on heroku trying to access an API that requires my apps ip to be whitelisted. So, I used the heroku add-on proximo to get host/ip for the api's whitelist.
A quick test I set up to test connectivity using HTTParty is failing.
class FakeRequest
include HTTParty
http_proxy 'XX.XXX.XX.XX', 80, 'user', 'pass'
def set_defaults
{:api_key=>"BLARG_BLARG",
:login_name=>"user",
:method => "do_something",
:response_format => "json",
:v => "1.0",
:login_password=>"pass"}
end
def make_post
HTTParty.post "https://test.com", :query => set_defaults
end
end
Going this like:
req = FakeRequest.new
req.make_post
Returns an error message from the api complaining that the source IP is not whitelisted. I looked at the source IP and it is not using the proxy. How can I make HTTParty post using the proxy and not my ISP's IP.

This is the module I built to do just this:
module ProximoParty
PROXIMO = URI.parse(ENV['PROXIMO_URL'])
def self.included(base)
base.send(:include, HTTParty)
base.http_proxy(PROXIMO.host, 80, PROXIMO.user, PROXIMO.password)
end
end
This uses the PROXIMO URL as it is added to your heroku app when you install the addon. So you can drop this file into your app and include ProximoParty into your FakeRequest class instead of HTTParty and it should "just work".
It looks like my code is doing the same thing your code is doing though, so what I'm guessing is that you may not be manually carrying over the credentials properly for proximo.
I ran into a similar problem where it wasn't quite working for me right off the bat. I believe the problem was that I was getting tripped up that there looked to be a "proxy:" protocol in the proximo URL but that was just the username part of the URL.
Anyways, this may or may not help, but please let me know if it does!

It blows my mind how many answers you can get on this question that don't work. Here is how I got it working:
HTTParty::Basement.http_proxy('localhost', 8000, nil, nil)
Put this as a global override in your env.rb file. That's it. Done.

With recent versions of HTTParty it's as simple as using the
http_proxy method:
class Foo
include HTTParty
http_proxy 'http://example.com', 80, 'user', 'pass'
end

HTTParty can use a proxy server address using the following proxy options.
[:+http_proxyaddr+:] Address of proxy server to use
[:+http_proxyport+:] Port of proxy server to use.
[:+http_proxyuser+:] User for proxy server authentication
[:+http_proxypass+:] Password for proxy server authentication.

As you configure HTTParty as an inclusion in your module, you have to call HTTParty method through your class, so:
def make_post
self.class.post "https://test.com", :query => set_defaults
end

I included a link because it include lengthy setup steps. But point taken about the link changing and page becoming invalid. We used squid proxy server on a EC2 AMI and called it a day.

I think you need to call the local httparty, like this:
def make_post
self.post "https://test.com", :query => set_defaults
end

Related

Intercept WEBrick request

I have a web app that runs on different pieces of hardware, that for the most part consists of smart TVs and set-top boxes.
My web app contains a ruby script to setup the app for local debugging. This script builds my app, listens for file changes, and hosts the app using a simple WEBrick server.
Now I'm running into a problem on a specific piece of hardware. This hardware expects to get a success response from a POST request to a health_check API running on the same host as the web app, before it will load up the web app.
I'm simply hoping to intercept this request and spoof it so that the hardware will load my client. So far I've gotten as far as this:
def start_server
require 'webrick'
root = File.expand_path 'public'
request_callback = Proc.new { |req, res|
if req.path =~ /health_check/
# return 200 response somehow?
end
}
server = WEBrick::HTTPServer.new :Port => 5000, :DocumentRoot => root, :RequestCallback => request_callback
server.start
end
I can modify the response object to set status to 200, but it still ends up returning a 404.
You don't need to "intercept" all requests and check for a specific path. You simply want mount_proc, to handle a specific route with a proc.
Add the following before server.start:
server.mount_proc '/health_check' do |req, res|
res.body = 'what what' # your content here
end
You'll probably want to wrap this in a check to determine if you're running on whatever custom hardware requires this behavior.
See Custom Behavior in the WEBrick docs.

Simplest method of enforcing HTTPS for Heroku Ruby Sinatra app

I have an app I created on Heroku which is written in Ruby (not rails) and Sinatra.
It is hosted on the default herokuapp domain so I can address the app with both HTTP and HTTPS.
The app requests user credentials which I forward on to an HTTPS call so the forwarding part is secure.
I want to ensure my users always connect securely to my app so the credentials aren't passed in clear text.
Despite lots of research, I've not found a solution to this simple requirement.
Is there a simple solution without changing my app to Ruby rails or otherwise?
Thanks,
Alan
I use a helper that looks like this:
def https_required!
if settings.production? && request.scheme == 'http'
headers['Location'] = request.url.sub('http', 'https')
halt 301, "https required\n"
end
end
I can then add it to any single route I want to force to https, or use it in the before filter to force on a set of urls:
before "/admin/*" do
https_required!
end
Redirect in a Before Filter
This is untested, but it should work. If not, or if it needs additional refinement, it should at least give you a reasonable starting point.
before do
redirect request.url.sub('http', 'https') unless request.secure?
end
See Also
Filters
Request Object
RackSsl::Enforcer

upload file to box api v2

i am trying to upload a file to box.com with their v2 api.
i am able to successfully upload a file with curl, but cannot upload a file from my rails application. i am passing my upload function the correct folder id and file is a tempfile object created by a form upload in my app.
here is the successful curl command
curl https://upload.box.com/api/2.0/files/data -H "Authorization: BoxAuth api_key=API_KEY&auth_token=TOKEN" -F contract=#test.png -F folder_id=387656851 -ssl3
and here is my ruby code
class BoxApi
require 'httmultiparty'
include HTTMultiParty
ssl_version :SSLv3
def initialize
#key = API_KEY
#token = TOKEN
end
def upload_file(folder_id,file,filename,content_type)
File.open(file) do |open_file|
response = self.class.post('https://upload.box.com/2.0/files/data', :query => {
:file => open_file,
:folder_id => folder_id
}, :headers => {'Authorization' => "BoxAuth api_key=#{#key}&auth_token=#{#token}"})
p response
end
end
i get an html page back from box with this text
It appears that your firewall may be blocking Box or you are encountering an error.Please contact your IT administrator to configure your firewall to recognize all sub-domains of .box.com, .box.com and .boxcdn.net. The ports that should be opened for these domains are 80 and 443.If that does not resolve the issue, then please submit a support ticket at https://www.box.com/help.
any ideas why the curl command would be working but not the ruby code?
Despite from being late, this could be useful for people who came across this question.
There is a gem ruby-box to use with Box service at the 2.0 version of their API.
This works properly for me
require 'httmultiparty'
class SomeClient
include HTTMultiParty
base_uri 'https://api.box.com/2.0'
end
response = SomeClient.post('/files/data',
:headers => { 'authorization' => 'BoxAuth api_key={YOUR API KEY}&auth_token={YOUR TOKEN' },
:body => { :folder_id => '0', :somefile => File.new('large.jpeg')}
)
I would try to verify that
You can make non-upload API calls (i.e. GET /folders/0)
If not, check your firewall settings.
Sean already covered this in his answer but I'll highlight it explicitly. We had some issues using the https://upload.box.com URL which is no longer recommended by box. I'd recommend trying the https://api.box.com/2.0 URL and seeing if that it changes your results.
Worst case I'd try capturing my packets using a packet analyzer like wireshark and looking for differences between the two cases.

How can I make ruby's xmlrpc client ignore SSL certificate errors?

When access an XML-RPC service using xmlrpc/client in ruby, it throws an OpenSSL::SSL::SSLError when the server certificate is not valid. How can I make it ignore this error and proceed with the connection?
Turns out it's like this:
xmlrpc = ::XMLRPC::Client.new("foohost")
xmlrpc.instance_variable_get(:#http).instance_variable_set(:#verify_mode, OpenSSL::SSL::VERIFY_NONE)
That works with ruby 1.9.2, but clearly is poking at internals, so the real answer is "the API doesn't provide such a mechanism, but here's a hack".
Actually the client has been updated, now one has direct access to the http connection:
https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/41286/diff/lib/xmlrpc/client.rb
xmlrpc.http.verify_mode = OpenSSL::SSL::VERIFY_NONE
But better set ca_file or ca_path.
Still I see no option to apply such config to _async calls.
Update: found a workaround by monkey patching the client object:
xmlrpc_client.http.ca_file = #options[:ca_file]
xmlrpc_client.instance_variable_set(:#ca_file, #options[:ca_file])
def xmlrpc_client.net_http(host, port, proxy_host, proxy_port)
h = Net::HTTP.new host, port, proxy_host, proxy_port
h.ca_file = #ca_file
h
end
So you need both, the older approach and the monkey patching. We add also an instance variable, otherwise the new method cannot see the actual value.

401 error with Ruby OAuth for Twitter

xI've been working for days to get Twitter to authenticate with Ruby, but I'm not having any luck.
My first attempt was something like this:
class TwitterController < ApplicationController
def index
#callback_url = "http://dev.twipler.com:3000/twitter/auth"
#auth= TwitterOAuth::Client.new( :consumer_key => "xxx", :consumer_secret => "xxxxxxxxxxxxxxxxx" )
#rtoken = #auth.request_token :oauth_callback => #callback_url
#token = #rtoken.token
#secret = #rtoken.secret
#link = #rtoken.authorize_url
session['token' ] = #token
session['secret'] = #secret
redirect_to #link
end
def auth
#auth.authorize_from_request(session[:rtoken], session[:rsecret], params[:oauth_verifier])
end
end
And a very similar way but with the Twitter gem, and the same with the OAuth gem directly. No matter what OAuth::Consumer::token_request dies with a 401 error.
So, out of desperation I attempted to git clone Snitter, add my Twitter creds, and try it, but it too dies with a 401.
I've tried using localhost:300/twitter/auth, http://dev.twipler.com:3000/twitter/auth, and a bit.ly for each of the former 2. Nothing works.
Any help?
EDIT: Of course I would forget to do the most logical thing to do and delete my secrets. (They've been changed ;)).
You may want to edit your consumer secret out. With that, anyone can make requests on behalf of your app.
That said, make sure your system time is synced to an ntp server. If your system time has drifted fast or slow, OAuth requests will fail, since their include a timestamp and relatively short TTL. I had this exact problem a while back.
Failing that, you can crack open the oauth gem and turn on HTTP debugging, which will show you the full HTTP transaction including any error message returned.

Resources