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

Fix some unlockable bugs.

This commit is contained in:
José Valim 2010-03-28 23:09:28 +02:00
parent 97b7ba8659
commit 2a082f3e4c
7 changed files with 48 additions and 53 deletions

View file

@ -1,4 +1,5 @@
class Devise::UnlocksController < ApplicationController class Devise::UnlocksController < ApplicationController
prepend_before_filter :ensure_email_as_unlock_strategy
prepend_before_filter :require_no_authentication prepend_before_filter :require_no_authentication
include Devise::Controllers::InternalHelpers include Devise::Controllers::InternalHelpers
@ -31,4 +32,10 @@ class Devise::UnlocksController < ApplicationController
render_with_scope :new render_with_scope :new
end end
end end
protected
def ensure_email_as_unlock_strategy
raise ActionController::UnknownAction unless resource_class.unlock_strategy_enabled?(:email)
end
end end

View file

@ -57,15 +57,9 @@ module Devise
::Devise::Mailer.confirmation_instructions(self).deliver ::Devise::Mailer.confirmation_instructions(self).deliver
end end
# Remove confirmation date and send confirmation instructions, to ensure # Resend confirmation token. This method does not need to generate a new token.
# after sending these instructions the user won't be able to sign in without
# confirming it's account
def resend_confirmation_token def resend_confirmation_token
unless_confirmed do unless_confirmed { send_confirmation_instructions }
generate_confirmation_token
save(:validate => false)
send_confirmation_instructions
end
end end
# Overwrites active? from Devise::Models::Activatable for confirmation # Overwrites active? from Devise::Models::Activatable for confirmation

View file

@ -23,9 +23,10 @@ module Devise
# Lock an user setting it's locked_at to actual time. # Lock an user setting it's locked_at to actual time.
def lock_access! def lock_access!
return true if access_locked?
self.locked_at = Time.now self.locked_at = Time.now
if unlock_strategy_enabled?(:email) if self.class.unlock_strategy_enabled?(:email)
generate_unlock_token generate_unlock_token
send_unlock_instructions send_unlock_instructions
end end
@ -55,11 +56,7 @@ module Devise
# Resend the unlock instructions if the user is locked. # Resend the unlock instructions if the user is locked.
def resend_unlock_token def resend_unlock_token
if_access_locked do if_access_locked { send_unlock_instructions }
generate_unlock_token unless unlock_token.present?
save(:validate => false)
send_unlock_instructions
end
end end
# Overwrites active? from Devise::Models::Activatable for locking purposes # Overwrites active? from Devise::Models::Activatable for locking purposes
@ -82,10 +79,7 @@ module Devise
self.failed_attempts = 0 self.failed_attempts = 0
else else
self.failed_attempts += 1 self.failed_attempts += 1
if failed_attempts > self.class.maximum_attempts lock_access! if failed_attempts > self.class.maximum_attempts
lock_access!
return false
end
end end
save(:validate => false) if changed? save(:validate => false) if changed?
result result
@ -100,7 +94,7 @@ module Devise
# Tells if the lock is expired if :time unlock strategy is active # Tells if the lock is expired if :time unlock strategy is active
def lock_expired? def lock_expired?
if unlock_strategy_enabled?(:time) if self.class.unlock_strategy_enabled?(:time)
locked_at && locked_at < self.class.unlock_in.ago locked_at && locked_at < self.class.unlock_in.ago
else else
false false
@ -118,11 +112,6 @@ module Devise
end end
end end
# Is the unlock enabled for the given unlock strategy?
def unlock_strategy_enabled?(strategy)
[:both, strategy].include?(self.class.unlock_strategy)
end
module ClassMethods module ClassMethods
# Attempt to find a user by it's email. If a record is found, send new # Attempt to find a user by it's email. If a record is found, send new
# unlock instructions to it. If not user is found, returns a new user # unlock instructions to it. If not user is found, returns a new user
@ -144,6 +133,11 @@ module Devise
lockable lockable
end end
# Is the unlock enabled for the given unlock strategy?
def unlock_strategy_enabled?(strategy)
[:both, strategy].include?(self.unlock_strategy)
end
Devise::Models.config(self, :maximum_attempts, :unlock_strategy, :unlock_in) Devise::Models.config(self, :maximum_attempts, :unlock_strategy, :unlock_in)
end end
end end

View file

