Using Shoes and download over https gives ssl errors - ruby

In a shoes application am trying to download stuff from some internal websites. I get this error
Error in /tmp/selfgz14214/ruby/lib/net/protocol.rb line 66
undefined method 'closed?' for #<OpenSSL::SSL::SSLSocket:0xb6af94f0>
I got the above error for this code. This give the above error if used from Shoes.
require 'net/http'
require 'net/https'
require 'rexml/document'
class Blogs
attr_reader :Connection
def initialize
#Connection = Net::HTTP::new("someInternalWebSite", 443)
#Connection.use_ssl = true
end
def get_blogs
doc = REXML::Document.new #Connection.get('/weblogs/feed/entries/atom').body
blogs = Array.new
# ----- some crap to parse the blogs
return blogs
end
end
Note this problem only happens when run from inside shoes.
Also using the inbuilt download method in shoes it doesn't return, not even start event gets raised. The following is the code for that
download "https://internalWebsite/weblogs/feed/entries/atom",
:start => lambda {
alert "hello"
},
:progress => lambda {
alert "progress"
},
:finish => lambda {
alert "finish"
}

I haven't worked with ( or indeed heard of ) shoes, but when I have had problems with accessing stuff over HTTPS in Ruby it has often been a case of not having the certificate set up properly.
My experience with this was a couple of years ago now but it may be worth doing a bit of experimentation just to check that you can actually make a regular SSL connection with that code. I would expect that you would at least need to tell it where to find the client certificate or that it doesn't need a client certificate at all.
I also recall that I needed to use http-access2 rather than the regular http library.
As I say, I'm sure things have moved on since I was trying to do this, but most of the problems I found relating to ssl connections were certificate related.

Shoes doesn't support HTTPS in the current version.

Related

Requesting An Access Token from Google API Returns 302

