Omniauth making multiple auth calls per request? - ruby-on-rails

I have Omniauth set up with a WePay strategy ( https://github.com/intridea/omniauth ). When getting authorization, it is making the v2/oauth2/token call four times (interspersed with /v2/user calls), but returns on the first access token in the env["omniauth.auth"] variable. This results in both long load times on the callback and a "access_token revoked" error when trying to perform an API call later.
I'm completely flummoxed as to why this is happening. I've tried disabling every method that follows the callback, so I'm pretty sure this is happening within Omniauth itself, as opposed to my app (which is in Rails, btw).
Here's my omniauth.rb initializer file:
require "omniauth/strategies/wepay"
OmniAuth.config.logger = Rails.logger
Rails.application.config.middleware.use OmniAuth::Builder do
provider :wepay, ENV['WEPAY_STAGE_APP_ID'], ENV['WEPAY_STAGE_SECRET']
provider :twitter, ENV['TWITTER_CONSUMER_KEY'], ENV['TWITTER_CONSUMER_SECRET']
provider :facebook, ENV['FACEBOOK_APP_ID'], ENV['FACEBOOK_APP_SECRET']
end
Relevant routes:
match 'auth/wepay/callback', to: 'sessions#wepay'
match 'auth/failure', to: redirect('/organization')
The sessions controller (though I am reasonably confident the loop is happening before this ever gets called):
class SessionsController < ApplicationController
before_filter :get_all_organizations
before_filter :authorize_current_organization
def wepay
current_user.from_omniauth(env["omniauth.auth"])
if #organization.wepay_account_id? == false
#organization.create_wepay_account(current_user)
end
redirect_to transactions_path, notice: 'Login successful.'
end
end
The relevant section of my log:
Started GET "/auth/wepay/" for 127.0.0.1 at 2012-08-26 17:40:18 -0700
(wepay) Request phase initiated.
Started GET "/auth/wepay/callback?code=XXXXX&state=XXXXX" for 127.0.0.1 at 2012-08-26 17:40:25 -0700
(wepay) Callback phase initiated.
Connected to NewRelic Service at collector-6.newrelic.com
Processing by SessionsController#wepay as HTML
Parameters: {"code"=>"XXXXX", "state"=>"XXXXX"}
I'm having a tough time debugging this, but New Relic does show that 548ms are being spent in sessions#wepay, vs 261ms in Net::HTTP[stage.wepayapi.com]: POST. I don't know if that's indicative of anything.

Cool, just checking. On my end, as a test, I just ran the gem through a couple of Rails Omniauth premade apps, both of which were easily able to authenticate and return back to the app. I used these to create the apps:
http://net.tutsplus.com/tutorials/ruby/how-to-use-omniauth-to-authenticate-your-users/
and
http://railsapps.github.com/tutorial-rails-mongoid-omniauth.html
I would check the session controller code, as it may not just be a routing issue.

Related

OAuth2::Error redirect_uri_mismatch using omniauth-google-oauth2 gem

I'm getting this error: OAuth2::Error redirect_uri_mismatch
This is how I have omniauth.rb set up, per omniauth-google-oauth2's documentation.
# config/initializers/omniauth.rb
OmniAuth.config.logger = Rails.logger
OmniAuth.config.full_host = Rails.env.production? ? 'https://www.********.org' : 'http://localhost:3000'
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook, ENV['FACEBOOK_OAUTH_CLIENT_ID'], ENV['FACEBOOK_OAUTH_SECRET']
provider :google_oauth2, ENV['GOOGLE_OAUTH_CLIENT_ID'], ENV['GOOGLE_OAUTH_SECRET'], {scope: 'profile', image_aspect_ratio: 'square', image_size: 48, access_type: 'online'}
end
And this is how I have my routes.rb set up to handle the callback:
# config/routes.rb
get 'auth/:provider/callback', to: 'sessions#create'
Here's a screenshot of my Google Developer Console, where I have my authorized redirect uri set up as http://localhost:3000/auth/google_oauth2/callback.
I have tried it as just http://localhost:3000 and with https and http://localhost/auth/google_oauth2/callback and several other variations.
Some people say the console can take a while to update, so I wonder if it's possible I tried the correct thing at some point and didn't give it enough time (more than 5 minutes?) to update.
Facebook's callback (http://localhost:3000/auth/facebook/callback at the Facebook developer console) works, taking me all the way through to the SessionsController's #create action, where I haven't added a way to handle it yet, so it's throwing an error there.
Can anyone spot what I'm doing wrong!?

OmniAuth OAuth 1 strategy for upwork API error

I'm using OmniAuth gem along with the specific provider gems for FB, Linkedin and G+, both for login, registration and information retrieval. I want to offer further integration with other API's in this case with Upwork's api, that uses OAuth 1.
I've set the App with Upwork and have working key and secret. I've set the loader to load my custom strategy (since it's not a gem) and it loads. I've set the provider to pass the key and secret which are stored in an env file.
All of that seems to be working now, after many hours into it.
I tried reading through the sparse information contained in OmniAuth's strategy guide, along with OAuth wiki, and looked into the gem files of other providers. I ended up copying a bit of the code I thought would be enough to work through this, at least, for login but I'm messing something up.
Whenever I go to the callback path for upwork, set automatically by omniauth I get an error.
Started GET "/auth/upwork" for ::1 at 2015-07-29 00:08:12 +0800
ActiveRecord::SchemaMigration Load (0.3ms) SELECT "schema_migrations".* FROM "schema_migrations"
I, [2015-07-29T00:08:12.169605 #24517] INFO -- omniauth: (upwork) Request phase initiated.
OAuth::Unauthorized (405 Method Not Allowed):
lib/omniauth/strategies/upwork.rb:18:in `request_phase'
Rendered /Users/mnussbaumer/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/middleware/templates/rescues/_source.erb (5.1ms)
By the documentation this seems to be when I either try a GET to a POST only, or a POST to a GET only endpoint.
In Upwork's API reference they explicitly say that:
Get request token
Endpoint
POST /api/auth/v1/oauth/token/request
My strategy is currently as this:
require 'json'
require 'omniauth-oauth'
module OmniAuth
module Strategies
class Upwork < OmniAuth::Strategies::OAuth
option :client_options, {
:site => "https://www.upwork.com/api",
:request_token_path => "/api/auth/v1/oauth/token/request",
:authorize_url => "/services/api/auth",
:access_token_path => "api/auth/v1/oauth/token/access",
}
uid { request.params['user_id'] }
def request_phase
request_token = consumer.get_request_token(:oauth_callback => callback_url)
session['oauth'] ||= {}
session['oauth'][name.to_s] = {'callback_confirmed' => request_token.callback_confirmed?, 'request_token' => request_token.token, 'request_secret' => request_token.secret}
if request_token.callback_confirmed?
redirect request_token.authorize_url(options[:authorize_params].merge(:oauth_consumer_key => consumer.key))
else
redirect request_token.authorize_url(options[:authorize_params].merge(:oauth_callback => callback_url, :oauth_consumer_key => consumer.key))
end
rescue ::Timeout::Error => e
fail!(:timeout, e)
rescue ::Net::HTTPFatalError, ::OpenSSL::SSL::SSLError => e
fail!(:service_unavailable, e)
end
def raw_info
#raw_info ||= JSON.load(access_token.get('/me.json')).body
end
end
end
end
I tried changing "consumer.get_request_token" to "consumer.post_request_token" but I think that has nothing to do with it.
The request_phase was ripped off of a gem I found and the JSON.load from a different one. I thought it would work with only these 2 but it seems not. I'm learning slowly how to use all this and would like to build first a usable strategy and then provide it as a public gem for omniauth.
UpWork has an API documentation, and they even have a gem for ruby, but I would like to use OmniAuth for everything, plus, I'll need to figure out other API's in the future so I would like to know how to do this well.
https://developers.upwork.com/?lang=ruby#authentication_oauth-10
Anybody can help with this? Or with creating an OmniAuth gem for Upwork.
Thanks!
(edited to change the error - now it's much thinner output but it's the same error)
The request_phase method is actually a method that belongs to omniauth-oauth which you required on top of the upwork.rb and your class Upwork inherits it (OmniAuth::Strategies::OAuth). you don't have to override it.

Rails 3.2 error overriding devise for email only signup

I have been trying to follow https://github.com/plataformatec/devise/wiki/How-To:-Override-confirmations-so-users-can-pick-their-own-passwords-as-part-of-confirmation-activation in order to allow users on my app to supply only an email address when they sign up, and then be prompted for the remainder of their information after they confirm their email. But the approach seems to be slightly broken or I don't fully understand it.
In the instructions, in the confirmations_controller there is this method:
def with_unconfirmed_confirmable
original_token = params[:confirmation_token]
confirmation_token = Devise.token_generator.digest(User, :confirmation_token, original_token)
#confirmable = User.find_or_initialize_with_error_by(:confirmation_token, confirmation_token)
if !#confirmable.new_record?
#confirmable.only_if_unconfirmed {yield}
end
end
If I leave it as is, I always get a "Confirmation Token is Invalid" error. It appears to be due to the new token being generated and not found. You can see what I mean in the log:
Started GET "/users/confirmation?confirmation_token=9835abdff3d03d0a29e1c5a640c6a22f1ed6289b4cf696ed514ba183aad49caa" for 127.0.0.1 at 2013-11-12 07:39:42 -0700
Processing by ConfirmationsController#show as HTML
Parameters: {"confirmation_token"=>"9835abdff3d03d0a29e1c5a640c6a22f1ed6289b4cf696ed514ba183aad49caa"}
ESC[1mESC[36mUser Load (0.3ms)ESC[0m ESC[1mSELECT "users".* FROM "users" WHERE "users"."confirmation_token" = '98e17d2ea3cc3fcba5cab7d37bd9a865fc2e318372cb293b541b8a05b46f
e4a3' LIMIT 1ESC[0m
But if I change the method to use the original_token instead of the generated confirmation_token, it all works. What am I missing? Should I be worried about not using the derived token?
Turns out the error was because my app was on an older version of devise that inadvertently got upgraded to devise 3.1. Thanks to this post: Upgrading to devise 3.1 => getting Reset password token is invalid
I updated the mailer to send the correct token and now all is working.

Devise with mobile mime type, 401 only displays flash message

I have a Rail 3.2.2 app with Devise 2.0 that I've begun to incorporate mobile views with. I'm using a before_filter in my application_controller.rb to use the mobile layout as follows:
before_filter :adjust_format_for_mobile
private
def adjust_format_for_mobile
if request.env["HTTP_USER_AGENT"] && request.env["HTTP_USER_AGENT"][/(iPhone|iPod)/]
request.format = :mobile
end
end
I have the mime type defined in initializers/mime_types:
Mime::Type.register_alias "text/html", :mobile
Whenever I attempt to access the root_path as defined in routes.rb:
root :to => "wells#index"
(which is protected via before_filter :authenticate_user!)
All that is rendered is the Devise flash message (no HTML whatsoever):
You need to sign in or sign up before continuing
I have the necessary mobile layout, what am I missing here? The behavior on the desktop version is that you're redirected to the new_user_session_path, why is that not the case here?
EDIT:
The console log is as follows:
Started GET "/" for 127.0.0.1 at 2012-03-21 17:07:35 -0500
Processing by WellsController#index as HTML
Completed 401 Unauthorized in 0ms
Additionally, this only occurs with that particular path (the root path). If I manually go to users/sign_up or users/sign_in it works perfect. I can then log in and everything works fine.
Found a wiki on the process:
How To: Make Devise work with other formats like mobile, iphone and ipad (Rails specific)

How Can I Tell Controller Specs to Use the Signed OAuth Request

I am building a 2-Legged OAuth provider for my api. Everything is hooked up properly and I can make signed calls from the rails console. The problem I have is that I am having trouble integrating OAuth into the controller_spec.
Here is an example of a working call on my server:
coneybeare $ rails c test
Loading test environment (Rails 3.2.0)
rails test: main
>> consumer = OAuth::Consumer.new("one_key", "MyString", :site => [REDACTED])
# => #<OAuth::Consumer:0x007f9d01252268 #key="one_key", #secret="MyString", #options={:signature_method=>"HMAC-SHA1", :request_token_path=>"/oauth/request_token", :authorize_path=>"/oauth/authorize", :access_token_path=>"/oauth/access_token", :proxy=>nil, :scheme=>:header, :http_method=>:post, :oauth_version=>"1.0", :site=>[REDACTED]}>
ruby: main
>> req = consumer.create_signed_request(:get, "/api/v1/client_applications.json", nil)
# => #<Net::HTTP::Get GET>
ruby: main
>> res = Net::HTTP.start([REDACTED]) {|http| http.request(req) }
# => #<Net::HTTPOK 200 OK readbody=true>
ruby: main
>> puts res.body
{"client_applications":[{"id":119059960,"name":"FooBar1","url":"http://test1.com"},{"id":504489040,"name":"FooBar2","url":"http://test2.com"}]}
# => nil
And here is what I am doing in my controller tests:
require 'oauth/client/action_controller_request'
describe Api::ClientApplicationsController do
include OAuthControllerSpecHelper
…
…
it "assigns all client_applications as #client_applications" do
consumer = OAuth::Consumer.new("one_key", "MyString", :site => [REDACTED])
ActionController::TestRequest.use_oauth=true
#request.configure_oauth(consumer)
#request.apply_oauth!
puts "request.env['Authorization'] = #{#request.env['Authorization']}"
get :index, {:api_version => 'v1', :format => :json}
response.should be_success # Just this for now until I can get authorization, then proper controller testing
end
end
The output of that test:
request.env['Authorization'] = OAuth oauth_consumer_key="one_key", oauth_nonce="gzAbvBSWyFtIYKfuokMAdu6VnH39EHeXvebbH2qUtE", oauth_signature="juBkJo5K0WLu9mYqHVC3Ar%2FATUs%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1328474800", oauth_version="1.0"
1) Api::ClientApplicationsController GET index assigns all client_applications as #client_applications
Failure/Error: response.should be_success
expected success? to return true, got false
And the corresponding server call from the rails log:
Processing by Api::ClientApplicationsController#index as JSON
Parameters: {"api_version"=>1}
Rendered text template (0.0ms)
Filter chain halted as #<OAuth::Controllers::ApplicationControllerMethods::Filter:0x007f85a51a8858 #options={:interactive=>false, :strategies=>:two_legged}, #strategies=[:two_legged]> rendered or redirected
Completed 401 Unauthorized in 15ms (Views: 14.1ms | ActiveRecord: 0.0ms)
(0.2ms) ROLLBACK
I just can't figure out why it's not working :/ Am I making an obvious mistake?
If you'd like to test it in a request spec and actually need to test without stubbing, you can build an OAuth consumer and sign a request like this:
#access_token = FactoryGirl.create :access_token
#consumer = OAuth::Consumer.new(#access_token.app.key, #access_token.app.secret, :site => "http://www.example.com/")
#path = "/path/to/request"
#request = #consumer.create_signed_request(:get, #path, OAuth::AccessToken.new(#consumer, #access_token.token, #access_token.secret))
get #path, nil, { 'HTTP_AUTHORIZATION' => #request.get_fields('authorization').first }
I would take a look as to how the Omniauth test helpers work, specifically these files: https://github.com/intridea/omniauth/tree/master/lib/omniauth/test. See their wiki page on integration testing for ideas of how this is set up. I realize that you're building a provider, not a client, but this may be a good starting point. Also, as some of the commenters have already said, I don't know if you can do this with a controller test; you may need a request or integration test to fully simulate the rack environment.
Turns out that the best way to test my controller was the simplest as well. Instead of trying to sign each test so the controller gets the right information (something that indeed does belong in a request spec not a controller spec), I figured out that I could just give the controller the information it needed manually.
To do this, I simply had to stub 2 methods:
fixtures :client_applications
before(:each) do
#client_application1 = client_applications(:client_application1)
Api::ClientApplicationsController::Authenticator.any_instance.stub(:allow?).and_return(true)
controller.stub(:client_application).and_return(#client_application1)
end
Stubbing the allow? method caused the rack auth to be fooled into thinking it was authenticated. allow? also set the client_application based on the credentials though, so I had to stub that as well. Now that the auth is out of the way, I can test my controller properly.

Resources