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

Added navigational formats to specify when it should return a 302 and when a 401, closes #234 and #249.

This commit is contained in:
José Valim 2010-05-16 19:13:20 +02:00
parent a65fd873dd
commit bff64a6291
9 changed files with 63 additions and 30 deletions

View file

@ -18,6 +18,7 @@
* No need to append ?unauthenticated=true in URLs anymore since Flash was moved to a middleware in Rails 3.
* :activatable is included by default in your models.
* Allow to set cookie domain for the remember token. (by github.com/mantas)
* Added navigational formats to specify when it should return a 302 and when a 401.
* bug fix
* Fix a bug with STI.

View file

@ -147,6 +147,9 @@ module Devise
mattr_accessor :token_authentication_key
@@token_authentication_key = :auth_token
mattr_accessor :navigational_formats
@@navigational_formats = [:html]
# Private methods to interface with Warden.
mattr_accessor :warden_config
@@warden_config = nil

View file

@ -64,7 +64,7 @@ module Devise
end
def http_auth?
request.authorization
!Devise.navigational_formats.include?(request.format.to_sym) || request.xhr?
end
def http_auth_body
@ -97,7 +97,7 @@ module Devise
# yet, but we still need to store the uri based on scope, so different scopes
# would never use the same uri to redirect.
def store_location!
session[:"#{scope}_return_to"] = attempted_path if request && request.get?
session[:"#{scope}_return_to"] = attempted_path if request.get? && !http_auth?
end
end
end

View file

@ -4,6 +4,11 @@ Devise.setup do |config|
# Configure the e-mail address which will be shown in DeviseMailer.
config.mailer_sender = "please-change-me@config-initializers-devise.com"
# ==> ORM configuration
# Load and configure the ORM. Supports :active_record (default), :mongoid
# (bson_ext recommended) and :data_mapper (experimental).
require 'devise/orm/<%= options[:orm] %>'
# ==> Configuration for any authentication mechanism
# Configure which keys are used when authenticating an user. By default is
# just :email. You can configure it to use [:username, :subdomain], so for
@ -85,11 +90,7 @@ Devise.setup do |config|
# Defines name of the authentication token params key
# config.token_authentication_key = :auth_token
# ==> General configuration
# Load and configure the ORM. Supports :active_record (default), :mongoid
# (bson_ext recommended) and :data_mapper (experimental).
require 'devise/orm/<%= options[:orm] %>'
# ==> Scopes configuration
# Turn scoped views on. Before rendering "sessions/new", it will first check for
# "sessions/users/new". It's turned off by default because it's slower if you
# are using only default views.
@ -105,6 +106,15 @@ Devise.setup do |config|
# role declared in your routes.
# config.default_scope = :user
# ==> Navigation configuration
# Lists the formats that should be treated as navigational. Formats like
# :html, should redirect to the sign in page when the user does not have
# access, but formats like :xml or :json, should return 401.
# If you have any extra navigational formats, like :iphone or :mobile, you
# should add them to the navigational formats lists. Default is [:html]
# config.navigational_formats = [:html, :iphone]
# ==> Warden configuration
# If you want to use other strategies, that are not (yet) supported by Devise,
# you can configure them inside the config.warden block. The example below
# allows you to setup OAuth, using http://github.com/roman/warden_oauth

View file