@ -36,6 +36,15 @@ class LockTest < ActionController::IntegrationTest
assert_equal 0, ActionMailer::Base.deliveries.size assert_equal 0, ActionMailer::Base.deliveries.size
end end
test 'unlocked pages should not be available if email strategy is disabled' do
visit new_user_unlock_path
swap Devise, :unlock_strategy => :time do
assert_raise AbstractController::ActionNotFound do
visit new_user_unlock_path
end
end
end
test 'user with invalid unlock token should not be able to unlock an account' do test 'user with invalid unlock token should not be able to unlock an account' do
visit_user_unlock_with_token('invalid_token') visit_user_unlock_with_token('invalid_token')
@ -60,7 +69,6 @@ class LockTest < ActionController::IntegrationTest
test "sign in user automatically after unlocking it's account" do test "sign in user automatically after unlocking it's account" do
user = create_user(:locked => true) user = create_user(:locked => true)
visit_user_unlock_with_token(user.unlock_token) visit_user_unlock_with_token(user.unlock_token)
assert warden.authenticated?(:user) assert warden.authenticated?(:user)
end end
@ -71,6 +79,16 @@ class LockTest < ActionController::IntegrationTest
assert_not warden.authenticated?(:user) assert_not warden.authenticated?(:user)
end end
test "user should not send a new e-mail if already locked" do
user = create_user(:locked => true)
user.update_attribute(:failed_attempts, User.maximum_attempts + 1)
ActionMailer::Base.deliveries.clear
sign_in_as_user(:password => "invalid")
assert_contain 'Invalid email or password.'
assert ActionMailer::Base.deliveries.empty?
end
test 'error message is configurable by resource name' do test 'error message is configurable by resource name' do
store_translations :en, :devise => { store_translations :en, :devise => {
:sessions => { :admin => { :locked => "You are locked!" } } :sessions => { :admin => { :locked => "You are locked!" } }

View file

@ -11,15 +11,6 @@ class ConfirmableTest < ActiveSupport::TestCase
assert_not_nil create_user.confirmation_token assert_not_nil create_user.confirmation_token
end end
test 'should regenerate confirmation token each time' do
user = create_user
3.times do
token = user.confirmation_token
user.resend_confirmation_token
assert_not_equal token, user.confirmation_token
end
end
test 'should never generate the same confirmation token for different users' do test 'should never generate the same confirmation token for different users' do
confirmation_tokens = [] confirmation_tokens = []
3.times do 3.times do
@ -137,13 +128,6 @@ class ConfirmableTest < ActiveSupport::TestCase
assert_equal "not found", confirmation_user.errors[:email].join assert_equal "not found", confirmation_user.errors[:email].join
end end
test 'should generate a confirmation token before send the confirmation instructions email' do
user = create_user
token = user.confirmation_token
confirmation_user = User.send_confirmation_instructions(:email => user.email)
assert_not_equal token, user.reload.confirmation_token
end
test 'should send email instructions for the user confirm it\'s email' do test 'should send email instructions for the user confirm it\'s email' do
user = create_user user = create_user
assert_email_sent do assert_email_sent do

View file

@ -37,7 +37,7 @@ class LockableTest < ActiveSupport::TestCase
assert_equal 0, user.reload.failed_attempts assert_equal 0, user.reload.failed_attempts
end end
test "should verify wheter a user is locked or not" do test "should verify whether a user is locked or not" do
user = create_user user = create_user
assert_not user.access_locked? assert_not user.access_locked?
user.lock_access! user.lock_access!
@ -64,6 +64,14 @@ class LockableTest < ActiveSupport::TestCase
assert 0, user.reload.failed_attempts assert 0, user.reload.failed_attempts
end end
test "should not lock a locked account" do
user = create_user
user.lock_access!
assert_no_difference "ActionMailer::Base.deliveries.size" do
user.lock_access!
end
end
test 'should not unlock an unlocked user' do test 'should not unlock an unlocked user' do
user = create_user user = create_user
assert_not user.unlock_access! assert_not user.unlock_access!
@ -101,16 +109,6 @@ class LockableTest < ActiveSupport::TestCase
assert_not_nil user.unlock_token assert_not_nil user.unlock_token
end end
test 'should not regenerate unlock token if it already exists' do
user = create_user
user.lock!
3.times do
token = user.unlock_token
user.resend_unlock_token
assert_equal token, user.unlock_token
end
end
test "should never generate the same unlock token for different users" do test "should never generate the same unlock token for different users" do
unlock_tokens = [] unlock_tokens = []
3.times do 3.times do

View file

@ -33,7 +33,7 @@ class ActionDispatch::IntegrationTest
user = create_user(options) user = create_user(options)
get new_user_session_path unless options[:visit] == false get new_user_session_path unless options[:visit] == false
fill_in 'email', :with => 'user@test.com' fill_in 'email', :with => 'user@test.com'
fill_in 'password', :with => '123456' fill_in 'password', :with => options[:password] || '123456'
check 'remember me' if options[:remember_me] == true check 'remember me' if options[:remember_me] == true
yield if block_given? yield if block_given?
click_button 'Sign In' click_button 'Sign In'