mirror of
https://github.com/heartcombo/devise.git
synced 2022-11-09 12:18:31 -05:00
Move part of the logic in SessionsController#create to the FailureApp. Whenever Warden is invoked with a :recall, the failure app will recall the chosen controller and the action given to recall.
This commit is contained in:
parent
13b8ddf54c
commit
2b5a068246
5 changed files with 94 additions and 45 deletions
|
@ -5,24 +5,17 @@ class Devise::SessionsController < ApplicationController
|
||||||
# GET /resource/sign_in
|
# GET /resource/sign_in
|
||||||
def new
|
def new
|
||||||
Devise::FLASH_MESSAGES.each do |message|
|
Devise::FLASH_MESSAGES.each do |message|
|
||||||
set_now_flash_message :alert, message if params.try(:[], message) == "true"
|
set_now_flash_message :alert, message if params[message] == "true"
|
||||||
end unless flash[:notice]
|
end unless flash[:notice]
|
||||||
build_resource({})
|
clean_up_passwords(build_resource)
|
||||||
render_with_scope :new
|
render_with_scope :new
|
||||||
end
|
end
|
||||||
|
|
||||||
# POST /resource/sign_in
|
# POST /resource/sign_in
|
||||||
def create
|
def create
|
||||||
if resource = warden.authenticate(:scope => resource_name)
|
resource = warden.authenticate!(:scope => resource_name, :recall => "new")
|
||||||
set_flash_message :notice, :signed_in
|
set_flash_message :notice, :signed_in
|
||||||
sign_in_and_redirect(resource_name, resource, true)
|
sign_in_and_redirect(resource_name, resource)
|
||||||
elsif warden.winning_strategy && warden.result != :failure
|
|
||||||
throw :warden, :scope => resource_name
|
|
||||||
else
|
|
||||||
set_now_flash_message :alert, (warden.message || :invalid)
|
|
||||||
clean_up_passwords(build_resource)
|
|
||||||
render_with_scope :new
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# GET /resource/sign_out
|
# GET /resource/sign_out
|
||||||
|
|
|
@ -117,10 +117,10 @@ module Devise
|
||||||
#
|
#
|
||||||
# If just a symbol is given, consider that the user was already signed in
|
# If just a symbol is given, consider that the user was already signed in
|
||||||
# through other means and just perform the redirection.
|
# through other means and just perform the redirection.
|
||||||
def sign_in_and_redirect(resource_or_scope, resource=nil, skip=false)
|
def sign_in_and_redirect(resource_or_scope, resource=nil)
|
||||||
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
||||||
resource ||= resource_or_scope
|
resource ||= resource_or_scope
|
||||||
sign_in(scope, resource) unless skip
|
sign_in(scope, resource) unless warden.user(scope) == resource
|
||||||
redirect_to stored_location_for(scope) || after_sign_in_path_for(resource)
|
redirect_to stored_location_for(scope) || after_sign_in_path_for(resource)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,6 @@ module Devise
|
||||||
include ActionController::UrlFor
|
include ActionController::UrlFor
|
||||||
include ActionController::Redirecting
|
include ActionController::Redirecting
|
||||||
|
|
||||||
mattr_accessor :default_message
|
|
||||||
self.default_message = :unauthenticated
|
|
||||||
|
|
||||||
def self.call(env)
|
def self.call(env)
|
||||||
action(:respond).call(env)
|
action(:respond).call(env)
|
||||||
end
|
end
|
||||||
|
@ -27,6 +24,11 @@ module Devise
|
||||||
self.headers["WWW-Authenticate"] = %(Basic realm=#{Devise.http_authentication_realm.inspect})
|
self.headers["WWW-Authenticate"] = %(Basic realm=#{Devise.http_authentication_realm.inspect})
|
||||||
self.content_type = request.format.to_s
|
self.content_type = request.format.to_s
|
||||||
self.response_body = http_auth_body
|
self.response_body = http_auth_body
|
||||||
|
elsif action = warden_options[:recall]
|
||||||
|
default_message :invalid
|
||||||
|
env["PATH_INFO"] = attempted_path
|
||||||
|
params.merge!(query_string_params)
|
||||||
|
self.response = recall_controller.action(action).call(env)
|
||||||
else
|
else
|
||||||
scope = warden_options[:scope]
|
scope = warden_options[:scope]
|
||||||
store_location!(scope)
|
store_location!(scope)
|
||||||
|
@ -37,7 +39,12 @@ module Devise
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def message
|
def message
|
||||||
@message ||= warden.try(:message) || warden_options[:message] || self.class.default_message
|
@message ||= warden.message || warden_options[:message] || default_message
|
||||||
|
end
|
||||||
|
|
||||||
|
def default_message(message=nil)
|
||||||
|
@default_message = message if message
|
||||||
|
@default_message ||= :unauthenticated
|
||||||
end
|
end
|
||||||
|
|
||||||
def http_auth?
|
def http_auth?
|
||||||
|
@ -59,7 +66,7 @@ module Devise
|
||||||
def query_string_params
|
def query_string_params
|
||||||
case message
|
case message
|
||||||
when Symbol
|
when Symbol
|
||||||
{ message => true }
|
{ message => "true" }
|
||||||
when String
|
when String
|
||||||
{ :message => message }
|
{ :message => message }
|
||||||
else
|
else
|
||||||
|
@ -67,6 +74,10 @@ module Devise
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def recall_controller
|
||||||
|
"#{params[:controller].camelize}Controller".constantize
|
||||||
|
end
|
||||||
|
|
||||||
def warden
|
def warden
|
||||||
env['warden']
|
env['warden']
|
||||||
end
|
end
|
||||||
|
|
|
@ -153,6 +153,7 @@ class ControllerAuthenticableTest < ActionController::TestCase
|
||||||
test 'sign in and redirect uses the stored location' do
|
test 'sign in and redirect uses the stored location' do
|
||||||
user = User.new
|
user = User.new
|
||||||
@controller.session[:"user.return_to"] = "/foo.bar"
|
@controller.session[:"user.return_to"] = "/foo.bar"
|
||||||
|
@mock_warden.expects(:user).with(:user).returns(nil)
|
||||||
@mock_warden.expects(:set_user).with(user, :scope => :user).returns(true)
|
@mock_warden.expects(:set_user).with(user, :scope => :user).returns(true)
|
||||||
@controller.expects(:redirect_to).with("/foo.bar")
|
@controller.expects(:redirect_to).with("/foo.bar")
|
||||||
@controller.sign_in_and_redirect(user)
|
@controller.sign_in_and_redirect(user)
|
||||||
|
@ -160,15 +161,18 @@ class ControllerAuthenticableTest < ActionController::TestCase
|
||||||
|
|
||||||
test 'sign in and redirect uses the configured after sign in path' do
|
test 'sign in and redirect uses the configured after sign in path' do
|
||||||
admin = Admin.new
|
admin = Admin.new
|
||||||
|
@mock_warden.expects(:user).with(:admin).returns(nil)
|
||||||
@mock_warden.expects(:set_user).with(admin, :scope => :admin).returns(true)
|
@mock_warden.expects(:set_user).with(admin, :scope => :admin).returns(true)
|
||||||
@controller.expects(:redirect_to).with(admin_root_path)
|
@controller.expects(:redirect_to).with(admin_root_path)
|
||||||
@controller.sign_in_and_redirect(admin)
|
@controller.sign_in_and_redirect(admin)
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'only redirect if skip is given' do
|
test 'sign in and redirect does not sign in again if user is already signed' do
|
||||||
admin = Admin.new
|
admin = Admin.new
|
||||||
|
@mock_warden.expects(:user).with(:admin).returns(admin)
|
||||||
|
@mock_warden.expects(:set_user).never
|
||||||
@controller.expects(:redirect_to).with(admin_root_path)
|
@controller.expects(:redirect_to).with(admin_root_path)
|
||||||
@controller.sign_in_and_redirect(:admin, admin, true)
|
@controller.sign_in_and_redirect(admin)
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'sign out and redirect uses the configured after sign out path' do
|
test 'sign out and redirect uses the configured after sign out path' do
|
||||||
|
|
|
@ -2,6 +2,9 @@ require 'test_helper'
|
||||||
require 'ostruct'
|
require 'ostruct'
|
||||||
|
|
||||||
class FailureTest < ActiveSupport::TestCase
|
class FailureTest < ActiveSupport::TestCase
|
||||||
|
def self.context(name, &block)
|
||||||
|
instance_eval(&block)
|
||||||
|
end
|
||||||
|
|
||||||
def call_failure(env_params={})
|
def call_failure(env_params={})
|
||||||
env = {
|
env = {
|
||||||
|
@ -9,11 +12,19 @@ class FailureTest < ActiveSupport::TestCase
|
||||||
'REQUEST_URI' => 'http://test.host/',
|
'REQUEST_URI' => 'http://test.host/',
|
||||||
'HTTP_HOST' => 'test.host',
|
'HTTP_HOST' => 'test.host',
|
||||||
'REQUEST_METHOD' => 'GET',
|
'REQUEST_METHOD' => 'GET',
|
||||||
'rack.session' => {}
|
'rack.session' => {},
|
||||||
|
'rack.input' => "",
|
||||||
|
'warden' => OpenStruct.new(:message => nil)
|
||||||
}.merge!(env_params)
|
}.merge!(env_params)
|
||||||
Devise::FailureApp.call(env)
|
Devise::FailureApp.call(env).to_a
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def call_failure_with_http(env_params={})
|
||||||
|
env = { "HTTP_AUTHORIZATION" => "Basic #{ActiveSupport::Base64.encode64("foo:bar")}" }
|
||||||
|
call_failure(env_params.merge!(env))
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'When redirecting' do
|
||||||
test 'return 302 status' do
|
test 'return 302 status' do
|
||||||
assert_equal 302, call_failure.first
|
assert_equal 302, call_failure.first
|
||||||
end
|
end
|
||||||
|
@ -22,13 +33,13 @@ class FailureTest < ActiveSupport::TestCase
|
||||||
assert_equal 'http://test.host/users/sign_in?unauthenticated=true', call_failure.second['Location']
|
assert_equal 'http://test.host/users/sign_in?unauthenticated=true', call_failure.second['Location']
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'uses the proxy failure message' do
|
test 'uses the proxy failure message as symbol' do
|
||||||
warden = OpenStruct.new(:message => :test)
|
warden = OpenStruct.new(:message => :test)
|
||||||
location = call_failure('warden' => warden).second['Location']
|
location = call_failure('warden' => warden).second['Location']
|
||||||
assert_equal 'http://test.host/users/sign_in?test=true', location
|
assert_equal 'http://test.host/users/sign_in?test=true', location
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'uses the given message' do
|
test 'uses the proxy failure message as string' do
|
||||||
warden = OpenStruct.new(:message => 'Hello world')
|
warden = OpenStruct.new(:message => 'Hello world')
|
||||||
location = call_failure('warden' => warden).second['Location']
|
location = call_failure('warden' => warden).second['Location']
|
||||||
assert_equal 'http://test.host/users/sign_in?message=Hello+world', location
|
assert_equal 'http://test.host/users/sign_in?message=Hello+world', location
|
||||||
|
@ -43,4 +54,34 @@ class FailureTest < ActiveSupport::TestCase
|
||||||
assert_match /redirected/, call_failure.last.body
|
assert_match /redirected/, call_failure.last.body
|
||||||
assert_match /\?unauthenticated=true/, call_failure.last.body
|
assert_match /\?unauthenticated=true/, call_failure.last.body
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'For HTTP request' do
|
||||||
|
test 'return 401 status' do
|
||||||
|
assert_equal 401, call_failure_with_http.first
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'return WWW-authenticate headers' do
|
||||||
|
assert_equal 'Basic realm="Application"', call_failure_with_http.second["WWW-Authenticate"]
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'uses the proxy failure message as response body' do
|
||||||
|
warden = OpenStruct.new(:message => :invalid)
|
||||||
|
response = call_failure_with_http('warden' => warden).third
|
||||||
|
assert_equal 'Invalid email or password.', response.body
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'With recall' do
|
||||||
|
test 'calls the original controller' do
|
||||||
|
env = {
|
||||||
|
"action_dispatch.request.parameters" => { :controller => "devise/sessions" },
|
||||||
|
"warden.options" => { :recall => "new", :attempted_path => "/users/sign_in" },
|
||||||
|
"warden" => stub_everything
|
||||||
|
}
|
||||||
|
response = call_failure(env).third
|
||||||
|
assert response.body.include?('<h2>Sign in</h2>')
|
||||||
|
assert response.body.include?('Invalid email or password.')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue