diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-02-19 06:07:43 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-02-19 06:07:43 +0300 |
commit | 5e14570e0f814ae20e61fbf4b0dbc32518ecde1d (patch) | |
tree | aa88172df3391acc6a1cefeb75b34f89b07cbebb /spec | |
parent | dc28888b7ae87747d44e179c36ba85968275d75f (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r-- | spec/features/users/login_spec.rb | 187 | ||||
-rw-r--r-- | spec/views/devise/shared/_error_messages.html.haml_spec.rb | 43 |
2 files changed, 145 insertions, 85 deletions
diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb index f8c06a85f71..3da7bd1a780 100644 --- a/spec/features/users/login_spec.rb +++ b/spec/features/users/login_spec.rb @@ -207,8 +207,89 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_ describe 'with two-factor authentication', :js do def enter_code(code) - fill_in 'user_otp_attempt', with: code - click_button 'Verify code' + if page.has_content?("Sign in via 2FA code") + click_on("Sign in via 2FA code") + enter_code(code) + else + fill_in 'user_otp_attempt', with: code + click_button 'Verify code' + end + end + + shared_examples_for 'can login with recovery codes' do + context 'using backup code' do + let(:codes) { user.generate_otp_backup_codes! } + + before do + expect(codes.size).to eq 10 + + # Ensure the generated codes get saved + user.save!(touch: false) + end + + context 'with valid code' do + it 'allows login' do + expect(authentication_metrics) + .to increment(:user_authenticated_counter) + .and increment(:user_two_factor_authenticated_counter) + + enter_code(codes.sample) + + expect(page).to have_current_path root_path, ignore_query: true + end + + it 'invalidates the used code' do + expect(authentication_metrics) + .to increment(:user_authenticated_counter) + .and increment(:user_two_factor_authenticated_counter) + + expect { enter_code(codes.sample) } + .to change { user.reload.otp_backup_codes.size }.by(-1) + end + + it 'invalidates backup codes twice in a row' do + expect(authentication_metrics) + .to increment(:user_authenticated_counter).twice + .and increment(:user_two_factor_authenticated_counter).twice + .and increment(:user_session_destroyed_counter) + + random_code = codes.delete(codes.sample) + expect { enter_code(random_code) } + .to change { user.reload.otp_backup_codes.size }.by(-1) + + gitlab_sign_out + gitlab_sign_in(user) + + expect { enter_code(codes.sample) } + .to change { user.reload.otp_backup_codes.size }.by(-1) + end + + it 'triggers ActiveSession.cleanup for the user' do + expect(authentication_metrics) + .to increment(:user_authenticated_counter) + .and increment(:user_two_factor_authenticated_counter) + expect(ActiveSession).to receive(:cleanup).with(user).once.and_call_original + + enter_code(codes.sample) + end + end + + context 'with invalid code' do + it 'blocks login' do + # TODO, invalid two factor authentication does not increment + # metrics / counters, see gitlab-org/gitlab-ce#49785 + + code = codes.sample + expect(user.invalidate_otp_backup_code!(code)).to eq true + + user.save!(touch: false) + expect(user.reload.otp_backup_codes.size).to eq 9 + + enter_code(code) + expect(page).to have_content('Invalid two-factor code.') + end + end + end end context 'with valid username/password' do @@ -216,8 +297,6 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_ before do gitlab_sign_in(user, remember: true) - - expect(page).to have_content('Enter verification code') end it 'does not show a "You are already signed in." error message' do @@ -290,78 +369,16 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_ end end - context 'using backup code' do - let(:codes) { user.generate_otp_backup_codes! } - - before do - expect(codes.size).to eq 10 - - # Ensure the generated codes get saved - user.save!(touch: false) - end - - context 'with valid code' do - it 'allows login' do - expect(authentication_metrics) - .to increment(:user_authenticated_counter) - .and increment(:user_two_factor_authenticated_counter) - - enter_code(codes.sample) - - expect(page).to have_current_path root_path, ignore_query: true - end - - it 'invalidates the used code' do - expect(authentication_metrics) - .to increment(:user_authenticated_counter) - .and increment(:user_two_factor_authenticated_counter) - - expect { enter_code(codes.sample) } - .to change { user.reload.otp_backup_codes.size }.by(-1) - end - - it 'invalidates backup codes twice in a row' do - expect(authentication_metrics) - .to increment(:user_authenticated_counter).twice - .and increment(:user_two_factor_authenticated_counter).twice - .and increment(:user_session_destroyed_counter) - - random_code = codes.delete(codes.sample) - expect { enter_code(random_code) } - .to change { user.reload.otp_backup_codes.size }.by(-1) - - gitlab_sign_out - gitlab_sign_in(user) - - expect { enter_code(codes.sample) } - .to change { user.reload.otp_backup_codes.size }.by(-1) - end - - it 'triggers ActiveSession.cleanup for the user' do - expect(authentication_metrics) - .to increment(:user_authenticated_counter) - .and increment(:user_two_factor_authenticated_counter) - expect(ActiveSession).to receive(:cleanup).with(user).once.and_call_original - - enter_code(codes.sample) - end - end - - context 'with invalid code' do - it 'blocks login' do - # TODO, invalid two factor authentication does not increment - # metrics / counters, see gitlab-org/gitlab-ce#49785 + context 'when user with TOTP enabled' do + let(:user) { create(:user, :two_factor) } - code = codes.sample - expect(user.invalidate_otp_backup_code!(code)).to eq true + include_examples 'can login with recovery codes' + end - user.save!(touch: false) - expect(user.reload.otp_backup_codes.size).to eq 9 + context 'when user with only Webauthn enabled' do + let(:user) { create(:user, :two_factor_via_webauthn, registrations_count: 1) } - enter_code(code) - expect(page).to have_content('Invalid two-factor code.') - end - end + include_examples 'can login with recovery codes' end end @@ -379,8 +396,8 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_ context 'when authn_context is worth two factors' do let(:mock_saml_response) do File.read('spec/fixtures/authentication/saml_response.xml') - .gsub('urn:oasis:names:tc:SAML:2.0:ac:classes:Password', - 'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorOTPSMS') + .gsub('urn:oasis:names:tc:SAML:2.0:ac:classes:Password', + 'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorOTPSMS') end it 'signs user in without prompting for second factor' do @@ -928,22 +945,22 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_ it 'asks the user to accept the terms before setting an email', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/388049', type: :flaky } do - expect(authentication_metrics) - .to increment(:user_authenticated_counter) + expect(authentication_metrics) + .to increment(:user_authenticated_counter) - gitlab_sign_in_via('saml', user, 'my-uid') + gitlab_sign_in_via('saml', user, 'my-uid') - expect_to_be_on_terms_page - click_button 'Accept terms' + expect_to_be_on_terms_page + click_button 'Accept terms' - expect(page).to have_current_path(profile_path, ignore_query: true) + expect(page).to have_current_path(profile_path, ignore_query: true) - fill_in 'Email', with: 'hello@world.com' + fill_in 'Email', with: 'hello@world.com' - click_button 'Update profile settings' + click_button 'Update profile settings' - expect(page).to have_content('Profile was successfully updated') - end + expect(page).to have_content('Profile was successfully updated') + end end end diff --git a/spec/views/devise/shared/_error_messages.html.haml_spec.rb b/spec/views/devise/shared/_error_messages.html.haml_spec.rb new file mode 100644 index 00000000000..afd3141f2c7 --- /dev/null +++ b/spec/views/devise/shared/_error_messages.html.haml_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'devise/shared/_error_messages', feature_category: :authentication_and_authorization do + describe 'Error messages' do + let(:resource) do + instance_spy(User, errors: errors, class: User) + end + + before do + allow(view).to receive(:resource).and_return(resource) + end + + context 'with errors', :aggregate_failures do + let(:errors) { errors_stub(['Invalid name', 'Invalid password']) } + + it 'shows errors' do + render + + expect(rendered).to have_selector('#error_explanation') + expect(rendered).to have_content('Invalid name') + expect(rendered).to have_content('Invalid password') + end + end + + context 'without errors' do + let(:errors) { [] } + + it 'does not show errors' do + render + + expect(rendered).not_to have_selector('#error_explanation') + end + end + end + + def errors_stub(*messages) + ActiveModel::Errors.new(double).tap do |errors| + messages.each { |msg| errors.add(:base, msg) } + end + end +end |