@ -8,11 +8,12 @@ class FailureTest < ActiveSupport::TestCase
def call_failure(env_params={})
env = {
'warden.options' => { :scope => :user },
'REQUEST_URI' => 'http://test.host/',
'HTTP_HOST' => 'test.host',
'REQUEST_METHOD' => 'GET',
'warden.options' => { :scope => :user },
'rack.session' => {},
'action_dispatch.request.formats' => Array(env_params.delete('formats') || :html),
'rack.input' => "",
'warden' => OpenStruct.new(:message => nil)
}.merge!(env_params)
@ -21,11 +22,6 @@ class FailureTest < ActiveSupport::TestCase
@request = ActionDispatch::Request.new(env)
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
call_failure
@ -61,22 +57,41 @@ class FailureTest < ActiveSupport::TestCase
assert_match /redirected/, @response.last.body
assert_match /users\/sign_in/, @response.last.body
end
test 'works for any navigational format' do
swap Devise, :navigational_formats => [:xml] do
call_failure('formats' => :xml)
assert_equal 302, @response.first
end
end
end
context 'For HTTP request' do
test 'return 401 status' do
call_failure_with_http
call_failure('formats' => :xml)
assert_equal 401, @response.first
end
test 'return WWW-authenticate headers' do
call_failure_with_http
call_failure('formats' => :xml)
assert_equal 'Basic realm="Application"', @response.second["WWW-Authenticate"]
end
test 'uses the proxy failure message as response body' do
call_failure_with_http('warden' => OpenStruct.new(:message => :invalid))
assert_equal 'Invalid email or password.', @response.third.body
call_failure('formats' => :xml, 'warden' => OpenStruct.new(:message => :invalid))
assert_match '<error>Invalid email or password.</error>', @response.third.body
end
test 'works for any non navigational format' do
swap Devise, :navigational_formats => [] do
call_failure('formats' => :html)
assert_equal 401, @response.first
end
end
test 'works for xml http requests' do
call_failure('formats' => :html, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest')
assert_equal 401, @response.first
end
end

View file

@ -155,7 +155,6 @@ class AuthenticationTest < ActionController::IntegrationTest
test 'redirect to default url if no other was configured' do
sign_in_as_user
assert_template 'home/index'
assert_nil session[:"user_return_to"]
end
@ -188,6 +187,12 @@ class AuthenticationTest < ActionController::IntegrationTest
assert_nil session[:"user_return_to"]
end
test 'xml http requests does not store urls for redirect' do
get users_path, {}, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest'
assert_equal 401, response.status
assert_nil session[:"user_return_to"]
end
test 'redirect to configured home path for a given scope after sign in' do
sign_in_as_admin
assert_equal "/admin_area/home", @request.path

View file

@ -5,8 +5,7 @@ class HttpAuthenticationTest < ActionController::IntegrationTest
test 'sign in should authenticate with http' do
sign_in_as_new_user_with_http
assert_response :success
assert_template 'users/index'
assert_contain 'Welcome'
assert_match '<email>user@test.com</email>', response.body
assert warden.authenticated?(:user)
end
@ -17,10 +16,10 @@ class HttpAuthenticationTest < ActionController::IntegrationTest
end
test 'uses the request format as response content type' do
sign_in_as_new_user_with_http("unknown", "123456", :xml)
sign_in_as_new_user_with_http("unknown")
assert_equal 401, status
assert_equal "application/xml; charset=utf-8", headers["Content-Type"]
assert response.body.include?("<error>Invalid email or password.</error>")
assert_match "<error>Invalid email or password.</error>", response.body
end
test 'returns a custom response with www-authenticate and chosen realm' do
@ -33,19 +32,18 @@ class HttpAuthenticationTest < ActionController::IntegrationTest
test 'sign in should authenticate with http even with specific authentication keys' do
swap Devise, :authentication_keys => [:username] do
sign_in_as_new_user_with_http "usertest"
sign_in_as_new_user_with_http("usertest")
assert_response :success
assert_template 'users/index'
assert_contain 'Welcome'
assert_match '<email>user@test.com</email>', response.body
assert warden.authenticated?(:user)
end
end
private
def sign_in_as_new_user_with_http(username="user@test.com", password="123456", format=:html)
def sign_in_as_new_user_with_http(username="user@test.com", password="123456")
user = create_user
get users_path(:format => format), {}, "HTTP_AUTHORIZATION" => "Basic #{ActiveSupport::Base64.encode64("#{username}:#{password}")}"
get users_path(:format => :xml), {}, "HTTP_AUTHORIZATION" => "Basic #{ActiveSupport::Base64.encode64("#{username}:#{password}")}"
user
end
end

View file

@ -18,8 +18,7 @@ class TokenAuthenticationTest < ActionController::IntegrationTest
sign_in_as_new_user_with_token(:http_auth => true)
assert_response :success
assert_template 'users/index'
assert_contain 'Welcome'
assert_match '<email>user@test.com</email>', response.body
assert warden.authenticated?(:user)
end
end
@ -78,7 +77,7 @@ class TokenAuthenticationTest < ActionController::IntegrationTest
if options[:http_auth]
header = "Basic #{ActiveSupport::Base64.encode64("#{VALID_AUTHENTICATION_TOKEN}:X")}"
get users_path, {}, "HTTP_AUTHORIZATION" => header
get users_path(:format => :xml), {}, "HTTP_AUTHORIZATION" => header
else
visit users_path(options[:auth_token_key].to_sym => options[:auth_token])
end

View file

@ -1,8 +1,10 @@
class UsersController < ApplicationController
before_filter :authenticate_user!
respond_to :html, :xml
def index
user_session[:cart] = "Cart"
respond_with(current_user)
end
def expire