From 585c4955686339193f9baf37c4f0b00cccaee2a2 Mon Sep 17 00:00:00 2001 From: Desiree Chevalier Date: Tue, 17 Nov 2020 14:34:01 -0500 Subject: [PATCH 1/2] Add formless login for e2e tests Add ability to login without UI for e2e specs --- app/controllers/qa_sessions_controller.rb | 23 ++++++++++++++++ config/routes/user.rb | 4 +++ qa/qa.rb | 1 + qa/qa/flow/login.rb | 14 +++++++++- qa/qa/page/main/formless_login.rb | 26 +++++++++++++++++++ qa/qa/runtime/browser.rb | 2 +- qa/qa/runtime/env.rb | 4 +++ .../1_manage/login/2fa_recovery_spec.rb | 4 +-- .../1_manage/login/2fa_ssh_recovery_spec.rb | 4 +-- .../browser_ui/1_manage/login/log_in_spec.rb | 2 +- .../1_manage/login/log_in_with_2fa_spec.rb | 2 +- .../login/log_into_gitlab_via_ldap_spec.rb | 2 +- .../log_into_mattermost_via_gitlab_spec.rb | 2 +- .../1_manage/login/register_spec.rb | 4 +-- 14 files changed, 82 insertions(+), 12 deletions(-) create mode 100644 app/controllers/qa_sessions_controller.rb create mode 100644 qa/qa/page/main/formless_login.rb diff --git a/app/controllers/qa_sessions_controller.rb b/app/controllers/qa_sessions_controller.rb new file mode 100644 index 00000000000000..c2b2db1061a1f1 --- /dev/null +++ b/app/controllers/qa_sessions_controller.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +class QaSessionsController < Devise::SessionsController + prepend_before_action :ensure_qa_running! + # prepend_ is important, normal before_action would mean that + # the user is authenticated right away if the username/password params + # are correct and it runs this filter only after a session is created. + + feature_category :authentication_and_authorization + + def create + if current_user + redirect_to after_sign_in_path_for(current_user) + else + head :unauthorized # when the username/password is invalid and login fails + end + end + + def ensure_qa_running! + return head :forbidden unless ENV['GITLAB_QA_FORMLESS_LOGIN_TOKEN'].present? + return head :forbidden unless params[:gitlab_qa_formless_login_token] == ENV['GITLAB_QA_FORMLESS_LOGIN_TOKEN'] + end +end diff --git a/config/routes/user.rb b/config/routes/user.rb index 7af4bf2ac2a28d..d34536c244c4fe 100644 --- a/config/routes/user.rb +++ b/config/routes/user.rb @@ -26,6 +26,10 @@ def override_omniauth(provider, controller, path_prefix = '/users/auth') devise_scope :user do get '/users/almost_there' => 'confirmations#almost_there' + + if ENV['GITLAB_QA_FORMLESS_LOGIN_TOKEN'].present? || Rails.env.test? + get '/users/qa_sign_in' => 'qa_sessions#create' + end end scope '-/users', module: :users do diff --git a/qa/qa.rb b/qa/qa.rb index b30497d88e1064..653cb3b9c8ad51 100644 --- a/qa/qa.rb +++ b/qa/qa.rb @@ -178,6 +178,7 @@ module SubMenus end module Main + autoload :FormlessLogin, 'qa/page/main/formless_login' autoload :Login, 'qa/page/main/login' autoload :Menu, 'qa/page/main/menu' autoload :OAuth, 'qa/page/main/oauth' diff --git a/qa/qa/flow/login.rb b/qa/qa/flow/login.rb index d23d8eaf097b6c..5681bc4f0f89d6 100644 --- a/qa/qa/flow/login.rb +++ b/qa/qa/flow/login.rb @@ -22,8 +22,20 @@ def while_signed_in_as_admin(address: :gitlab) end end - def sign_in(as: nil, address: :gitlab, skip_page_validation: false) + def sign_in(as: nil, address: :gitlab, skip_page_validation: false, formless: true) Page::Main::Menu.perform(&:sign_out) if Page::Main::Menu.perform(&:signed_in?) + + if formless && Runtime::Env.gitlab_qa_formless_login_token + Page::Main::FormlessLogin.new(as, address) + + if Page::Main::Menu.perform(&:signed_in?) + Runtime::Logger.debug("Formless login successful") + return + else + Runtime::Logger.warn("Formless login failed...Falling back to UI login") + end + end + Runtime::Browser.visit(address, Page::Main::Login) Page::Main::Login.perform { |login| login.sign_in_using_credentials(user: as, skip_page_validation: skip_page_validation) } end diff --git a/qa/qa/page/main/formless_login.rb b/qa/qa/page/main/formless_login.rb new file mode 100644 index 00000000000000..1a076a1e0f51b3 --- /dev/null +++ b/qa/qa/page/main/formless_login.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module QA + module Page + module Main + class FormlessLogin < Page::Base + # This workaround avoids failure in Test::Sanity::Selectors + # as it requires a Page class to have views / elements defined. + view 'app/views/layouts/devise.html.haml' + + attr_accessor :path + + def initialize(as, address) + user = as || Runtime::User + self.path = "/users/qa_sign_in?user[login]=#{user.username}&user[password]=#{user.password}&gitlab_qa_formless_login_token=#{Runtime::Env.gitlab_qa_formless_login_token}" + + formless_login(address) + end + + def formless_login(address) + Runtime::Browser.visit(address, path) + end + end + end + end +end diff --git a/qa/qa/runtime/browser.rb b/qa/qa/runtime/browser.rb index a3fce8bff888ef..707932694b5c72 100644 --- a/qa/qa/runtime/browser.rb +++ b/qa/qa/runtime/browser.rb @@ -173,7 +173,7 @@ def perform(&block) simulate_slow_connection if Runtime::Env.simulate_slow_connection? - page_class.validate_elements_present! + page_class.validate_elements_present! unless page_class.is_a?(String) if QA::Runtime::Env.qa_cookies browser = Capybara.current_session.driver.browser diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb index 54b670485eb7db..69b4eda2e1b8e7 100644 --- a/qa/qa/runtime/env.rb +++ b/qa/qa/runtime/env.rb @@ -399,6 +399,10 @@ def user_agent ENV['GITLAB_QA_USER_AGENT'] end + def gitlab_qa_formless_login_token + ENV['GITLAB_QA_FORMLESS_LOGIN_TOKEN'] + end + private def remote_grid_credentials diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/2fa_recovery_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/2fa_recovery_spec.rb index a6b4a8108a3f9a..1fae1b28bf7848 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/2fa_recovery_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/2fa_recovery_spec.rb @@ -36,7 +36,7 @@ module QA it 'allows using 2FA recovery code once only', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/972' do recovery_code = enable_2fa_for_user_and_fetch_recovery_code(developer_user) - Flow::Login.sign_in(as: developer_user, skip_page_validation: true) + Flow::Login.sign_in(as: developer_user, skip_page_validation: true, formless: false) Page::Main::TwoFactorAuth.perform do |two_fa_auth| two_fa_auth.set_2fa_code(recovery_code) @@ -47,7 +47,7 @@ module QA Page::Main::Menu.perform(&:sign_out) - Flow::Login.sign_in(as: developer_user, skip_page_validation: true) + Flow::Login.sign_in(as: developer_user, skip_page_validation: true, formless: false) Page::Main::TwoFactorAuth.perform do |two_fa_auth| two_fa_auth.set_2fa_code(recovery_code) diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb index 7ebbe7887b9fde..f22a93974ec6bf 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb @@ -29,7 +29,7 @@ module QA output.scan(/([A-Za-z0-9]{16})\n/).flatten.first end - Flow::Login.sign_in(as: user, skip_page_validation: true) + Flow::Login.sign_in(as: user, skip_page_validation: true, formless: false) Page::Main::TwoFactorAuth.perform do |two_fa_auth| two_fa_auth.set_2fa_code(recovery_code) two_fa_auth.click_verify_code_button @@ -38,7 +38,7 @@ module QA expect(Page::Main::Menu.perform(&:signed_in?)).to be_truthy Page::Main::Menu.perform(&:sign_out) - Flow::Login.sign_in(as: user, skip_page_validation: true) + Flow::Login.sign_in(as: user, skip_page_validation: true, formless: false) Page::Main::TwoFactorAuth.perform do |two_fa_auth| two_fa_auth.set_2fa_code(recovery_code) two_fa_auth.click_verify_code_button diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb index 624f8d20b62d85..7f8f6ca561e7fc 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb @@ -4,7 +4,7 @@ module QA RSpec.describe 'Manage', :smoke do describe 'basic user login' do it 'user logs in using basic credentials and logs out', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/424' do - Flow::Login.sign_in + Flow::Login.sign_in(formless: false) Page::Main::Menu.perform do |menu| expect(menu).to have_personal_area diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb index 1f0215cd92950e..5a14e74b871476 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb @@ -40,7 +40,7 @@ module QA enable_two_factor_authentication_for_user(developer_user) - Flow::Login.sign_in(as: developer_user, skip_page_validation: true) + Flow::Login.sign_in(as: developer_user, skip_page_validation: true, formless: false) Page::Main::TwoFactorAuth.perform do |two_fa_auth| two_fa_auth.set_2fa_code('000000') diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb index cc12dd4e3155fa..a3317331f22448 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb @@ -4,7 +4,7 @@ module QA RSpec.describe 'Manage', :orchestrated, :ldap_no_tls, :ldap_tls do describe 'LDAP login' do it 'user logs into GitLab using LDAP credentials', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/668' do - Flow::Login.sign_in + Flow::Login.sign_in(formless: false) Page::Main::Menu.perform do |menu| expect(menu).to have_personal_area diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb index 366f150bcd1500..c944bdab7d45e1 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb @@ -4,7 +4,7 @@ module QA RSpec.describe 'Manage', :orchestrated, :mattermost do describe 'Mattermost login' do it 'user logs into Mattermost using GitLab OAuth', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/666' do - Flow::Login.sign_in + Flow::Login.sign_in(formless: false) Support::Retrier.retry_on_exception do Runtime::Browser.visit(:mattermost, Page::Mattermost::Login) diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb index d58857f6da277f..1c92d38a143881 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb @@ -106,7 +106,7 @@ def admin_api_client it 'allows user login after approval', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1076' do expect(page).to have_text(signed_up_waiting_approval_text) - Flow::Login.sign_in(as: @user, skip_page_validation: true) + Flow::Login.sign_in(as: @user, skip_page_validation: true, formless: false) expect(page).to have_text(pending_approval_blocked_text) @@ -157,7 +157,7 @@ def set_require_admin_approval_after_user_signup_via_api(enable_or_disable) def enable_require_admin_approval_after_user_signup_via_ui unless Runtime::ApplicationSettings.get_application_settings[:require_admin_approval_after_user_signup] - Flow::Login.while_signed_in_as_admin do + Flow::Login.while_signed_in_as_admin(formless: false) do Page::Main::Menu.perform(&:go_to_admin_area) QA::Page::Admin::Menu.perform(&:go_to_general_settings) Page::Admin::Settings::General.perform do |setting| -- GitLab From b25bc758ba87e07da2dae18cdbed1eab5833cc16 Mon Sep 17 00:00:00 2001 From: Desiree Chevalier Date: Wed, 18 Nov 2020 21:28:22 -0500 Subject: [PATCH 2/2] Do not use url --- qa/qa/flow/login.rb | 23 ++++++++++++--------- qa/qa/page/main/formless_login.rb | 34 +++++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/qa/qa/flow/login.rb b/qa/qa/flow/login.rb index 5681bc4f0f89d6..a968ffb3ca9381 100644 --- a/qa/qa/flow/login.rb +++ b/qa/qa/flow/login.rb @@ -5,10 +5,10 @@ module Flow module Login module_function - def while_signed_in(as: nil, address: :gitlab) + def while_signed_in(as: nil, address: :gitlab, formless: true) Page::Main::Menu.perform(&:sign_out_if_signed_in) - sign_in(as: as, address: address) + sign_in(as: as, address: address, formless: formless) result = yield @@ -16,8 +16,8 @@ def while_signed_in(as: nil, address: :gitlab) result end - def while_signed_in_as_admin(address: :gitlab) - while_signed_in(as: Runtime::User.admin, address: address) do + def while_signed_in_as_admin(address: :gitlab, formless: true) + while_signed_in(as: Runtime::User.admin, address: address, formless: formless) do yield end end @@ -26,10 +26,13 @@ def sign_in(as: nil, address: :gitlab, skip_page_validation: false, formless: tr Page::Main::Menu.perform(&:sign_out) if Page::Main::Menu.perform(&:signed_in?) if formless && Runtime::Env.gitlab_qa_formless_login_token - Page::Main::FormlessLogin.new(as, address) + user = as || Runtime::User + Page::Main::FormlessLogin.perform do |login| + login.formless_login(user) + end if Page::Main::Menu.perform(&:signed_in?) - Runtime::Logger.debug("Formless login successful") + Runtime::Logger.debug("Formless login as #{user.username} successful") return else Runtime::Logger.warn("Formless login failed...Falling back to UI login") @@ -40,12 +43,12 @@ def sign_in(as: nil, address: :gitlab, skip_page_validation: false, formless: tr Page::Main::Login.perform { |login| login.sign_in_using_credentials(user: as, skip_page_validation: skip_page_validation) } end - def sign_in_as_admin(address: :gitlab) - sign_in(as: Runtime::User.admin, address: address) + def sign_in_as_admin(address: :gitlab, formless: true) + sign_in(as: Runtime::User.admin, address: address, formless: formless) end - def sign_in_unless_signed_in(as: nil, address: :gitlab) - sign_in(as: as, address: address) unless Page::Main::Menu.perform(&:signed_in?) + def sign_in_unless_signed_in(as: nil, address: :gitlab, formless: true) + sign_in(as: as, address: address, formless: formless) unless Page::Main::Menu.perform(&:signed_in?) end end end diff --git a/qa/qa/page/main/formless_login.rb b/qa/qa/page/main/formless_login.rb index 1a076a1e0f51b3..a2260c3539d25b 100644 --- a/qa/qa/page/main/formless_login.rb +++ b/qa/qa/page/main/formless_login.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'rest-client' + module QA module Page module Main @@ -8,17 +10,33 @@ class FormlessLogin < Page::Base # as it requires a Page class to have views / elements defined. view 'app/views/layouts/devise.html.haml' - attr_accessor :path + def formless_login(user) + url = "#{Runtime::Scenario.gitlab_address}/users/qa_sign_in" + get_params = { + user: { + login: user.username, + password: user.password + }, + gitlab_qa_formless_login_token: Runtime::Env.gitlab_qa_formless_login_token + } - def initialize(as, address) - user = as || Runtime::User - self.path = "/users/qa_sign_in?user[login]=#{user.username}&user[password]=#{user.password}&gitlab_qa_formless_login_token=#{Runtime::Env.gitlab_qa_formless_login_token}" + response = RestClient::Request.execute( + method: :get, + url: url, + headers: { params: get_params } + ) do |response, request, result| + @redirect = response.headers[:location] + response.return! + end - formless_login(address) - end + # Add the 3 cookies from the response: _gitlab_session_<#> + # experimentation_subject_id, and perf_bar_enabled + response.cookies.each { |key, value| Capybara.current_session.driver.browser.manage.add_cookie(name: key, value: value) } + + visit(@redirect) - def formless_login(address) - Runtime::Browser.visit(address, path) + rescue RestClient::ExceptionWithResponse => e + return_response_or_raise(e) end end end -- GitLab