From 6829619330d925fc66393fbf6f4b5b976fc25389 Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Thu, 19 Nov 2009 13:53:57 -0200 Subject: [PATCH] Allow overwriting find for authentication method. --- lib/devise/models/authenticatable.rb | 17 ++++++++++++----- test/models/authenticatable_test.rb | 14 ++++++++++++-- test/rails_app/app/models/account.rb | 4 ++++ test/rails_app/app/models/admin.rb | 4 ++++ test/test_helper.rb | 6 +++--- 5 files changed, 35 insertions(+), 10 deletions(-) diff --git a/lib/devise/models/authenticatable.rb b/lib/devise/models/authenticatable.rb index 9354a7c7..7ac60fb2 100644 --- a/lib/devise/models/authenticatable.rb +++ b/lib/devise/models/authenticatable.rb @@ -60,16 +60,23 @@ module Devise end module ClassMethods - # Authenticate a user based on email and password. Returns the - # authenticated user if it's valid or nil. - # Attributes are :email and :password + # Authenticate a user based on configured attribute keys. Returns the + # authenticated user if it's valid or nil. Attributes are by default + # :email and :password, the latter is always required. def authenticate(attributes={}) return unless authentication_keys.all? { |k| attributes[k].present? } conditions = attributes.slice(*authentication_keys) - authenticatable = find(:first, :conditions => conditions) + authenticatable = find_for_authentication(conditions) authenticatable if authenticatable.try(:valid_password?, attributes[:password]) 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. + def find_for_authentication(conditions) + find(:first, :conditions => conditions) + end + # Attempt to find a user by it's email. If not user is found, returns a # new user with an email not found error. def find_or_initialize_with_error_by_email(email) @@ -88,7 +95,7 @@ module Devise # Hook to serialize user from session. Overwrite if you want. def serialize_from_session(keys) klass, id = keys - raise "#{self} cannot serialize from #{klass} session since it's not its ancestors" unless klass <= self + raise "#{self} cannot serialize from #{klass} session since it's not its ancestors" unless klass <= self klass.find_by_id(id) end end diff --git a/test/models/authenticatable_test.rb b/test/models/authenticatable_test.rb index 1a4bda32..600a6bb8 100644 --- a/test/models/authenticatable_test.rb +++ b/test/models/authenticatable_test.rb @@ -92,9 +92,9 @@ class AuthenticatableTest < ActiveSupport::TestCase Devise.stretches = default_stretches end end - + test 'should respect encryptor configuration' do - begin + begin Devise.encryptor = ::Devise::Encryptors::Sha512 user = create_user assert_equal user.encrypted_password, encrypt_password(user, User.pepper, User.stretches, ::Devise::Encryptors::Sha512) @@ -136,6 +136,16 @@ class AuthenticatableTest < ActiveSupport::TestCase end end + test 'should allow overwriting find for authentication conditions' do + admin = Admin.create!(valid_attributes) + assert_not_nil Admin.authenticate(:email => admin.email, :password => admin.password) + end + + test 'should never authenticate an account' do + account = Account.create!(valid_attributes) + assert_nil Account.authenticate(:email => account.email, :password => account.password) + end + test 'should serialize user into session' do user = create_user assert_equal [User, user.id], User.serialize_into_session(user) diff --git a/test/rails_app/app/models/account.rb b/test/rails_app/app/models/account.rb index cac9a24f..1a4e588d 100644 --- a/test/rails_app/app/models/account.rb +++ b/test/rails_app/app/models/account.rb @@ -1,3 +1,7 @@ class Account < ActiveRecord::Base devise :all + + def self.find_for_authentication(conditions) + nil + end end diff --git a/test/rails_app/app/models/admin.rb b/test/rails_app/app/models/admin.rb index 571785b8..ef00cd87 100644 --- a/test/rails_app/app/models/admin.rb +++ b/test/rails_app/app/models/admin.rb @@ -1,3 +1,7 @@ class Admin < ActiveRecord::Base devise :all, :except => [:recoverable, :confirmable, :rememberable, :validatable] + + def self.find_for_authentication(conditions) + last(:conditions => conditions) + end end diff --git a/test/test_helper.rb b/test/test_helper.rb index b0914a56..f82f8711 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -15,12 +15,12 @@ ActiveRecord::Base.logger = Logger.new(nil) ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:") ActiveRecord::Schema.define(:version => 1) do - [:users, :admins].each do |table| + [:users, :admins, :accounts].each do |table| create_table table do |t| t.authenticatable :null => table == :admins - t.string :username if table == :users - if table == :users + if table != :admin + t.string :username t.confirmable t.recoverable t.rememberable