Merge remote branch 'adahl/master'

This commit is contained in:
José Valim
2010-11-20 20:57:02 +01:00
8 changed files with 89 additions and 13 deletions

View File

@@ -59,14 +59,18 @@ module Devise
mattr_accessor :stretches
@@stretches = 10
# Keys used when authenticating an user.
# Keys used when authenticating a user.
mattr_accessor :authentication_keys
@@authentication_keys = [ :email ]
# Request keys used when authenticating an user.
# Request keys used when authenticating a user.
mattr_accessor :request_keys
@@request_keys = []
# Keys that should be case-insensitive.
mattr_accessor :case_insensitive_keys
@@case_insensitive_keys = [ :email ]
# If http authentication is enabled by default.
mattr_accessor :http_authenticatable
@@http_authenticatable = false

View File

@@ -77,7 +77,7 @@ module Devise
end
module ClassMethods
Devise::Models.config(self, :authentication_keys, :request_keys, :http_authenticatable, :params_authenticatable)
Devise::Models.config(self, :authentication_keys, :request_keys, :case_insensitive_keys, :http_authenticatable, :params_authenticatable)
def params_authenticatable?(strategy)
params_authenticatable.is_a?(Array) ?
@@ -100,6 +100,7 @@ module Devise
# end
#
def find_for_authentication(conditions)
case_insensitive_keys.each { |k| conditions[k].try(:downcase!) }
to_adapter.find_first(conditions)
end
@@ -110,6 +111,8 @@ module Devise
# Find an initialize a group of attributes based on a list of required attributes.
def find_or_initialize_with_errors(required_attributes, attributes, error=:invalid) #:nodoc:
case_insensitive_keys.each { |k| attributes[k].try(:downcase!) }
attributes = attributes.slice(*required_attributes)
attributes.delete_if { |key, value| value.blank? }

View File

@@ -22,6 +22,7 @@ module Devise
included do
attr_reader :password, :current_password
attr_accessor :password_confirmation
before_save :downcase_keys
end
# Generates password encryption based on the given value.
@@ -73,13 +74,18 @@ module Devise
protected
# Downcase case-insensitive keys
def downcase_keys
self.class.case_insensitive_keys.each { |k| self[k].try(:downcase!) }
end
# Digests the password using bcrypt.
def password_digest(password)
::BCrypt::Password.create("#{password}#{self.class.pepper}", :cost => self.class.stretches).to_s
end
module ClassMethods
Devise::Models.config(self, :pepper, :stretches)
Devise::Models.config(self, :pepper, :stretches, :case_insensitive_keys)
# We assume this method already gets the sanitized values from the
# DatabaseAuthenticatable strategy. If you are using this method on

View File

@@ -15,22 +15,27 @@ Devise.setup do |config|
require 'devise/orm/<%= options[:orm] %>'
# ==> Configuration for any authentication mechanism
# Configure which keys are used when authenticating an user. By default is
# Configure which keys are used when authenticating a user. The default is
# just :email. You can configure it to use [:username, :subdomain], so for
# authenticating an user, both parameters are required. Remember that those
# authenticating a 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.
# You can also supply a hash where the value is a boolean determining whether
# or not authentication should be aborted when the value is not present.
# 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
# given should be a request method and it will automatically be passed to the
# 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 = []
# Configure which authentication keys should be case-insensitive.
# These keys will be downcased upon creating or modifying a user and when used
# to authenticate or find a user. Default is :email.
# config.case_insensitive_keys = [ :email ]
# Tell if authentication through request.params is enabled. True by default.
# config.params_authenticatable = true

View File

@@ -1,6 +1,28 @@
require 'test_helper'
class DatabaseAuthenticationTest < ActionController::IntegrationTest
test 'sign in with email of different case should succeed when email is in the list of case insensitive keys' do
create_user(:email => 'Foo@Bar.com')
sign_in_as_user do
fill_in 'email', :with => 'foo@bar.com'
end
assert warden.authenticated?(:user)
end
test 'sign in with email of different case should fail when email is NOT the list of case insensitive keys' do
swap Devise, :case_insensitive_keys => [] do
create_user(:email => 'Foo@Bar.com')
sign_in_as_user do
fill_in 'email', :with => 'foo@bar.com'
end
assert_not warden.authenticated?(:user)
end
end
test 'sign in should not authenticate if not using proper authentication keys' do
swap Devise, :authentication_keys => [:username] do
sign_in_as_user

View File

@@ -27,6 +27,32 @@ class PasswordTest < ActionController::IntegrationTest
click_button 'Change my password'
end
test 'reset password with email of different case should succeed when email is in the list of case insensitive keys' do
create_user(:email => 'Foo@Bar.com')
request_forgot_password do
fill_in 'email', :with => 'foo@bar.com'
end
assert_current_url '/users/sign_in'
assert_contain 'You will receive an email with instructions about how to reset your password in a few minutes.'
end
test 'reset password with email of different case should fail when email is NOT the list of case insensitive keys' do
swap Devise, :case_insensitive_keys => [] do
create_user(:email => 'Foo@Bar.com')
request_forgot_password do
fill_in 'email', :with => 'foo@bar.com'
end
assert_response :success
assert_current_url '/users/password'
assert_have_selector "input[type=email][value='foo@bar.com']"
assert_contain 'not found'
end
end
test 'authenticated user should not be able to visit forgot password page' do
sign_in_as_user
assert warden.authenticated?(:user)

View File

@@ -2,6 +2,16 @@ require 'test_helper'
require 'digest/sha1'
class DatabaseAuthenticatableTest < ActiveSupport::TestCase
test 'should downcase case insensitive keys when saving' do
# case_insensitive_keys is set to :email by default.
email = 'Foo@Bar.com'
user = new_user(:email => email)
assert_equal email, user.email
user.save!
assert_equal email.downcase, user.email
end
test 'should respond to password and password confirmation' do
user = new_user
assert user.respond_to?(:password)

View File

@@ -9,9 +9,9 @@ class ActionDispatch::IntegrationTest
@user ||= begin
user = User.create!(
:username => 'usertest',
:email => 'user@test.com',
:password => '123456',
:password_confirmation => '123456',
:email => options[:email] || 'user@test.com',
:password => options[:password] || '123456',
:password_confirmation => options[:password] || '123456',
:created_at => Time.now.utc
)
user.confirm! unless options[:confirm] == false
@@ -32,7 +32,7 @@ class ActionDispatch::IntegrationTest
def sign_in_as_user(options={}, &block)
user = create_user(options)
visit_with_option options[:visit], new_user_session_path
fill_in 'email', :with => 'user@test.com'
fill_in 'email', :with => options[:email] || 'user@test.com'
fill_in 'password', :with => options[:password] || '123456'
check 'remember me' if options[:remember_me] == true
yield if block_given?