Просмотр исходного кода

Maintenance: Refactored handling of login_failed counter.

Martin Gruner 2 лет назад
Родитель
Сommit
92f8a39479
3 измененных файлов с 17 добавлено и 9 удалено
  1. 10 7
      lib/auth.rb
  2. 6 1
      spec/lib/auth_spec.rb
  3. 1 1
      spec/system/js/q_unit_spec.rb

+ 10 - 7
lib/auth.rb

@@ -8,6 +8,8 @@ class Auth
 
   attr_accessor :increase_login_failed_attempts
 
+  BRUTE_FORCE_SLEEP = 1.second
+
   # Initializes a Auth object for the given user.
   #
   # @param username [String] the user name for the user object which needs an authentication.
@@ -28,20 +30,21 @@ class Auth
   #
   # @return [Boolean] true if the user was authenticated, otherwise false.
   def valid?
-    if !auth_user || !auth_user.can_login?
-      avoid_brute_force_attack
+    # Wrap in a lock to synchronize concurrent requests.
+    validated = auth_user&.user&.with_lock do
+      next false if !auth_user.can_login?
+      next true if backends.valid?
 
-      return false
+      auth_user.increase_login_failed if increase_login_failed_attempts
+      false
     end
 
-    if backends.valid?
+    if validated
       auth_user.update_last_login
       return true
     end
 
     avoid_brute_force_attack
-
-    auth_user.increase_login_failed if increase_login_failed_attempts
     false
   end
 
@@ -49,7 +52,7 @@ class Auth
 
   # Sleep for a second to avoid brute force attacks.
   def avoid_brute_force_attack
-    sleep 1
+    sleep BRUTE_FORCE_SLEEP
   end
 
   def backends

+ 6 - 1
spec/lib/auth_spec.rb

@@ -7,6 +7,10 @@ RSpec.describe Auth do
   let(:user)     { create(:user, password: password) }
   let(:instance) { described_class.new(user.login, password) }
 
+  before do
+    stub_const('Auth::BRUTE_FORCE_SLEEP', 0)
+  end
+
   describe '.valid?' do
     it 'responds to valid?' do
       expect(instance).to respond_to(:valid?)
@@ -83,7 +87,8 @@ RSpec.describe Auth do
         it 'failed login avoids brute force attack' do
           allow(instance).to receive(:sleep)
           instance.valid?
-          expect(instance).to have_received(:sleep).with(1)
+          # sleep receives the stubbed value.
+          expect(instance).to have_received(:sleep).with(0)
         end
       end
 

+ 1 - 1
spec/system/js/q_unit_spec.rb

@@ -2,7 +2,7 @@
 
 require 'rails_helper'
 
-RSpec.describe 'QUnit', type: :system, authenticated_as: false, set_up: true, websocket: false, time_zone: 'Europe/London' do
+RSpec.describe 'QUnit', type: :system, authenticated_as: false, set_up: true, time_zone: 'Europe/London' do
   matcher :pass_qunit_test do
     match do
       actual.has_css?('.total', wait: 120)