From 3fd79803b9a110c9103f5f834309a5dde8d3c92f Mon Sep 17 00:00:00 2001 From: "yuuji.yaginuma" Date: Thu, 7 May 2020 14:41:25 +0900 Subject: [PATCH] Add `after_login_lock` callback This patch added a callback that execute only when user locked. This callback useful for run something actions(e.g. send notifications to admin) when user locked. --- CHANGELOG.md | 2 ++ lib/sorcery/controller.rb | 4 ++++ lib/sorcery/controller/config.rb | 2 ++ .../controller/submodules/brute_force_protection.rb | 5 ++++- .../controller_brute_force_protection_spec.rb | 12 ++++++++++++ 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1cf5301..e6d20e4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Changelog ## HEAD +* Add `after_login_lock` callback [#236](https://github.com/Sorcery/sorcery/pull/236) + ## 0.16.0 * Add BattleNet Provider [#260](https://github.com/Sorcery/sorcery/pull/260) diff --git a/lib/sorcery/controller.rb b/lib/sorcery/controller.rb index ba4a69fd..a83cf9a9 100644 --- a/lib/sorcery/controller.rb +++ b/lib/sorcery/controller.rb @@ -162,6 +162,10 @@ def after_remember_me!(user) Config.after_remember_me.each { |c| send(c, user) } end + def after_login_lock!(credentials) + Config.after_login_lock.each { |c| send(c, credentials) } + end + def user_class @user_class ||= Config.user_class.to_s.constantize rescue NameError diff --git a/lib/sorcery/controller/config.rb b/lib/sorcery/controller/config.rb index 1a9bf112..38a72fa4 100644 --- a/lib/sorcery/controller/config.rb +++ b/lib/sorcery/controller/config.rb @@ -19,6 +19,7 @@ class << self attr_accessor :before_logout attr_accessor :after_logout attr_accessor :after_remember_me + attr_accessor :after_login_lock def init! @defaults = { @@ -31,6 +32,7 @@ def init! :@before_logout => Set.new, :@after_logout => Set.new, :@after_remember_me => Set.new, + :@after_login_lock => Set.new, :@save_return_to_url => true, :@cookie_domain => nil } diff --git a/lib/sorcery/controller/submodules/brute_force_protection.rb b/lib/sorcery/controller/submodules/brute_force_protection.rb index e4756b7b..055bb04f 100644 --- a/lib/sorcery/controller/submodules/brute_force_protection.rb +++ b/lib/sorcery/controller/submodules/brute_force_protection.rb @@ -22,7 +22,10 @@ module InstanceMethods # Runs as a hook after a failed login. def update_failed_logins_count!(credentials) user = user_class.sorcery_adapter.find_by_credentials(credentials) - user.register_failed_login! if user + if user && !user.login_locked? + user.register_failed_login! + after_login_lock!(credentials) if user.login_locked? + end end # Resets the failed logins counter. diff --git a/spec/controllers/controller_brute_force_protection_spec.rb b/spec/controllers/controller_brute_force_protection_spec.rb index a871839d..4c090c8f 100644 --- a/spec/controllers/controller_brute_force_protection_spec.rb +++ b/spec/controllers/controller_brute_force_protection_spec.rb @@ -22,6 +22,7 @@ def request_test_login it 'counts login retries' do allow(User).to receive(:authenticate) { |&block| block.call(nil, :other) } allow(User.sorcery_adapter).to receive(:find_by_credentials).with(['bla@bla.com', 'blabla']).and_return(user) + allow(user).to receive(:login_locked?).and_return(false) expect(user).to receive(:register_failed_login!).exactly(3).times @@ -37,5 +38,16 @@ def request_test_login get :test_login, params: { email: 'bla@bla.com', password: 'secret' } end + + it 'calls after_login_lock when user locked' do + allow(User).to receive(:authenticate) { |&block| block.call(nil, :other) } + allow(User.sorcery_adapter).to receive(:find_by_credentials).with(['bla@bla.com', 'blabla']).and_return(user) + allow(user).to receive(:register_failed_login!) + allow(user).to receive(:login_locked?).and_return(false, true) + + expect(@controller).to receive(:after_login_lock!).exactly(1).times + + request_test_login + end end end