I'm currently following along with this railscast and for my specific situation am running into a Faraday timeout error on the callback from omniauth.
Currently I'm using a rails application as an API and backbone as a javascript front-end (on the same application)
I decided I wanted to lock down the API with OAuth and provided a custom strategy for Omniauth to access the API as a client as well as Doorkeeper to handle the authorization logic
module OmniAuth
module Strategies
class Twiddle < OmniAuth::Strategies::OAuth2
option :name, :twiddle
option :client_options, {
site: "http://localhost:3001",
authorize_path: "/oauth/authorize"
}
uid do
raw_info["id"]
end
info do
{
firstName: raw_info["firstName"],
lastName: raw_info["lastName"],
email: raw_info["email"]
}
end
def raw_info
#raw_info ||= access_token.get('/api/v1/user').parsed
end
end
end
end
I included the custom strategy like this:
require File.expand_path('lib/omniauth/strategies/twiddle', Rails.root)
Rails.application.config.middleware.use OmniAuth::Builder do
provider :twiddle, id, secret # Omitting the actual ones for obvious reasons
end
I am currently using these gems in my bundle
# OAuth
gem 'oauth2'
gem 'omniauth'
gem 'omniauth-oauth2'
gem 'omniauth-facebook'
gem 'doorkeeper'
Here is where I authenticate and attempt to retrive the proper access token (and also where I get stuck)
def loginParse
if ( user = User.authenticate( params[:email], params[:password] ) )
session[:user_id] = user.id
redirect_to '/auth/twiddle/'
else
render :controller => "authentication", :action => "loginIndex", :notice => "Incorrect credentials"
end
end
Here is the routing from the routes.rb
# Oauth urls
match '/auth/twiddle/callback', to: "authentication#connectAPI"
match "/auth/facebook/callback", to: "authentication#loginSocialMedia"
The application never is able to render the connectAPI action, getting COMPLETELY stuck at this point (given by the server logs)
User Load (0.4ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
Doorkeeper::Application Load (0.2ms) SELECT `oauth_applications`.* FROM `oauth_applications` WHERE `oauth_applications`.`uid` = '' LIMIT 1
CACHE (0.0ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
Doorkeeper::AccessToken Load (0.3ms) SELECT `oauth_access_tokens`.* FROM `oauth_access_tokens` WHERE `oauth_access_tokens`.`revoked_at` IS NULL AND `oauth_access_tokens`.`application_id` = 1 AND `oauth_access_tokens`.`resource_owner_id` = 1 ORDER BY created_at desc LIMIT 1
(0.1ms) BEGIN
Doorkeeper::AccessGrant Load (0.2ms) SELECT `oauth_access_grants`.* FROM `oauth_access_grants` WHERE `oauth_access_grants`.`token` = '' LIMIT 1
SQL (1.1ms) INSERT INTO `oauth_access_grants` (`application_id`, `created_at`, `expires_in`, `redirect_uri`, `resource_owner_id`, `revoked_at`, `scopes`, `token`) VALUES (1, '2012-08-08 03:10:31', 600, 'http://localhost:3001/auth/twiddle/callback', 1, NULL, '', '')
(1.4ms) COMMIT
Redirected to http://localhost:3001/auth/twiddle/callback?code=a
Completed 302 Found in 12ms (ActiveRecord: 3.7ms)
(twiddle) Callback phase initiated.
Many of the uids/important information have been omitted from the log.
Finally this error is given:
Faraday::Error::TimeoutError (Timeout::Error):
I hope I have been thorough in my explanation of this problem.
I don't know why exactly the application seems to be freezing at the callback initiated part of omniauth. I have tried updating bundler as a few other stackoverflow questions have pointed me to but it is not working.
Perhaps my understanding of OAuth2 is a bit murky.
If anyone can help me, I would greatly appreciate it
I'm not sure this applies to you been here was my scenario:
Problem
An app with data that our internal OAuth server wants
An OAuth server with little, to no data on it
We want to offload the authentication portion of App1 to App2 without moving data
Solution
App1 uses App2 as the Authentication server
App2 uses App1 for user data
Problem from this solution
Deadlock - App1 is waiting for an OAuth response from App2, but to complete
that response App2 must wait for a response from App1.
Final observation
In development mode on Rails (with WebBrick) you can't run multi-threaded, so the request
may never be allowed to complete.
My solution
My solution was to install puma and add to
config/environments/development.rb:
if ENV["THREADS"]
config.threadsafe!
end
Then when you start the server you'd do THREADS=1 rails s Puma to test your
OAuth stuff.
OR
Or your scenario is completely different and you're actually not communicating between
your services. Is your extra_info (like Github's /user) endpoint functioning on
the OAuth server? Is your callback actually doing anything?
I hope this helps!
Related
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.
I am working on rails json webservices. I am using warden for authentication in that, its working fine with html format , but in json its not working. because passed parameter is not working in config/intializers/wrden.rb file .below is the code
config/intializers/warden. rb
def authenticate!
Rails.logger.info '!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
Rails.logger.info params['emailID']
user = User.find_by_emailID(params['emailID'])
if user && user.authenticate(params['password'])
success! user
else
fail "Invalid email or password"
end
end
here is log of this
Parameters: {"emailID"=>"xyz#gmail.com", "password"=>"123456", "session"=>{"emailID"=>"xyz#gmail.com", "password"=>"123456"}}
(0.2ms) BEGIN
!!!!!!!!!!!!!!!!!!!!!!!!!!!!
nil
User Load (12.2ms) SELECT "users".* FROM "users" WHERE "users"."emailID" IS **NULL** LIMIT 1
(0.3ms) COMMIT
Completed in 276ms
Well, I just ran into this, too. This GitHub thread fixed it for me:
https://github.com/hassox/warden/issues/84
Basically, tell Warden to use Rails' request object instead of whatever it's using by default. You can use the rails-warden gem or mix this into Warden:
module Warden::Mixins::Common
def request
#request ||= ActionDispatch::Request.new(#env)
end
end
I am trying to save a form with rails, its a simple one, and everytime I try to send a name with a space (like john smith) I dont actually get an error, it returns succcess, but does not save anything, when I try johnsmith then it works.
I checked on my model and I have this
validates :first_name, :allow_blank => true, :format => { :with => /\A[a-zA-Z]+\z/, :message => "Only letters allowed" }
validating only letters, but accepting spaces, still, when I try, no success.
At my controller I have something like this.
name = params[:name].to_s
and later
#user.atributes = { :weight => weight, :name => name ... and so on
at the end I only make a #user.save
Any idea how to avoid this problem? I do want to accept spaces on the names, but without getting into security problems.
Thanks
result of the post in my console
Started POST "/users/custom" for 192.168.1.21 at 2013-05-21 17:51:06 -0600
Processing by UsersController#custom as JS
Parameters: {"name"=>" new user", "lastname"=>" my last name", "mail"=>"newuser#gmail.com", "sex"=>"0" ... n so on}
User Load (0.1ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 6 LIMIT 1
(0.1ms) BEGIN
(0.3ms) UPDATE `users` SET `first_name` = ' new user', `ssn` = 0, `updated_at` = '2013-05-21 23:51:06' WHERE `users`.`id` = 6
(1.2ms) COMMIT
Rendered users/custom.html.erb within layouts/application (0.1ms)
Completed 200 OK in 16ms (Views: 11.0ms | ActiveRecord: 1.7ms)
Your regex is wrong. You're accepting only letters, whitespace is not a letter. Try something like this: \A[a-zA-Z,\s]+\z
BTW rubular is pretty cool tool, if you need to test your regexps.
http://rubular.com/
About the validation message not showing up:
If you're doing asynchronous request, you'll need to make your validation on the client side. There are some gems which can help you with this, e.g. client side validations gem.
Also, if you're using jQuery.ajax() you can use its callback to perform an action after the call (notify user of success or do whatever with DOM you want to):
$.ajax({
url: "http://some/url.com",
// rest of your ajax call
}).done(function (data) {
console.log("Your data:", data); // this will be run after the async. call
});
If you need to debug things like this try pry. Just add to your gemfile:
group :test, :development do
gem 'pry', '~> 0.9.12'
end
Run bundle install, restart server and then you can add:
binding.pry
wherever you want to stop code execution and inspect current state of your app enviroment in the console.
In your case it would be somewhere at the end of UsersController#custom method. You can then check in your terminal value of #user. Methods #user.valid? and #user.errors will tell you if your #user object is valid and show you an array with all validation errors associated with the object.
I have a fairly simple app using devise and cancan for authentication and authorization. Everything works great except when users try signing in with invalid usernames and/or passwords. When this happens, we get an error loading page with the following exception in the logs:
Started POST "/users/sign_in" for 127.0.0.1 at 2012-02-09 22:23:22 -0600
Processing by Devise::SessionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"blahblahblahblah", "user"=>{"login"=>"asdasd", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Sign in"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE (lower(username) = 'asdasd' OR lower(email) = 'asdasd') LIMIT 1
Completed 401 Unauthorized in 74ms
I'm not sure what I need to set to allow the authorization and/or how to get more detailed logs to see exactly what is not authorized? If I enter valid credentials I can access the application and all other pieces of the app work as expected.
I know this question has been posted a couple months ago but I hot the same issue, and after fighting it for a few hours, overwriting Devise SessionController, Devise Custom Failure, debugging through, etc.., I finally found out what was going on and I decided to share the solution so you guys won't have to go through that.
The error 'Completed 401 Unauthorized in XXms' happens within the create method of SessionController at the line:
resource = build_resource(...)
And the resource cannot be built since the resource is not passed to the server. Now the problem resides in WHY the resource isn't passed to the server? I'm using JQUERY mobile which post the sign_in as an AJAX call, which JQUERY cannot upload data like that through AJAX.
You need to add to your signin form the data-ajax=false:
in Devise/sessions/new.html.erb modify the form to look like this:
form_for(resource, :as => resource_name, :url => user_session_url, html: {data: {ajax: false}}) do |f|
Hope that helps someone down the road.
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.