1
0
Fork 0
mirror of https://github.com/heartcombo/devise.git synced 2022-11-09 12:18:31 -05:00

Start to add helpers for OAuth tests.

This commit is contained in:
José Valim 2010-07-15 18:13:55 +02:00
parent eb3118e89a
commit ef841ca17d
17 changed files with 174 additions and 85 deletions

View file

@ -47,6 +47,13 @@ class Devise::RegistrationsController < ApplicationController
protected
# Build a devise resource passing in the session. Useful to move
# temporary session data to the newly created user.
def build_resource(hash=nil)
hash ||= params[resource_name] || {}
self.resource = resource_class.new_with_session(hash, session)
end
# Authenticates the current scope and gets a copy of the current resource.
# We need to use a copy because we don't want actions like update changing
# the current user in place.

View file

@ -214,7 +214,7 @@ module Devise
mapping = Devise::Mapping.new(resource, options)
@@mappings[mapping.name] = mapping
@@default_scope ||= mapping.name
@@helpers.each { |h| h.define_helpers(mapping.name) }
@@helpers.each { |h| h.define_helpers(mapping) }
mapping
end

View file

@ -34,6 +34,8 @@ module Devise
# before_filter :authenticate_admin! # Tell devise to use :admin map
#
def self.define_helpers(mapping) #:nodoc:
mapping = mapping.name
class_eval <<-METHODS, __FILE__, __LINE__ + 1
def authenticate_#{mapping}!
warden.authenticate!(:scope => :#{mapping})

View file

@ -70,7 +70,7 @@ module Devise
# Build a devise resource.
def build_resource(hash=nil)
hash ||= params[resource_name] || {}
self.resource = resource_class.new_with_session(hash, session)
self.resource = resource_class.new(hash)
end
# Helper for use in before_filters where no authentication is required.

View file

@ -78,12 +78,6 @@ module Devise
http_authenticatable.include?(strategy) : http_authenticatable
end
# By default discards all information sent by the session by calling
# new with params.
def new_with_session(params, session)
new(params)
end
# Find first record based on conditions given (ie by the sign in form).
# Overwrite to add customized conditions, create a join, or maybe use a
# namedscope to filter records while authenticating.

View file

@ -3,6 +3,19 @@ module Devise
# Registerable is responsible for everything related to registering a new
# resource (ie user sign up).
module Registerable
extend ActiveSupport::Concern
module ClassMethods
# A convenience method that receives both parameters and session to
# initialize an user. This can be used by OAuth, for example, to send
# in the user token and be stored on initialization.
#
# By default discards all information sent by the session by calling
# new with params.
def new_with_session(params, session)
new(params)
end
end
end
end
end

View file

@ -11,5 +11,16 @@ module Devise
autoload :Helpers, "devise/oauth/helpers"
autoload :InternalHelpers, "devise/oauth/internal_helpers"
autoload :UrlHelpers, "devise/oauth/url_helpers"
autoload :TestHelpers, "devise/oauth/test_helpers"
class << self
delegate :short_circuit_authorizers!, :unshort_circuit_authorizers!, :to => "Devise::Oauth::TestHelpers"
def test_mode!
Faraday.default_adapter = :test
ActiveSupport.on_load(:action_controller) { include Devise::Oauth::TestHelpers }
ActiveSupport.on_load(:action_view) { include Devise::Oauth::TestHelpers }
end
end
end
end

View file

@ -122,7 +122,6 @@ module Devise
clean_up_passwords(resource)
render_for_oauth
else
session[oauth_session_key] = access_token.token
set_oauth_flash_message :alert, :skipped
redirect_to after_oauth_skipped_path_for(resource_name)
end

View file

@ -0,0 +1,29 @@
module Devise
module Oauth
module TestHelpers #:nodoc:
def self.short_circuit_authorizers!
module_eval <<-ALIASES, __FILE__, __LINE__ + 1
def oauth_authorize_url(scope, provider)
oauth_callback_url(scope, provider, :code => "12345")
end
ALIASES
Devise.mappings.each_value do |m|
next unless m.oauthable?
module_eval <<-ALIASES, __FILE__, __LINE__ + 1
def #{m.name}_oauth_authorize_url(provider)
#{m.name}_oauth_callback_url(provider, :code => "12345")
end
ALIASES
end
end
def self.unshort_circuit_authorizers!
module_eval do
instance_methods.each { |m| remove_method(m) }
end
end
end
end
end

View file

@ -2,10 +2,12 @@ module Devise
module Oauth
module UrlHelpers
def self.define_helpers(mapping)
return unless mapping.oauthable?
class_eval <<-URL_HELPERS, __FILE__, __LINE__ + 1
def #{mapping}_oauth_authorize_url(provider, options={})
def #{mapping.name}_oauth_authorize_url(provider, options={})
if config = Devise.oauth_configs[provider.to_sym]
options[:redirect_uri] ||= #{mapping}_oauth_callback_url(provider.to_s)
options[:redirect_uri] ||= #{mapping.name}_oauth_callback_url(provider.to_s)
config.authorize_url(options)
else
raise ArgumentError, "Could not find oauth provider \#{provider.inspect}"

View file

@ -1,15 +1,6 @@
require 'test_helper'
class AuthenticationSanityTest < ActionController::IntegrationTest
def setup
Devise.sign_out_all_scopes = false
end
def teardown
Devise.sign_out_all_scopes = false
end
test 'home should be accessible without sign in' do
visit '/'
assert_response :success
@ -18,14 +9,12 @@ class AuthenticationSanityTest < ActionController::IntegrationTest
test 'sign in as user should not authenticate admin scope' do
sign_in_as_user
assert warden.authenticated?(:user)
assert_not warden.authenticated?(:admin)
end
test 'sign in as admin should not authenticate user scope' do
sign_in_as_admin
assert warden.authenticated?(:admin)
assert_not warden.authenticated?(:user)
end
@ -33,59 +22,61 @@ class AuthenticationSanityTest < ActionController::IntegrationTest
test 'sign in as both user and admin at same time' do
sign_in_as_user
sign_in_as_admin
assert warden.authenticated?(:user)
assert warden.authenticated?(:admin)
end
test 'sign out as user should not touch admin authentication if sign_out_all_scopes is false' do
sign_in_as_user
sign_in_as_admin
get destroy_user_session_path
assert_not warden.authenticated?(:user)
assert warden.authenticated?(:admin)
swap Devise, :sign_out_all_scopes => false do
sign_in_as_user
sign_in_as_admin
get destroy_user_session_path
assert_not warden.authenticated?(:user)
assert warden.authenticated?(:admin)
end
end
test 'sign out as admin should not touch user authentication if sign_out_all_scopes is false' do
sign_in_as_user
sign_in_as_admin
swap Devise, :sign_out_all_scopes => false do
sign_in_as_user
sign_in_as_admin
get destroy_admin_session_path
assert_not warden.authenticated?(:admin)
assert warden.authenticated?(:user)
get destroy_admin_session_path
assert_not warden.authenticated?(:admin)
assert warden.authenticated?(:user)
end
end
test 'sign out as user should also sign out admin if sign_out_all_scopes is true' do
Devise.sign_out_all_scopes = true
sign_in_as_user
sign_in_as_admin
swap Devise, :sign_out_all_scopes => true do
sign_in_as_user
sign_in_as_admin
get destroy_user_session_path
assert_not warden.authenticated?(:user)
assert_not warden.authenticated?(:admin)
get destroy_user_session_path
assert_not warden.authenticated?(:user)
assert_not warden.authenticated?(:admin)
end
end
test 'sign out as admin should also sign out user if sign_out_all_scopes is true' do
Devise.sign_out_all_scopes = true
sign_in_as_user
sign_in_as_admin
swap Devise, :sign_out_all_scopes => true do
sign_in_as_user
sign_in_as_admin
get destroy_admin_session_path
assert_not warden.authenticated?(:admin)
assert_not warden.authenticated?(:user)
get destroy_admin_session_path
assert_not warden.authenticated?(:admin)
assert_not warden.authenticated?(:user)
end
end
test 'not signed in as admin should not be able to access admins actions' do
get admins_path
assert_redirected_to new_admin_session_path
assert_not warden.authenticated?(:admin)
end
test 'not signed in as admin should not be able to access private route restricted to admins' do
get private_path
assert_redirected_to new_admin_session_path
assert_not warden.authenticated?(:admin)
end
@ -94,7 +85,6 @@ class AuthenticationSanityTest < ActionController::IntegrationTest
sign_in_as_user
assert warden.authenticated?(:user)
assert_not warden.authenticated?(:admin)
get private_path
assert_redirected_to new_admin_session_path
end
@ -236,6 +226,25 @@ class AuthenticationSessionTest < ActionController::IntegrationTest
get '/users'
assert_equal "Cart", @controller.user_session[:cart]
end
test 'does not explode when invalid user class is stored in session' do
klass = User
paths = ActiveSupport::Dependencies.autoload_paths.dup
begin
sign_in_as_user
assert warden.authenticated?(:user)
Object.send :remove_const, :User
ActiveSupport::Dependencies.autoload_paths.clear
visit "/users"
assert_not warden.authenticated?(:user)
ensure
Object.const_set(:User, klass)
ActiveSupport::Dependencies.autoload_paths.replace(paths)
end
end
end
class AuthenticationWithScopesTest < ActionController::IntegrationTest
@ -277,18 +286,6 @@ class AuthenticationWithScopesTest < ActionController::IntegrationTest
end
end
end
test 'uses the mapping from router' do
sign_in_as_user :visit => "/as/sign_in"
assert warden.authenticated?(:user)
assert_not warden.authenticated?(:admin)
end
test 'uses the mapping from nested devise_for call' do
sign_in_as_user :visit => "/devise_for/sign_in"
assert warden.authenticated?(:user)
assert_not warden.authenticated?(:admin)
end
end
class AuthenticationOthersTest < ActionController::IntegrationTest
@ -317,28 +314,21 @@ class AuthenticationOthersTest < ActionController::IntegrationTest
end
end
test 'registration in xml format' do
test 'registration in xml format works when recognizing path' do
assert_nothing_raised do
post user_registration_path(:format => 'xml', :user => {:email => "test@example.com", :password => "invalid"} )
end
end
test 'does not explode when invalid user class is stored in session' do
klass = User
paths = ActiveSupport::Dependencies.autoload_paths.dup
test 'uses the mapping from router' do
sign_in_as_user :visit => "/as/sign_in"
assert warden.authenticated?(:user)
assert_not warden.authenticated?(:admin)
end
begin
sign_in_as_user
assert warden.authenticated?(:user)
Object.send :remove_const, :User
ActiveSupport::Dependencies.autoload_paths.clear
visit "/users"
assert_not warden.authenticated?(:user)
ensure
Object.const_set(:User, klass)
ActiveSupport::Dependencies.autoload_paths.replace(paths)
end
test 'uses the mapping from nested devise_for call' do
sign_in_as_user :visit => "/devise_for/sign_in"
assert warden.authenticated?(:user)
assert_not warden.authenticated?(:admin)
end
end

View file

@ -0,0 +1,31 @@
require 'test_helper'
class OAuthableTest < ActionController::IntegrationTest
FACEBOOK_INFO = {
:username => 'usertest',
:email => 'user@test.com'
}
ACCESS_TOKEN = {
:access_token => "plataformatec"
}
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
stub.post('/oauth/access_token') { [200, {}, ACCESS_TOKEN.to_json] }
stub.get('/me?access_token=plataformatec') { [200, {}, FACEBOOK_INFO.to_json] }
end
User.oauth_configs[:facebook].client.connection.build do |b|
b.adapter :test, stubs
end
setup { Devise::Oauth.short_circuit_authorizers! }
teardown { Devise::Oauth.unshort_circuit_authorizers! }
test "omg" do
assert_difference "User.count", 1 do
get "/users/sign_up"
click_link "Sign in with Facebook"
end
end
end

View file

@ -1,7 +1,17 @@
class User < ActiveRecord::Base
devise :database_authenticatable, :confirmable, :lockable, :recoverable,
:registerable, :rememberable, :timeoutable, :token_authenticatable,
:trackable, :validatable, :oauthable, :oauth_providers => [:github, :twitter]
:trackable, :validatable, :oauthable, :oauth_providers => [:github, :facebook]
attr_accessible :username, :email, :password, :password_confirmation
def self.find_for_facebook_oauth(access_token, signed_in_resource=nil)
user = ActiveSupport::JSON.decode(access_token.get('/me'))
create_with_oauth(user)
end
def self.create_with_oauth(user, &block)
User.create(:username => user["username"], :email => user["email"],
:password => Devise.friendly_token, :confirmed_at => Time.now, &block)
end
end

View file

@ -6,5 +6,5 @@ class User
devise :database_authenticatable, :confirmable, :lockable, :recoverable,
:registerable, :rememberable, :timeoutable, :token_authenticatable,
:trackable, :validatable, :oauthable, :oauth_providers => [:github, :twitter]
:trackable, :validatable, :oauthable, :oauth_providers => [:github, :facebook]
end

View file

@ -130,8 +130,9 @@ Devise.setup do |config|
:access_token_path => '/login/oauth/access_token',
:scope => 'user,public_repo'
config.oauth :twitter, 'APP_ID', 'APP_SECRET',
:site => 'http://twitter.com/'
config.oauth :facebook, 'APP_ID', 'APP_SECRET',
:site => 'https://graph.facebook.com/',
:scope => %w(email offline_access)
# ==> Warden configuration
# If you want to use other strategies, that are not (yet) supported by Devise,

View file

@ -87,11 +87,11 @@ class DefaultRoutingTest < ActionController::TestCase
end
test 'map oauth callbacks' do
assert_recognizes({:controller => 'devise/oauth_callbacks', :action => 'twitter'}, {:path => 'users/oauth/twitter/callback', :method => :get})
assert_recognizes({:controller => 'devise/oauth_callbacks', :action => 'facebook'}, {:path => 'users/oauth/facebook/callback', :method => :get})
assert_recognizes({:controller => 'devise/oauth_callbacks', :action => 'github'}, {:path => 'users/oauth/github/callback', :method => :get})
assert_raise ActionController::RoutingError do
assert_recognizes({:controller => 'devise/oauth_callbacks', :action => 'facebook'}, {:path => 'users/oauth/facebook/callback', :method => :get})
assert_recognizes({:controller => 'devise/oauth_callbacks', :action => 'twitter'}, {:path => 'users/oauth/twitter/callback', :method => :get})
end
end

View file

@ -16,7 +16,7 @@ Webrat.configure do |config|
config.open_error_files = false
end
Faraday.default_adapter = :test
Devise::Oauth.test_mode!
# Add support to load paths so we can overwrite broken webrat setup
$:.unshift File.expand_path('../support', __FILE__)