From df70443652b45e15acecef1ebaaec4b4ae09ca1d Mon Sep 17 00:00:00 2001 From: Malick Diarra Date: Wed, 26 Jun 2024 10:42:58 -0400 Subject: [PATCH 1/8] changelog: User-Facing Improvements, Authentication, Let users know how long they have until they can try to enter password in again --- app/controllers/users/sessions_controller.rb | 12 ++++++++++- config/locales/en.yml | 2 +- config/locales/es.yml | 2 +- config/locales/fr.yml | 2 +- config/locales/zh.yml | 2 +- .../users/sessions_controller_spec.rb | 21 +++++++++++++++++++ 6 files changed, 36 insertions(+), 5 deletions(-) diff --git a/app/controllers/users/sessions_controller.rb b/app/controllers/users/sessions_controller.rb index 135ef08f9cd..2c7df8dd3e8 100644 --- a/app/controllers/users/sessions_controller.rb +++ b/app/controllers/users/sessions_controller.rb @@ -74,10 +74,20 @@ def increment_session_bad_password_count def process_locked_out_session warden.logout(:user) warden.lock! - flash[:error] = t('errors.sign_in.bad_password_limit') + + flash[:error] = t( + 'errors.sign_in.bad_password_limit', + time_left: locked_out_time_remaining, + ) redirect_to root_url end + def locked_out_time_remaining + locked_at = session[:max_bad_passwords_at] + window = IdentityConfig.store.max_bad_passwords_window_in_seconds.seconds + distance_of_time_in_words(Time.zone.now, (locked_at + window), true, except: :seconds) + end + def valid_captcha_result? return @valid_captcha_result if defined?(@valid_captcha_result) @valid_captcha_result = SignInRecaptchaForm.new(**recaptcha_form_args).submit( diff --git a/config/locales/en.yml b/config/locales/en.yml index 3c931ad39a4..01ae8d1bfac 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -744,7 +744,7 @@ errors.messages.wrong_length.one: is the wrong length (should be 1 character) errors.messages.wrong_length.other: is the wrong length (should be %{count} characters) errors.piv_cac_setup.unique_name: That name is already taken. Please choose a different name. errors.registration.terms: Before you can continue, you must give us permission. Please check the box below and then click continue. -errors.sign_in.bad_password_limit: You have exceeded the maximum sign in attempts. +errors.sign_in.bad_password_limit: You have exceeded the maximum sign in attempts. You must wait %{time_left} before trying again. errors.two_factor_auth_setup.must_select_additional_option: Select an additional authentication method. errors.two_factor_auth_setup.must_select_option: Select an authentication method. errors.verify_personal_key.rate_limited: You tried too many times, please try again in %{timeout}. diff --git a/config/locales/es.yml b/config/locales/es.yml index e32ab74ce44..a45c68330f2 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -755,7 +755,7 @@ errors.messages.wrong_length.one: tiene la longitud incorrecta (debe ser de 1 c errors.messages.wrong_length.other: tiene la longitud incorrecta (debe ser de %{count} caracteres) errors.piv_cac_setup.unique_name: Ese nombre ya fue seleccionado. Elija un nombre diferente. errors.registration.terms: Antes de continuar, debe darnos permiso. Marque la casilla a continuación y luego haga clic en continuar. -errors.sign_in.bad_password_limit: Superó el número máximo de intentos de inicio de sesión. +errors.sign_in.bad_password_limit: Superó el número máximo de intentos de inicio de sesión. Debe esperar %{time_left} antes de volver a intentarlo. errors.two_factor_auth_setup.must_select_additional_option: Seleccione un método de autenticación adicional. errors.two_factor_auth_setup.must_select_option: Seleccione un método de autenticación. errors.verify_personal_key.rate_limited: Lo intentó demasiadas veces; vuelva a intentarlo en %{timeout}. diff --git a/config/locales/fr.yml b/config/locales/fr.yml index a70d855ed5f..fac6100576f 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -744,7 +744,7 @@ errors.messages.wrong_length.one: n’est pas de la bonne longueur (devrait êtr errors.messages.wrong_length.other: n’est pas de la bonne longueur (devrait être de %{count} caractères) errors.piv_cac_setup.unique_name: Ce nom est déjà pris. Veuillez choisir un autre nom. errors.registration.terms: Avant de pouvoir continuer, vous devez nous donner la permission. Veuillez cocher la case ci-dessous, puis cliquez sur Suite. -errors.sign_in.bad_password_limit: Vous avez dépassé le nombre maximal de tentatives de connexion. +errors.sign_in.bad_password_limit: Vous avez dépassé le nombre maximal de tentatives de connexion. Vous devez attendre %{time_left} avant de réessayer. errors.two_factor_auth_setup.must_select_additional_option: Sélectionnez une méthode d’authentification supplémentaire. errors.two_factor_auth_setup.must_select_option: Sélectionnez une méthode d’authentification. errors.verify_personal_key.rate_limited: Vous avez essayé trop de fois, veuillez réessayer dans %{timeout}. diff --git a/config/locales/zh.yml b/config/locales/zh.yml index a8b5be89b5e..f77d63a41f5 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -755,7 +755,7 @@ errors.messages.wrong_length.one: 长度不对(应当是 1 个字符) errors.messages.wrong_length.other: 长度不对(应当是 %{count} 个字符) errors.piv_cac_setup.unique_name: 这个名字已被使用。请选择一个不同的名字。 errors.registration.terms: 在你能继续之前,你必须授予我们你的同意。请在下面的框打勾然后点击继续。 -errors.sign_in.bad_password_limit: 你已超出登录尝试允许最多次数。 +errors.sign_in.bad_password_limit: 你已超出登录尝试允许最多次数。你必须等待 %{time_left} 才能重试。 errors.two_factor_auth_setup.must_select_additional_option: 请选择一个额外的身份证实方法。 errors.two_factor_auth_setup.must_select_option: 选择一个身份证实方法。 errors.verify_personal_key.rate_limited: 你尝试了太多次。请在 %{timeout}后再试。 diff --git a/spec/controllers/users/sessions_controller_spec.rb b/spec/controllers/users/sessions_controller_spec.rb index e50c63953fe..8ef36321017 100644 --- a/spec/controllers/users/sessions_controller_spec.rb +++ b/spec/controllers/users/sessions_controller_spec.rb @@ -116,6 +116,27 @@ end end + context 'locked out session' do + let(:locked_at) { Time.zone.now } + let(:user) { create(:user, :fully_registered) } + + before do + allow(subject).to receive(:session_bad_password_count_max_exceeded?). + and_return(true) + allow(subject).to receive(:clear_session_bad_password_count_if_window_expired). + and_return(nil) + allow(IdentityConfig.store).to receive(:max_bad_passwords_window_in_seconds).and_return(600) + end + + it 'renders an error letting user know they are locked out for a period of time' do + session[:max_bad_passwords_at] = locked_at + post :create, params: { user: { email: user.email.upcase, password: user.password } } + + expect(response).to redirect_to root_url + expect(flash[:error]).to be_truthy + end + end + it 'tracks the unsuccessful authentication for existing user' do user = create(:user, :fully_registered) From 3a0daca554736fe3f73e9e4b3100fbdf3fe536ed Mon Sep 17 00:00:00 2001 From: Malick Diarra Date: Wed, 26 Jun 2024 16:06:01 -0400 Subject: [PATCH 2/8] address comments and fix specs --- app/controllers/users/sessions_controller.rb | 2 +- .../users/sessions_controller_spec.rb | 27 ++++++++++++------- spec/features/visitors/bad_password_spec.rb | 19 +++++++++++-- spec/requests/rack_attack_spec.rb | 8 ++++++ 4 files changed, 44 insertions(+), 12 deletions(-) diff --git a/app/controllers/users/sessions_controller.rb b/app/controllers/users/sessions_controller.rb index 2c7df8dd3e8..38cbc311c4c 100644 --- a/app/controllers/users/sessions_controller.rb +++ b/app/controllers/users/sessions_controller.rb @@ -85,7 +85,7 @@ def process_locked_out_session def locked_out_time_remaining locked_at = session[:max_bad_passwords_at] window = IdentityConfig.store.max_bad_passwords_window_in_seconds.seconds - distance_of_time_in_words(Time.zone.now, (locked_at + window), true, except: :seconds) + distance_of_time_in_words(Time.zone.now, (locked_at + window), true) end def valid_captcha_result? diff --git a/spec/controllers/users/sessions_controller_spec.rb b/spec/controllers/users/sessions_controller_spec.rb index 8ef36321017..3563abbce3d 100644 --- a/spec/controllers/users/sessions_controller_spec.rb +++ b/spec/controllers/users/sessions_controller_spec.rb @@ -119,13 +119,17 @@ context 'locked out session' do let(:locked_at) { Time.zone.now } let(:user) { create(:user, :fully_registered) } + let(:locked_out_time_remaining) do + distance_of_time_in_words(Time.zone.now, (locked_at + 600.seconds), true) + end before do allow(subject).to receive(:session_bad_password_count_max_exceeded?). and_return(true) allow(subject).to receive(:clear_session_bad_password_count_if_window_expired). and_return(nil) - allow(IdentityConfig.store).to receive(:max_bad_passwords_window_in_seconds).and_return(600) + allow(subject).to receive(:locked_out_time_remaining). + and_return(locked_out_time_remaining) end it 'renders an error letting user know they are locked out for a period of time' do @@ -133,7 +137,19 @@ post :create, params: { user: { email: user.email.upcase, password: user.password } } expect(response).to redirect_to root_url - expect(flash[:error]).to be_truthy + expect(flash[:error]).to eq( + t( + 'errors.sign_in.bad_password_limit', + time_left: locked_out_time_remaining, + ), + ) + end + + it 'tracks unsuccessful authentication for too many auth failures' do + allow(subject).to receive(:session_bad_password_count_max_exceeded?).and_return(true) + mock_email_parameter = { email: 'bob@example.com' } + + post :create, params: { user: { **mock_email_parameter, password: 'eatCake!' } } end end @@ -178,13 +194,6 @@ post :create, params: { user: { email: 'foo@example.com', password: 'password' } } end - it 'tracks unsuccessful authentication for too many auth failures' do - allow(subject).to receive(:session_bad_password_count_max_exceeded?).and_return(true) - mock_email_parameter = { email: 'bob@example.com' } - - post :create, params: { user: { **mock_email_parameter, password: 'eatCake!' } } - end - it 'tracks unsuccessful authentication for locked out user' do user = create( :user, diff --git a/spec/features/visitors/bad_password_spec.rb b/spec/features/visitors/bad_password_spec.rb index 53fe0364040..95f6faf5012 100644 --- a/spec/features/visitors/bad_password_spec.rb +++ b/spec/features/visitors/bad_password_spec.rb @@ -1,6 +1,7 @@ require 'rails_helper' RSpec.feature 'Visitor signs in with bad passwords and gets locked out' do + include ActionView::Helpers::DateHelper let(:user) { create(:user, :fully_registered) } let(:bad_password) { 'badpassword' } @@ -15,14 +16,28 @@ expect(page).to have_content(error_message) expect(page).to have_current_path(new_user_session_path) end + locked_out_time_remaining = distance_of_time_in_words(5.minutes) + allow_any_instance_of(Users::SessionsController).to receive(:locked_out_time_remaining). + and_return(locked_out_time_remaining) 2.times do fill_in_credentials_and_submit(user.email, bad_password) expect(page).to have_current_path(new_user_session_path) - expect(page).to have_content(t('errors.sign_in.bad_password_limit')) + expect(page).to have_content( + t( + 'errors.sign_in.bad_password_limit', + time_left: locked_out_time_remaining, + ), + ) end fill_in_credentials_and_submit(user.email, user.password) expect(page).to have_current_path(new_user_session_path) - expect(page).to have_content(t('errors.sign_in.bad_password_limit')) + expect(page).to have_content( + t( + 'errors.sign_in.bad_password_limit', + time_left: locked_out_time_remaining, + ), + ) + travel_to(IdentityConfig.store.max_bad_passwords_window_in_seconds.seconds.from_now) do fill_in_credentials_and_submit(user.email, bad_password) expect(page).to have_content(error_message) diff --git a/spec/requests/rack_attack_spec.rb b/spec/requests/rack_attack_spec.rb index 491f1c25f89..c4bef6d4697 100644 --- a/spec/requests/rack_attack_spec.rb +++ b/spec/requests/rack_attack_spec.rb @@ -249,6 +249,10 @@ it 'throttles with a custom response' do analytics = FakeAnalytics.new + # Needed because time logic wont work since we freeze time. + locked_out_time_remaining = 5.minutes + allow_any_instance_of(Users::SessionsController).to receive(:locked_out_time_remaining). + and_return(locked_out_time_remaining) allow(Analytics).to receive(:new).and_return(analytics) allow(analytics).to receive(:track_event) @@ -315,6 +319,10 @@ context 'when number of logins per email + ip is higher than limit per period' do it 'throttles with a custom response' do analytics = FakeAnalytics.new + # Needed because time logic wont work since we freeze time. + locked_out_time_remaining = 5.minutes + allow_any_instance_of(Users::SessionsController).to receive(:locked_out_time_remaining). + and_return(locked_out_time_remaining) allow(Analytics).to receive(:new).and_return(analytics) allow(analytics).to receive(:track_event) analytics_hash = { type: 'logins/email+ip' } From 7cbceab337d84e51aa8cfa1c7b6ec4392c6aa050 Mon Sep 17 00:00:00 2001 From: Malick Diarra Date: Mon, 1 Jul 2024 11:13:57 -0400 Subject: [PATCH 3/8] update session controller to not stub method --- .../controllers/users/sessions_controller_spec.rb | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/spec/controllers/users/sessions_controller_spec.rb b/spec/controllers/users/sessions_controller_spec.rb index 3563abbce3d..85bbf5d66fa 100644 --- a/spec/controllers/users/sessions_controller_spec.rb +++ b/spec/controllers/users/sessions_controller_spec.rb @@ -119,33 +119,36 @@ context 'locked out session' do let(:locked_at) { Time.zone.now } let(:user) { create(:user, :fully_registered) } - let(:locked_out_time_remaining) do - distance_of_time_in_words(Time.zone.now, (locked_at + 600.seconds), true) - end + let(:bad_password_window) { IdentityConfig.store.max_bad_passwords_window_in_seconds } before do allow(subject).to receive(:session_bad_password_count_max_exceeded?). and_return(true) allow(subject).to receive(:clear_session_bad_password_count_if_window_expired). and_return(nil) - allow(subject).to receive(:locked_out_time_remaining). - and_return(locked_out_time_remaining) end it 'renders an error letting user know they are locked out for a period of time' do session[:max_bad_passwords_at] = locked_at post :create, params: { user: { email: user.email.upcase, password: user.password } } + current_time = Time.zone.now + time_in_hours = distance_of_time_in_words( + current_time, + (locked_at + bad_password_window.seconds), + true, + ) expect(response).to redirect_to root_url expect(flash[:error]).to eq( t( 'errors.sign_in.bad_password_limit', - time_left: locked_out_time_remaining, + time_left: time_in_hours, ), ) end it 'tracks unsuccessful authentication for too many auth failures' do + session[:max_bad_passwords_at] = locked_at allow(subject).to receive(:session_bad_password_count_max_exceeded?).and_return(true) mock_email_parameter = { email: 'bob@example.com' } From b541b1d15da7476df3258b706be86f3ee05d9e3e Mon Sep 17 00:00:00 2001 From: Malick Diarra Date: Tue, 2 Jul 2024 11:01:56 -0400 Subject: [PATCH 4/8] change to_i --- app/controllers/users/sessions_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/users/sessions_controller.rb b/app/controllers/users/sessions_controller.rb index 38cbc311c4c..6acc21ba3ef 100644 --- a/app/controllers/users/sessions_controller.rb +++ b/app/controllers/users/sessions_controller.rb @@ -68,7 +68,7 @@ def session_bad_password_count_max_exceeded? def increment_session_bad_password_count session[:bad_password_count] = session[:bad_password_count].to_i + 1 return unless session_bad_password_count_max_exceeded? - session[:max_bad_passwords_at] ||= Time.zone.now.to_i + session[:max_bad_passwords_at] ||= Time.zone.now end def process_locked_out_session From 622e36e1ec7c889adabbb14c42e6c72c0d6b6ed1 Mon Sep 17 00:00:00 2001 From: Malick Diarra Date: Tue, 2 Jul 2024 12:47:56 -0400 Subject: [PATCH 5/8] fix spec to ensure they work as intended --- app/controllers/users/sessions_controller.rb | 5 +++-- .../users/sessions_controller_spec.rb | 8 ++------ spec/features/visitors/bad_password_spec.rb | 16 +++++++++++----- spec/requests/rack_attack_spec.rb | 3 --- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/app/controllers/users/sessions_controller.rb b/app/controllers/users/sessions_controller.rb index 6acc21ba3ef..db805d4a707 100644 --- a/app/controllers/users/sessions_controller.rb +++ b/app/controllers/users/sessions_controller.rb @@ -68,7 +68,7 @@ def session_bad_password_count_max_exceeded? def increment_session_bad_password_count session[:bad_password_count] = session[:bad_password_count].to_i + 1 return unless session_bad_password_count_max_exceeded? - session[:max_bad_passwords_at] ||= Time.zone.now + session[:max_bad_passwords_at] ||= Time.zone.now.to_i end def process_locked_out_session @@ -85,7 +85,8 @@ def process_locked_out_session def locked_out_time_remaining locked_at = session[:max_bad_passwords_at] window = IdentityConfig.store.max_bad_passwords_window_in_seconds.seconds - distance_of_time_in_words(Time.zone.now, (locked_at + window), true) + new_time = Time.zone.at(locked_at) + window + distance_of_time_in_words(Time.zone.now, new_time, true) end def valid_captcha_result? diff --git a/spec/controllers/users/sessions_controller_spec.rb b/spec/controllers/users/sessions_controller_spec.rb index 85bbf5d66fa..7c48896a3df 100644 --- a/spec/controllers/users/sessions_controller_spec.rb +++ b/spec/controllers/users/sessions_controller_spec.rb @@ -122,14 +122,11 @@ let(:bad_password_window) { IdentityConfig.store.max_bad_passwords_window_in_seconds } before do - allow(subject).to receive(:session_bad_password_count_max_exceeded?). - and_return(true) - allow(subject).to receive(:clear_session_bad_password_count_if_window_expired). - and_return(nil) + session[:bad_password_count] = IdentityConfig.store.max_bad_passwords + 1 + session[:max_bad_passwords_at] = locked_at.to_i end it 'renders an error letting user know they are locked out for a period of time' do - session[:max_bad_passwords_at] = locked_at post :create, params: { user: { email: user.email.upcase, password: user.password } } current_time = Time.zone.now time_in_hours = distance_of_time_in_words( @@ -148,7 +145,6 @@ end it 'tracks unsuccessful authentication for too many auth failures' do - session[:max_bad_passwords_at] = locked_at allow(subject).to receive(:session_bad_password_count_max_exceeded?).and_return(true) mock_email_parameter = { email: 'bob@example.com' } diff --git a/spec/features/visitors/bad_password_spec.rb b/spec/features/visitors/bad_password_spec.rb index 95f6faf5012..1493b96a04c 100644 --- a/spec/features/visitors/bad_password_spec.rb +++ b/spec/features/visitors/bad_password_spec.rb @@ -4,6 +4,7 @@ include ActionView::Helpers::DateHelper let(:user) { create(:user, :fully_registered) } let(:bad_password) { 'badpassword' } + let(:window) { IdentityConfig.store.max_bad_passwords_window_in_seconds.seconds } scenario 'visitor tries too many bad passwords gets locked out then waits window seconds' do visit new_user_session_path @@ -16,25 +17,30 @@ expect(page).to have_content(error_message) expect(page).to have_current_path(new_user_session_path) end - locked_out_time_remaining = distance_of_time_in_words(5.minutes) - allow_any_instance_of(Users::SessionsController).to receive(:locked_out_time_remaining). - and_return(locked_out_time_remaining) + locked_at = Time.zone.at(page.get_rack_session['max_bad_passwords_at']) + # Need to do this because getting rack session changes the url. + visit new_user_session_path 2.times do fill_in_credentials_and_submit(user.email, bad_password) + expect(page).to have_current_path(new_user_session_path) + new_time = Time.zone.at(locked_at) + window + time_left = distance_of_time_in_words(Time.zone.now, new_time, true) expect(page).to have_content( t( 'errors.sign_in.bad_password_limit', - time_left: locked_out_time_remaining, + time_left: time_left, ), ) end fill_in_credentials_and_submit(user.email, user.password) expect(page).to have_current_path(new_user_session_path) + new_time = Time.zone.at(locked_at) + window + time_left = distance_of_time_in_words(Time.zone.now, new_time, true) expect(page).to have_content( t( 'errors.sign_in.bad_password_limit', - time_left: locked_out_time_remaining, + time_left: time_left, ), ) diff --git a/spec/requests/rack_attack_spec.rb b/spec/requests/rack_attack_spec.rb index c4bef6d4697..ff2672c8502 100644 --- a/spec/requests/rack_attack_spec.rb +++ b/spec/requests/rack_attack_spec.rb @@ -250,9 +250,6 @@ it 'throttles with a custom response' do analytics = FakeAnalytics.new # Needed because time logic wont work since we freeze time. - locked_out_time_remaining = 5.minutes - allow_any_instance_of(Users::SessionsController).to receive(:locked_out_time_remaining). - and_return(locked_out_time_remaining) allow(Analytics).to receive(:new).and_return(analytics) allow(analytics).to receive(:track_event) From 3d25ca6c194cba458bc4461c646ec064c57103ee Mon Sep 17 00:00:00 2001 From: Malick Diarra Date: Tue, 2 Jul 2024 12:50:48 -0400 Subject: [PATCH 6/8] change rack spec to what it was originally --- spec/requests/rack_attack_spec.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/spec/requests/rack_attack_spec.rb b/spec/requests/rack_attack_spec.rb index ff2672c8502..491f1c25f89 100644 --- a/spec/requests/rack_attack_spec.rb +++ b/spec/requests/rack_attack_spec.rb @@ -249,7 +249,6 @@ it 'throttles with a custom response' do analytics = FakeAnalytics.new - # Needed because time logic wont work since we freeze time. allow(Analytics).to receive(:new).and_return(analytics) allow(analytics).to receive(:track_event) @@ -316,10 +315,6 @@ context 'when number of logins per email + ip is higher than limit per period' do it 'throttles with a custom response' do analytics = FakeAnalytics.new - # Needed because time logic wont work since we freeze time. - locked_out_time_remaining = 5.minutes - allow_any_instance_of(Users::SessionsController).to receive(:locked_out_time_remaining). - and_return(locked_out_time_remaining) allow(Analytics).to receive(:new).and_return(analytics) allow(analytics).to receive(:track_event) analytics_hash = { type: 'logins/email+ip' } From 0f3768e0a5b280db241090638e0740ffa39d4332 Mon Sep 17 00:00:00 2001 From: Malick Diarra Date: Tue, 2 Jul 2024 12:52:40 -0400 Subject: [PATCH 7/8] remove unused test --- spec/controllers/users/sessions_controller_spec.rb | 7 ------- 1 file changed, 7 deletions(-) diff --git a/spec/controllers/users/sessions_controller_spec.rb b/spec/controllers/users/sessions_controller_spec.rb index 7c48896a3df..2495cf64fcc 100644 --- a/spec/controllers/users/sessions_controller_spec.rb +++ b/spec/controllers/users/sessions_controller_spec.rb @@ -143,13 +143,6 @@ ), ) end - - it 'tracks unsuccessful authentication for too many auth failures' do - allow(subject).to receive(:session_bad_password_count_max_exceeded?).and_return(true) - mock_email_parameter = { email: 'bob@example.com' } - - post :create, params: { user: { **mock_email_parameter, password: 'eatCake!' } } - end end it 'tracks the unsuccessful authentication for existing user' do From 91adeadf45fb14dc0c81e962e9f5a4818cc43781 Mon Sep 17 00:00:00 2001 From: Malick Diarra Date: Tue, 2 Jul 2024 13:28:03 -0400 Subject: [PATCH 8/8] change naming scheme --- app/controllers/users/sessions_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/users/sessions_controller.rb b/app/controllers/users/sessions_controller.rb index db805d4a707..159e784baf2 100644 --- a/app/controllers/users/sessions_controller.rb +++ b/app/controllers/users/sessions_controller.rb @@ -85,8 +85,8 @@ def process_locked_out_session def locked_out_time_remaining locked_at = session[:max_bad_passwords_at] window = IdentityConfig.store.max_bad_passwords_window_in_seconds.seconds - new_time = Time.zone.at(locked_at) + window - distance_of_time_in_words(Time.zone.now, new_time, true) + time_lockout_expires = Time.zone.at(locked_at) + window + distance_of_time_in_words(Time.zone.now, time_lockout_expires, true) end def valid_captcha_result?