diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-13 12:09:22 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-13 12:09:22 +0000 |
commit | 286fe61013674fe2d245ffc8d2233baf09923e70 (patch) | |
tree | 2037291f5863105e54e75be056b49f7d62007cae /spec/features | |
parent | 4cb5e5011abfe8d50ac3a7ebd0018c563c6d7af4 (diff) | |
download | gitlab-ce-286fe61013674fe2d245ffc8d2233baf09923e70.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/features')
-rw-r--r-- | spec/features/admin/admin_mode/login_spec.rb | 184 | ||||
-rw-r--r-- | spec/features/admin/admin_mode/logout_spec.rb | 42 | ||||
-rw-r--r-- | spec/features/admin/admin_mode_spec.rb | 4 |
3 files changed, 228 insertions, 2 deletions
diff --git a/spec/features/admin/admin_mode/login_spec.rb b/spec/features/admin/admin_mode/login_spec.rb new file mode 100644 index 00000000000..b8a910d3a40 --- /dev/null +++ b/spec/features/admin/admin_mode/login_spec.rb @@ -0,0 +1,184 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Admin Mode Login', :clean_gitlab_redis_shared_state, :do_not_mock_admin_mode do + include TermsHelper + include UserLoginHelper + + describe 'with two-factor authentication', :js do + def enter_code(code) + fill_in 'user_otp_attempt', with: code + click_button 'Verify code' + end + + context 'with valid username/password' do + let(:user) { create(:admin, :two_factor) } + + context 'using one-time code' do + it 'blocks login if we reuse the same code immediately' do + gitlab_sign_in(user, remember: true) + + expect(page).to have_content('Two-Factor Authentication') + + repeated_otp = user.current_otp + enter_code(repeated_otp) + gitlab_enable_admin_mode_sign_in(user) + + expect(page).to have_content('Two-Factor Authentication') + + enter_code(repeated_otp) + + expect(current_path).to eq admin_session_path + expect(page).to have_content('Invalid two-factor code') + end + + context 'not re-using codes' do + before do + gitlab_sign_in(user, remember: true) + + expect(page).to have_content('Two-Factor Authentication') + + enter_code(user.current_otp) + gitlab_enable_admin_mode_sign_in(user) + + expect(page).to have_content('Two-Factor Authentication') + end + + it 'allows login with valid code' do + # Cannot reuse the TOTP + Timecop.travel(30.seconds.from_now) do + enter_code(user.current_otp) + + expect(current_path).to eq admin_root_path + expect(page).to have_content('Admin mode enabled') + end + end + + it 'blocks login with invalid code' do + # Cannot reuse the TOTP + Timecop.travel(30.seconds.from_now) do + enter_code('foo') + + expect(page).to have_content('Invalid two-factor code') + end + end + + it 'allows login with invalid code, then valid code' do + # Cannot reuse the TOTP + Timecop.travel(30.seconds.from_now) do + enter_code('foo') + + expect(page).to have_content('Invalid two-factor code') + + enter_code(user.current_otp) + + expect(current_path).to eq admin_root_path + expect(page).to have_content('Admin mode enabled') + 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 + end + + context 'with valid code' do + it 'allows login' do + enter_code(codes.sample) + + expect(current_path).to eq admin_root_path + expect(page).to have_content('Admin mode enabled') + end + + it 'invalidates the used code' do + expect { enter_code(codes.sample) } + .to change { user.reload.otp_backup_codes.size }.by(-1) + end + end + + context 'with invalid code' do + it 'blocks login' do + code = codes.sample + expect(user.invalidate_otp_backup_code!(code)).to eq true + + user.save! + 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 + end + + context 'when logging in via omniauth' do + let(:user) { create(:omniauth_user, :admin, :two_factor, extern_uid: 'my-uid', provider: 'saml')} + let(:mock_saml_response) do + File.read('spec/fixtures/authentication/saml_response.xml') + end + + before do + stub_omniauth_saml_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'], + providers: [mock_saml_config_with_upstream_two_factor_authn_contexts]) + end + + 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') + end + + it 'signs user in without prompting for second factor' do + sign_in_using_saml! + + expect(page).not_to have_content('Two-Factor Authentication') + + enable_admin_mode_using_saml! + + expect(page).not_to have_content('Two-Factor Authentication') + expect(current_path).to eq admin_root_path + expect(page).to have_content('Admin mode enabled') + end + end + + context 'when two factor authentication is required' do + it 'shows 2FA prompt after omniauth login' do + sign_in_using_saml! + + expect(page).to have_content('Two-Factor Authentication') + enter_code(user.current_otp) + + enable_admin_mode_using_saml! + + expect(page).to have_content('Two-Factor Authentication') + + # Cannot reuse the TOTP + Timecop.travel(30.seconds.from_now) do + enter_code(user.current_otp) + + expect(current_path).to eq admin_root_path + expect(page).to have_content('Admin mode enabled') + end + end + end + + def sign_in_using_saml! + gitlab_sign_in_via('saml', user, 'my-uid', mock_saml_response) + end + + def enable_admin_mode_using_saml! + gitlab_enable_admin_mode_sign_in_via('saml', user, 'my-uid', mock_saml_response) + end + end + end + end +end diff --git a/spec/features/admin/admin_mode/logout_spec.rb b/spec/features/admin/admin_mode/logout_spec.rb new file mode 100644 index 00000000000..e1b4aba5724 --- /dev/null +++ b/spec/features/admin/admin_mode/logout_spec.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Admin Mode Logout', :js, :clean_gitlab_redis_shared_state, :do_not_mock_admin_mode do + include TermsHelper + include UserLoginHelper + + let(:user) { create(:admin) } + + before do + gitlab_sign_in(user) + gitlab_enable_admin_mode_sign_in(user) + visit admin_root_path + end + + it 'disable removes admin mode and redirects to root page' do + gitlab_disable_admin_mode + + expect(current_path).to eq root_path + expect(page).to have_link(href: new_admin_session_path) + end + + it 'disable shows flash notice' do + gitlab_disable_admin_mode + + expect(page).to have_selector('.flash-notice') + end + + context 'on a read-only instance' do + before do + allow(Gitlab::Database).to receive(:read_only?).and_return(true) + end + + it 'disable removes admin mode and redirects to root page' do + gitlab_disable_admin_mode + + expect(current_path).to eq root_path + expect(page).to have_link(href: new_admin_session_path) + end + end +end diff --git a/spec/features/admin/admin_mode_spec.rb b/spec/features/admin/admin_mode_spec.rb index 7b8990aceef..f642d614a5d 100644 --- a/spec/features/admin/admin_mode_spec.rb +++ b/spec/features/admin/admin_mode_spec.rb @@ -45,7 +45,7 @@ describe 'Admin mode', :clean_gitlab_redis_shared_state, :do_not_mock_admin_mode it 'can enter admin mode' do visit new_admin_session_path - fill_in 'password', with: admin.password + fill_in 'user_password', with: admin.password click_button 'Enter Admin Mode' @@ -60,7 +60,7 @@ describe 'Admin mode', :clean_gitlab_redis_shared_state, :do_not_mock_admin_mode it 'can enter admin mode' do visit new_admin_session_path - fill_in 'password', with: admin.password + fill_in 'user_password', with: admin.password click_button 'Enter Admin Mode' |