I'm trying to get an access token from Google API in my Ruby on Rails app, as part of an overall goal of setting up a raketask. I am able to get an Auth Code fine, but when I make a post request to get an access token, I am getting a 302 error. I'll describe my current code first, and afterward list how I've tried to solve the problem so far.
Current code:
#users_controller
def auth_access
client = Signet::OAuth2::Client.new(
:authorization_uri => 'https://accounts.google.com/o/oauth2/auth',
:token_endpoint_uri => 'https://accounts.google.com/o/oauth2/token',
:client_id => ENV['OAUTH_CLIENT_ID'],
:client_secret => ENV['OAUTH_CLIENT_SECRET'],
:scope => 'https://www.googleapis.com/auth/analytics.readonly',
:redirect_uri => 'http://localhost:3000/google/auth_callback'
)
redirect_to client.authorization_uri.to_s
end
This part works fine so far. It redirects to the consent page, and when the user agrees it then redirects them to the page with the auth code in the url parameters. Next I take that auth code and try to make a POST request to API for an access token:
#users_controller
def auth_callback
http = Net::HTTP.new('accounts.google.com')
path = '/o/oauth2/token'
data = "code=#{params['code']}&client_id=#{ENV['OAUTH_CLIENT_ID']}&client_secret=#{ENV['OAUTH_CLIENT_SECRET']}&redirect_uri=http://localhost:3000/auth_final&grant_type=authorization_code"
response = http.post(path, data)
end
This when I run into a problem. The Google API returns a 302, and includes a message saying something akin to "we moved to 'https://accounts.google.com/o/oauth2/token'".
Here's how I've tried to fix the problem so far:
I assumed that the problem was that the http.post method is making a call to an http and not https.
I've tried including
http.use_ssl = true
http.ssl_version = :SSLv3
This returns the error "SSL_connect returned=1 errno=0 state=SSLv3 read server hello A: wrong version number".
I can take a guess at what this means, but I am still unsure of what the actual problem is and how to solve it. Googling the error message has not been a help.
In a similar vein, I tried using gems to make the https call for me, in particular HTTParty and Typheous, although I was not able to make any progress with them (and am still not even sure that it's an http/https problem).
I've tried using the Signet-Rails gem. This was the most productive method by far, making a successful API call and returning the information. However, it either wasn't saving the refresh token or I cannot find where it is being saved. As I need access to that token to run the rake tasks, I gave up on Signet-Rails.
I tried using Legato, and was constantly running into various problems. Overall, Legato left me with the impression that it did not integrate getting the auth code, consent and tokens into the app, instead requiring the developer to set those up in advance outside of the app's scope. I want to be able to set up the auth code as part of the app. If I am understanding Legato properly, then it is not the gem I need.
I've also tried other various odds and ends but to no avail. The above solutions were the tactics I kept coming back to. Primarily I'm looking for an answer to what is going wrong in my code, and what is the best avenue to fix it (and if I was going down the right track with any of my attempted solutions above, which one?)
Thanks for taking the time to read this and answer!
(on a complete sidenote, those last three list items should be 2, 3, 4, but the stackoverflow text editor thinks it knows better than me...)
Specify the port:
http = Net::HTTP.new('accounts.google.com', 443)
Source: SSL Error on HTTP POST (Unknown Protocol)

Writing unit tests in Ruby for a REST API

I've written a basic REST API using sinatra.
Does anyone know the best way to write tests for it? I would like to do so using Ruby.
I've done my initial testing using curl. But I'd like to do something more robust. This is my first API - is there anything specific I should be testing?
The best way is a matter of opinion :) Personally, I like simple and clean. With tools like minitest, Watir and rest-client, you can put together a very simple test of both your REST interface as well as testing your web service through actual browsers (all major browsers are supported).
#!/usr/bin/ruby
#
# Requires that you have installed the following gem packages:
# json, minitest, watir, watir-webdrive, rest-client
# To use Chrome, you need to install chromedriver on your path
require 'rubygems'
require 'rest-client'
require 'json'
require 'pp'
require 'minitest/autorun'
require 'watir'
require 'watir-webdriver'
class TestReportSystem < MiniTest::Unit::TestCase
def setup
#browser = Watir::Browser.new :chrome # Defaults to firefox. Can do Safari and IE too.
# Log in here.....
end
def teardown
#browser.close
end
def test_report_lists # For minitest, the method names need to start with test
response = RestClient.get 'http://localhost:8080/reporter/reports/getReportList'
assert_equal response.code,200
parsed = JSON.parse response.to_str
assert_equal parsed.length, 3 # There are 3 reports available on the test server
end
def test_on_browser
#browser.goto 'http://localhost:8080/reporter/exampleReport/simple/genReport?month=Aug&year=2012'
assert(#browser.text.include?('Report for Aug 2012'))
end
end
Run the test cases by simply executing the script. There are many other testing systems and REST clients for Ruby which can be put to work in a similar way.
You might have a look at this approach http://anthonyeden.com/2013/07/10/testing-rest-apis-with-cucumber-and-rack.html
although many might say that using Cucumber is really more application or Acceptance testing and not unit testing, it does contain an approach to creating the HTTP headers and forming the http request, which I'm guessing might be where you are stuck?
Personally I don't have a problem with that since if you are truely going to unit test the API, you'd likely have to mock any units of code the api might be talking with (e.g. however you are persisting the data)
Seeing as I'm a QA guy not a dev, I'd be perfectly happy with using cucumber and testing it at that level, but I also greatly appreciate it when devs unit test, so while you might use rSpec instead of Cuke, perhaps the tip towards 'rack test' will be useful to what you are trying to accomplish.
You can try using airborne which is a framework written for just this purpose:
https://github.com/brooklynDev/airborne
You can test against either a live API, or against a Sinatra, Grape, Rails application.
I would use fakeweb gem to do unit testing with web services.
I would suggest client-api gem - it has loads of useful features specific to api automation which is easy to use and to maintain scripts.
https://github.com/prashanth-sams/client-api
Interestingly, this gem binds an api automation framework within itself. So, you don't even need a framework setup.
Key Features of client-api library:
Custom Header, URL, and Timeout support
URL query string customization
Datatype and key-pair value validation
Single key-pair response validation
Multi key-pair response validation
JSON response schema validation
JSON response content validation
JSON response size validation
JSON response is empty? validation
JSON response has specific key? validation
JSON response array-list sorting validation (descending, ascending)
Response headers validation
JSON template as body and schema
Support to store JSON responses of each tests for the current run
Logs support for debug
Custom logs remover
Auto-handle SSL for http(s) schemes
Example specs: https://github.com/prashanth-sams/client-api/tree/master/spec/client
Add this config snippet in the spec_helper.rb file:
ClientApi.configure do |config|
config.base_url = 'https://reqres.in'
config.headers = {'Content-Type' => 'application/json', 'Accept' => 'application/json'}
config.basic_auth = {'Username' => 'ahamilton#apigee.com', 'Password' => 'myp#ssw0rd'}
config.json_output = {'Dirname' => './output', 'Filename' => 'test'}
config.time_out = 10 # in secs
config.logger = {'Dirname' => './logs', 'Filename' => 'test', 'StoreFilesCount' => 2}
end
RSpec test scenarios look like,
api = ClientApi::Api.new
it "GET request" do
api.get('/api/users')
expect(api.status).to eq(200)
expect(api.message).to eq('OK')
end
it "POST request" do
api.post('/api/users', {"name": "prashanth sams"})
expect(api.status).to eq(201)
end
Note: This is an active project handling issues and new features based on user requirements

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.

Cucumber Error: Socket Error for Test Environment Host in REST API

I posted this to the Cucumber group with no replies, which makes me wonder if this is actually a cucumber issue or not. I'm pretty new to cucumber, and there are a number of things I really don't quite understand about how the cucumber environment is set up and executed within the test environment.
I have a REST API rails app I'm testing with cucumber, using the RestClient gem to generate a post to controller create action. When I run the feature with a hard-coded URL pointing to a running localhost server (my local dev server environment; replacing tickets_url with "http://
localhost/tickets" in the snippet below), my cucumber steps execute as expected. However, when the resource URL resolves to the cucumber host I'm declaring, I get a socket error exception.
getaddrinfo: nodename nor servname provided, or not known (SocketError)
From the steps file:
When /^POS Adapter sends JSON data to the Tickets resource$/ do
ticket = {
:ticket => {
...
}
}
host! "test.host"
puts tickets_url
RestClient.post tickets_url, ticket.to_json, :content_type => :json, :accepts => :json
end
(the "puts" statement prints "http://test.host/tickets")
Using the following gems:
cucumber-0.6.1
webrat-0.6.0
rest-client-1.2.0
I should also say I have a similar set up in another rails app, using test.host as my host, and it seems to work fine. I'd appreciate any insight on what I might be missing in my configuration or what this could be related to.
What port number are you using? A similar problem was patched back in Oct. 2009. The issue was related to a large port number being used. Here's the light houseticket: https://rspec.lighthouseapp.com/projects/16211/tickets/502-wire-protocol-features-fail-with-os-x-snowy

POSTing an HTML form to remote.cgi - written in Ruby?

I am working on a website hosted on microsoft's office live service. It has a contact form enabling visitors to get in touch with the owner. I want to write a Ruby script that sits on a seperate sever and which the form will POST to. It will parse the form data and email the details to a preset address. The script should then redirect the browser to a confirmation page.
I have an ubuntu hardy machine running nginx and postfix. Ruby is installed and we shall see about using Thin and it's Rack functionality to handle the script. Now it's come to writing the script and i've drawn a blank.
It's been a long time and if i remember rightly the process is something like;
read HTTP header
parse parameters
send email
send redirect header
Broadly speaking, the question has been answered. Figuring out how to use the answer was more complicated than expected and I thought worth sharing.
First Steps:
I learnt rather abruptly that nginx doesn't directly support cgi scripts. You have to use some other process to run the script and get nginx to proxy requests over. If I was doing this in php (which in hind sight i think would have been a more natural choice) i could use something like php-fcgi and expect life would be pretty straight forward.
Ruby and fcgi felt pretty daunting. But if we are abandoning the ideal of loading these things at runtime then Rack is probably the most straight forward solution and Thin includes all we need. Learning how to make basic little apps with them has been profoundly beneficial to a relative Rails newcomer like me. The foundations of a Rails app can seem hidden for a long time and Rack has helped me lift the curtain that little bit further.
Nonetheless, following Yehuda's advice and looking up sinatra has been another surprise. I now have a basic sinatra app running in a Thin instance. It communicates with nginx over a unix socket in what i gather is the standard way. Sinatra enables a really elegant way to handle different requests and routes into the app. All you need is a get '/' {} to start handling requests to the virtual host. To add more (in a clean fashion) we just include a routes/script.rb into the main file.
# cgi-bin.rb
# main file loaded as a sinatra app
require 'sinatra'
# load cgi routes
require 'routes/default'
require 'routes/contact'
# 404 behaviour
not_found do
"Sorry, this CGI host does not recognize that request."
end
These route files will call on functionality stored in a separate library of classes:
# routes/contact.rb
# contact controller
require 'lib/contact/contactTarget'
require 'lib/contact/contactPost'
post '/contact/:target/?' do |target|
# the target for the message is taken from the URL
msg = ContactPost.new(request, target)
redirect msg.action, 302
end
The sheer horror of figuring out such a simple thing will stay with me for a while. I was expecting to calmly let nginx know that .rb files were to be executed and to just get on with it. Now that this little sinatra app is up and running, I'll be able to dive straight in if I want to add extra functionality in the future.
Implementation:
The ContactPost class handles the messaging aspect. All it needs to know are the parameters in the request and the target for the email. ContactPost::action kicks everything off and returns an address for the controller to redirect to.
There is a separate ContactTarget class that does some authentication to make sure the specified target accepts messages from the URL given in request.referrer. This is handled in ContactTarget::accept? as we can guess from the ContactPost::action method;
# lib/contact/contactPost.rb
class ContactPost
# ...
def action
return failed unless #target.accept? #request.referer
if send?
successful
else
failed
end
end
# ...
end
ContactPost::successful and ContactPost::failed each return a redirect address by combining paths supplied with the HTML form with the request.referer URI. All the behaviour is thus specified in the HTML form. Future websites that use this script just need to be listed in the user's own ~/cgi/contact.conf and they'll be away. This is because ContactTarget looks in /home/:target/cgi/contact.conf for the details. Maybe oneday this will be inappropriate, but for now it's just fine for my purposes.
The send method is simple enough, it creates an instance of a simple Email class and ships it out. The Email class is pretty much based on the standard usage example given in the Ruby net/smtp documentation;
# lib/email/email.rb
require 'net/smtp'
class Email
def initialize(from_alias, to, reply, subject, body)
#from_alias = from_alias
#from = "cgi_user#host.domain.com"
#to = to
#reply = reply
#subject = subject
#body = body
end
def send
Net::SMTP.start('localhost', 25) do |smtp|
smtp.send_message to_s, #from, #to
end
end
def to_s
<<END_OF_MESSAGE
From: #{#from_alias}
To: #{#to}
Reply-To: #{#from_alias}
Subject: #{#subject}
Date: #{DateTime::now().to_s}
#{#body}
END_OF_MESSAGE
end
end
All I need to do is rack up the application, let nginx know which socket to talk to and we're away.
Thank you everyone for your helpful pointers in the right direction! Long live sinatra!
It's all in the Net module, here's an example:
#net = Net::HTTP.new 'http://www.foo.com', 80
#params = {:name => 'doris', :email => 'doris#foo.com'}
# Create HTTP request
req = Net::HTTP::Post.new( 'script.cgi', {} )
req.set_form_data #params
# Send request
response = #net.start do |http|
http.read_timeout = 5600
http.request req
end
Probably the best way to do this would be to use an existing Ruby library like Sinatra:
require "rubygems"
require "sinatra"
get "/myurl" do
# params hash available here
# send email
end
You'll probably want to use MailFactory to send the actual email, but you definitely don't need to be mucking about with headers or parsing parameters.
CGI class of Ruby can be used for writing CGI scripts. Please check: http://www.ruby-doc.org/stdlib/libdoc/cgi/rdoc/index.html
By the way, there is no need to read the HTTP header. Parsing parametres will be easy using CGI class. Then, send the e-mail and redirect.

Resources