diff --git a/app/controllers/concerns/two_factor_authenticatable.rb b/app/controllers/concerns/two_factor_authenticatable.rb index 1fa1b566c70..5da4baa18f5 100644 --- a/app/controllers/concerns/two_factor_authenticatable.rb +++ b/app/controllers/concerns/two_factor_authenticatable.rb @@ -88,7 +88,7 @@ def two_factor_authentication_method # You can pass in any "type" with a corresponding I18n key in # devise.two_factor_authentication.invalid_#{type} def handle_invalid_otp(type: 'otp') - update_invalid_user if current_user.two_factor_enabled? && authentication_context? + update_invalid_user flash.now[:error] = t("devise.two_factor_authentication.invalid_#{type}") diff --git a/spec/controllers/two_factor_authentication/otp_verification_controller_spec.rb b/spec/controllers/two_factor_authentication/otp_verification_controller_spec.rb index 15f31702b38..c97c4f4b6b6 100644 --- a/spec/controllers/two_factor_authentication/otp_verification_controller_spec.rb +++ b/spec/controllers/two_factor_authentication/otp_verification_controller_spec.rb @@ -61,7 +61,7 @@ end describe '#create' do - context 'when the user enters an invalid OTP' do + context 'when the user enters an invalid OTP during authentication context' do before do sign_in_before_2fa @@ -95,6 +95,17 @@ end end + context 'when the user enters an invalid OTP during reauthentication context' do + it 'increments second_factor_attempts_count' do + sign_in_before_2fa + controller.user_session[:context] = 'reauthentication' + + post :create, params: { code: '12345', otp_delivery_preference: 'sms' } + + expect(subject.current_user.reload.second_factor_attempts_count).to eq 1 + end + end + context 'when the user has reached the max number of OTP attempts' do it 'tracks the event' do allow_any_instance_of(User).to receive(:max_login_attempts?).and_return(true) @@ -260,8 +271,8 @@ context 'user enters an invalid code' do before { post :create, params: { code: '999', otp_delivery_preference: 'sms' } } - it 'does not increment second_factor_attempts_count' do - expect(subject.current_user.reload.second_factor_attempts_count).to eq 0 + it 'increments second_factor_attempts_count' do + expect(subject.current_user.reload.second_factor_attempts_count).to eq 1 end it 'does not clear session data' do @@ -419,8 +430,8 @@ context 'user enters an invalid code' do before { post :create, params: { code: '999', otp_delivery_preference: 'sms' } } - it 'does not increment second_factor_attempts_count' do - expect(subject.current_user.reload.second_factor_attempts_count).to eq 0 + it 'increments second_factor_attempts_count' do + expect(subject.current_user.reload.second_factor_attempts_count).to eq 1 end it 'does not clear session data' do diff --git a/spec/features/two_factor_authentication/sign_in_spec.rb b/spec/features/two_factor_authentication/sign_in_spec.rb index 5a84a580bdd..bd6a33c2dfe 100644 --- a/spec/features/two_factor_authentication/sign_in_spec.rb +++ b/spec/features/two_factor_authentication/sign_in_spec.rb @@ -33,6 +33,20 @@ expect(user.voice?).to eq true end + context 'user enters OTP incorrectly 3 times' do + it 'locks the user out' do + sign_in_before_2fa + + submit_2fa_setup_form_with_valid_phone_and_choose_phone_call_delivery + 3.times do + fill_in('code', with: 'bad-code') + click_button t('forms.buttons.submit.default') + end + + expect(page).to have_content t('titles.account_locked') + end + end + context 'with U.S. phone that does not support phone delivery method' do let(:guam_phone) { '671-555-5555' }