Add request_keys support. Closes #401.

This commit is contained in:
José Valim 2010-09-21 11:45:44 +02:00
parent fc37436a24
commit b2066cc229
6 changed files with 97 additions and 5 deletions

View File

@ -7,6 +7,7 @@
* sign_out_via is available in the router to configure the method used for sign out (by github.com/martinrehfeld)
* Improved Ajax requests handling in failure app (by github.com/spastorino)
* Add reply-to to e-mail headers by default
* Add request_keys to easily use request specific values (like subdomain) in authentication
* bugfix
* after_sign_in_path_for always receives a resource

View File

@ -68,6 +68,10 @@ module Devise
mattr_accessor :authentication_keys
@@authentication_keys = [ :email ]
# Request keys used when authenticating an user.
mattr_accessor :request_keys
@@request_keys = []
# If http authentication is enabled by default.
mattr_accessor :http_authenticatable
@@http_authenticatable = false

View File

@ -10,6 +10,14 @@ module Devise
#
# * +authentication_keys+: parameters used for authentication. By default [:email].
#
# * +request_keys+: parameters from the request object used for authentication.
# By specifying a symbol (which should be a request method), it will automatically be
# passed to find_for_authentication method and considered in your model lookup.
#
# For instance, if you set :request_keys to [:subdomain], :subdomain will be considered
# as key on authentication. This can also be a hash where the value is a boolean expliciting
# if the value is required or not.
#
# * +http_authenticatable+: if this model allows http authentication. By default true.
# It also accepts an array specifying the strategies that should allow http.
#
@ -66,7 +74,7 @@ module Devise
end
module ClassMethods
Devise::Models.config(self, :authentication_keys, :http_authenticatable, :params_authenticatable)
Devise::Models.config(self, :authentication_keys, :request_keys, :http_authenticatable, :params_authenticatable)
def params_authenticatable?(strategy)
params_authenticatable.is_a?(Array) ?

View File

@ -101,10 +101,12 @@ module Devise
end
# Sets the authentication hash and the password from params_auth_hash or http_auth_hash.
def with_authentication_hash(hash)
self.authentication_hash = hash.slice(*authentication_keys)
self.password = hash[:password]
authentication_keys.all?{ |k| authentication_hash[k].present? }
def with_authentication_hash(auth_values)
self.authentication_hash = {}
self.password = auth_values[:password]
parse_authentication_key_values(auth_values, authentication_keys) &&
parse_authentication_key_values(request_values, request_keys)
end
# Holds the authentication keys.
@ -112,6 +114,33 @@ module Devise
@authentication_keys ||= mapping.to.authentication_keys
end
# Holds request keys.
def request_keys
@request_keys ||= mapping.to.request_keys
end
# Returns values from the request object.
def request_values
keys = request_keys.respond_to?(:keys) ? request_keys.keys : request_keys
keys.inject({}) do |hash, key|
hash[key] = self.request.send(key)
hash
end
end
# Parse authentication keys considering if they should be enforced or not.
def parse_authentication_key_values(hash, keys)
keys.each do |key, enforce|
value = hash[key].presence
if value
self.authentication_hash[key] = value
else
return false unless enforce == false
end
end
true
end
# Holds the authenticatable name for this class. Devise::Strategies::DatabaseAuthenticatable
# becomes simply :database.
def authenticatable_name

View File

@ -20,8 +20,17 @@ Devise.setup do |config|
# authenticating an user, both parameters are required. Remember that those
# parameters are used only when authenticating and not when retrieving from
# session. If you need permissions, you should implement that in a before filter.
# You can also supply hash where the value is a boolean expliciting if authentication
# should be aborted or not if the value is not present. By default is empty.
# config.authentication_keys = [ :email ]
# Configure parameters from the request object used for authentication. Each entry
# given should be a request method and it will automatically be passed to
# find_for_authentication method and considered in your model lookup. For instance,
# if you set :request_keys to [:subdomain], :subdomain will be used on authentication.
# The same considerations mentioned for authentication_keys also apply to request_keys.
# config.request_keys = []
# Tell if authentication through request.params is enabled. True by default.
# config.params_authenticatable = true

View File

@ -333,6 +333,47 @@ class AuthenticationOthersTest < ActionController::IntegrationTest
end
end
class AuthenticationRequestKeysTest < ActionController::IntegrationTest
test 'request keys are used on authentication' do
host! 'foo.bar.baz'
swap Devise, :request_keys => [:subdomain] do
User.expects(:find_for_authentication).with(:subdomain => 'foo', :email => 'user@test.com').returns(create_user)
sign_in_as_user
assert warden.authenticated?(:user)
end
end
test 'invalid request keys raises NoMethodError' do
swap Devise, :request_keys => [:unknown_method] do
assert_raise NoMethodError do
sign_in_as_user
end
assert_not warden.authenticated?(:user)
end
end
test 'blank request keys cause authentication to abort' do
host! 'test.com'
swap Devise, :request_keys => [:subdomain] do
sign_in_as_user
assert_contain "Invalid email or password."
assert_not warden.authenticated?(:user)
end
end
test 'blank request keys cause authentication to abort unless if marked as not required' do
host! 'test.com'
swap Devise, :request_keys => { :subdomain => false } do
sign_in_as_user
assert warden.authenticated?(:user)
end
end
end
class AuthenticationSignOutViaTest < ActionController::IntegrationTest
def sign_in!(scope)
sign_in_as_user(:visit => send("new_#{scope}_session_path"))