Skip to content

Commit

Permalink
Create a model hook around the lockable warden hook to reset attempts
Browse files Browse the repository at this point in the history
Resetting failed attempts after sign in happened inside a warden hook
specific for the lockable module, but that was hidden inside the hook
implementation and didn't allow any user customization.

One such customization needed for example is to direct these updates to
a write DB when using a multi-DB setup. With the logic hidden in the
warden hook this wasn't possible, now that it's exposed in a model
method much like trackable, we can override the model method to wrap it
in a connection switch block for example, point to a write DB, and
simply call `super`.

Closes #5310
Related to #5264 and #5133
  • Loading branch information
carlosantoniodasilva committed Mar 22, 2021
1 parent 0cd72a5 commit 28a4cf8
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 6 deletions.
7 changes: 2 additions & 5 deletions lib/devise/hooks/lockable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@
# After each sign in, if resource responds to failed_attempts, sets it to 0
# This is only triggered when the user is explicitly set (with set_user)
Warden::Manager.after_set_user except: :fetch do |record, warden, options|
if record.respond_to?(:failed_attempts) && warden.authenticated?(options[:scope])
unless record.failed_attempts.to_i.zero?
record.failed_attempts = 0
record.save(validate: false)
end
if record.respond_to?(:reset_failed_attempts!) && warden.authenticated?(options[:scope])
record.reset_failed_attempts!
end
end
10 changes: 9 additions & 1 deletion lib/devise/models/lockable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ def unlock_access!
save(validate: false)
end

# Resets failed attempts counter to 0.
def reset_failed_attempts!
if respond_to?(:failed_attempts) && !failed_attempts.to_i.zero?
self.failed_attempts = 0
save(validate: false)
end
end

# Verifies whether a user is locked or not.
def access_locked?
!!locked_at && !lock_expired?
Expand Down Expand Up @@ -110,7 +118,7 @@ def valid_for_authentication?
false
end
end

def increment_failed_attempts
self.class.increment_counter(:failed_attempts, id)
reload
Expand Down

0 comments on commit 28a4cf8

Please sign in to comment.