Commit a1fddbb7 authored by Diego Louzán's avatar Diego Louzán Committed by James Lopez

feat: user mode in session for admins

Require admins to enter admin-mode by re-authenticating before performing
administrative operations
parent 38931822
# frozen_string_literal: true
class Admin::SessionsController < ApplicationController
include InternalRedirect
before_action :user_is_admin!
def new
# Renders a form in which the admin can enter their password
end
def create
if current_user_mode.enable_admin_mode!(password: params[:password])
redirect_location = stored_location_for(:redirect) || admin_root_path
redirect_to safe_redirect_path(redirect_location)
else
flash.now[:alert] = _('Invalid Login or password')
render :new
end
end
def destroy
current_user_mode.disable_admin_mode!
redirect_to root_path, status: :found, notice: _('Admin mode disabled')
end
private
def user_is_admin!
render_404 unless current_user&.admin?
end
end
......@@ -36,6 +36,7 @@ class ApplicationController < ActionController::Base
protect_from_forgery with: :exception, prepend: true
helper_method :can?
helper_method :current_user_mode
helper_method :import_sources_enabled?, :github_import_enabled?,
:gitea_import_enabled?, :github_import_configured?,
:gitlab_import_enabled?, :gitlab_import_configured?,
......@@ -533,6 +534,10 @@ class ApplicationController < ActionController::Base
yield
end
end
def current_user_mode
@current_user_mode ||= Gitlab::Auth::CurrentUserMode.new(current_user)
end
end
ApplicationController.prepend_if_ee('EE::ApplicationController')
......@@ -14,6 +14,16 @@ module EnforcesAdminAuthentication
end
def authenticate_admin!
render_404 unless current_user.admin?
return render_404 unless current_user.admin?
return unless Feature.enabled?(:user_mode_in_session)
unless current_user_mode.admin_mode?
store_location_for(:redirect, request.fullpath) if storable_location?
redirect_to(new_admin_session_path, notice: _('Re-authentication required'))
end
end
def storable_location?
request.path != new_admin_session_path
end
end
......@@ -5,6 +5,12 @@
# Controller concern to handle PAT, RSS, and static objects token authentication methods
#
module SessionlessAuthentication
extend ActiveSupport::Concern
included do
before_action :enable_admin_mode!, if: :sessionless_user?
end
# This filter handles personal access tokens, atom requests with rss tokens, and static object tokens
def authenticate_sessionless_user!(request_format)
user = Gitlab::Auth::RequestAuthenticator.new(request).find_sessionless_user(request_format)
......@@ -25,4 +31,8 @@ module SessionlessAuthentication
sign_in(user, store: false, message: :sessionless_sign_in)
end
end
def enable_admin_mode!
current_user_mode.enable_admin_mode!(skip_password_validation: true) if Feature.enabled?(:user_mode_in_session)
end
end
......@@ -86,6 +86,12 @@ module NavHelper
links << :admin_impersonation
end
if Feature.enabled?(:user_mode_in_session)
if current_user&.admin? && current_user_mode&.admin_mode?
links << :admin_mode
end
end
links
end
end
......
......@@ -5,7 +5,13 @@ require_dependency 'declarative_policy'
class BasePolicy < DeclarativePolicy::Base
desc "User is an instance admin"
with_options scope: :user, score: 0
condition(:admin) { @user&.admin? }
condition(:admin) do
if Feature.enabled?(:user_mode_in_session)
Gitlab::Auth::CurrentUserMode.new(@user).admin_mode?
else
@user&.admin?
end
end
desc "User is blocked"
with_options scope: :user, score: 0
......
= form_tag(admin_session_path, method: :post, html: { class: 'new_user gl-show-field-errors', 'aria-live': 'assertive'}) do
.form-group
= label_tag :password, _('Password'), class: 'label-bold'
= password_field_tag :password, nil, class: 'form-control', required: true, title: _('This field is required.'), data: { qa_selector: 'password_field' }
.submit-container.move-submit-down
= submit_tag _('Enter admin mode'), class: 'btn btn-success', data: { qa_selector: 'sign_in_button' }
- if form_based_providers.any?
- if password_authentication_enabled_for_web?
.login-box.tab-pane{ id: 'login-pane', role: 'tabpanel' }
.login-body
= render 'admin/sessions/new_base'
- elsif password_authentication_enabled_for_web?
.login-box.tab-pane.active{ id: 'login-pane', role: 'tabpanel' }
.login-body
= render 'admin/sessions/new_base'
%ul.nav-links.new-session-tabs.nav-tabs.nav{ role: 'tablist' }
%li.nav-item{ role: 'presentation' }
%a.nav-link.active{ href: '#login-pane', data: { toggle: 'tab', qa_selector: 'sign_in_tab' }, role: 'tab' }= _('Enter admin mode')
- @hide_breadcrumbs = true
- page_title _('Enter admin mode')
.row.justify-content-center
.col-6.new-session-forms-container
.login-page
#signin-container
= render 'admin/sessions/tabs_normal'
.tab-content
- if password_authentication_enabled_for_web?
= render 'admin/sessions/signin_box'
- else
-# Show a message if none of the mechanisms above are enabled
.prepend-top-default.center
= _('No authentication methods configured.')
......@@ -68,6 +68,15 @@
= nav_link(controller: 'admin/dashboard') do
= link_to admin_root_path, class: 'd-lg-none admin-icon qa-admin-area-link' do
= _('Admin Area')
- if Feature.enabled?(:user_mode_in_session)
- if header_link?(:admin_mode)
= nav_link(controller: 'admin/sessions') do
= link_to destroy_admin_session_path, class: 'd-lg-none lock-open-icon' do
= _('Leave admin mode')
- elsif current_user.admin?
= nav_link(controller: 'admin/sessions') do
= link_to new_admin_session_path, class: 'd-lg-none lock-icon' do
= _('Enter admin mode')
- if Gitlab::Sherlock.enabled?
%li
= link_to sherlock_transactions_path, class: 'd-lg-none admin-icon' do
......@@ -95,6 +104,17 @@
= nav_link(controller: 'admin/dashboard', html_options: { class: "d-none d-lg-block d-xl-block"}) do
= link_to admin_root_path, class: 'admin-icon qa-admin-area-link', title: _('Admin Area'), aria: { label: _('Admin Area') }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= sprite_icon('admin', size: 18)
- if Feature.enabled?(:user_mode_in_session)
- if header_link?(:admin_mode)
= nav_link(controller: 'admin/sessions', html_options: { class: "d-none d-lg-block d-xl-block"}) do
= link_to destroy_admin_session_path, title: _('Leave admin mode'), aria: { label: _('Leave admin mode') }, data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
= sprite_icon('lock-open', size: 18)
- elsif current_user.admin?
= nav_link(controller: 'admin/sessions', html_options: { class: "d-none d-lg-block d-xl-block"}) do
= link_to new_admin_session_path, title: _('Enter admin mode'), aria: { label: _('Enter admin mode') }, data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
= sprite_icon('lock', size: 18)
- if Gitlab::Sherlock.enabled?
%li
= link_to sherlock_transactions_path, class: 'admin-icon d-none d-lg-block d-xl-block', title: _('Sherlock Transactions'),
......
---
title: Require admins to enter admin-mode by re-authenticating before performing
administrative operations
merge_request: 16981
author: Roger Rüttimann & Diego Louzán
type: added
......@@ -21,6 +21,10 @@ namespace :admin do
end
end
resource :session, only: [:new, :create] do
get 'destroy', action: :destroy, as: :destroy
end
resource :impersonation, only: :destroy
resources :abuse_reports, only: [:index, :destroy]
......
......@@ -4,6 +4,8 @@ describe API::GeoNodes, :geo, :prometheus, api: true do
include ApiHelpers
include ::EE::GeoHelpers
include_context 'custom session'
set(:primary) { create(:geo_node, :primary) }
set(:secondary) { create(:geo_node) }
set(:secondary_status) { create(:geo_node_status, :healthy, geo_node: secondary) }
......
......@@ -355,6 +355,8 @@ describe API::Projects do
end
context 'as an admin' do
include_context 'custom session'
let(:admin) { create(:admin) }
it 'returns 500 when repository storage is unknown' do
......
......@@ -17,6 +17,8 @@ module API
request.access_token
end
use AdminModeMiddleware
helpers HelperMethods
install_error_responders(base)
......@@ -52,6 +54,11 @@ module API
forbidden!(api_access_denied_message(user))
end
# Set admin mode for API requests (if admin)
if Feature.enabled?(:user_mode_in_session)
Gitlab::Auth::CurrentUserMode.new(user).enable_admin_mode!(skip_password_validation: true)
end
user
end
......@@ -141,5 +148,22 @@ module API
end
end
end
class AdminModeMiddleware < ::Grape::Middleware::Base
def initialize(app, **options)
super
end
def call(env)
if Feature.enabled?(:user_mode_in_session)
session = {}
Gitlab::Session.with_session(session) do
app.call(env)
end
else
app.call(env)
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module Auth
# Keeps track of the current session user mode
#
# In order to perform administrative tasks over some interfaces,
# an administrator must have explicitly enabled admin-mode
# e.g. on web access require re-authentication
class CurrentUserMode
SESSION_STORE_KEY = :current_user_mode
ADMIN_MODE_START_TIME_KEY = 'admin_mode'
MAX_ADMIN_MODE_TIME = 6.hours
def initialize(user)
@user = user
end
def admin_mode?
return false unless user
Gitlab::SafeRequestStore.fetch(request_store_key) do
user&.admin? && any_session_with_admin_mode?
end
end
def enable_admin_mode!(password: nil, skip_password_validation: false)
return unless user&.admin?
return unless skip_password_validation || user&.valid_password?(password)
current_session_data[ADMIN_MODE_START_TIME_KEY] = Time.now
end
def disable_admin_mode!
current_session_data[ADMIN_MODE_START_TIME_KEY] = nil
Gitlab::SafeRequestStore.delete(request_store_key)
end
private
attr_reader :user
def request_store_key
@request_store_key ||= { res: :current_user_mode, user: user.id }
end
def current_session_data
@current_session ||= Gitlab::NamespacedSessionStore.new(SESSION_STORE_KEY)
end
def any_session_with_admin_mode?
return true if current_session_data.initiated? && current_session_data[ADMIN_MODE_START_TIME_KEY].to_i > MAX_ADMIN_MODE_TIME.ago.to_i
all_sessions.any? do |session|
session[ADMIN_MODE_START_TIME_KEY].to_i > MAX_ADMIN_MODE_TIME.ago.to_i
end
end
def all_sessions
@all_sessions ||= ActiveSession.list_sessions(user).lazy.map do |session|
Gitlab::NamespacedSessionStore.new(SESSION_STORE_KEY, session.with_indifferent_access )
end
end
end
end
end
......@@ -1031,6 +1031,9 @@ msgstr ""
msgid "Admin Section"
msgstr ""
msgid "Admin mode disabled"
msgstr ""
msgid "Admin notes"
msgstr ""
......@@ -5734,6 +5737,9 @@ msgstr ""
msgid "Enter a number"
msgstr ""
msgid "Enter admin mode"
msgstr ""
msgid "Enter at least three characters to search"
msgstr ""
......@@ -9123,6 +9129,9 @@ msgstr ""
msgid "Leave"
msgstr ""
msgid "Leave admin mode"
msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
......@@ -12739,6 +12748,9 @@ msgstr ""
msgid "Raw blob request rate limit per minute"
msgstr ""
msgid "Re-authentication required"
msgstr ""
msgid "Read more"
msgstr ""
......
# frozen_string_literal: true
require 'spec_helper'
describe Admin::SessionsController, :do_not_mock_admin_mode do
include_context 'custom session'
let(:user) { create(:user) }
before do
sign_in(user)
end
describe '#new' do
context 'for regular users' do
it 'shows error page' do
get :new
expect(response).to have_gitlab_http_status(:not_found)
expect(controller.send(:current_user_mode).admin_mode?).to be(false)
end
end
context 'for admin users' do
let(:user) { create(:admin) }
it 'renders a password form' do
get :new
expect(response).to render_template :new
expect(controller.send(:current_user_mode).admin_mode?).to be(false)
end
end
end
describe '#create' do
context 'for regular users' do
it 'shows error page' do
post :create
expect(response).to have_gitlab_http_status(:not_found)
expect(controller.send(:current_user_mode).admin_mode?).to be(false)
end
end
context 'for admin users' do
let(:user) { create(:admin) }
it 'sets admin mode with a valid password' do
expect(controller.send(:current_user_mode).admin_mode?).to be(false)
controller.store_location_for(:redirect, admin_root_path)
post :create, params: { password: user.password }
expect(response).to redirect_to admin_root_path
expect(controller.send(:current_user_mode).admin_mode?).to be(true)
end
it 'fails with an invalid password' do
expect(controller.send(:current_user_mode).admin_mode?).to be(false)
controller.store_location_for(:redirect, admin_root_path)
post :create, params: { password: '' }
expect(response).to render_template :new
expect(controller.send(:current_user_mode).admin_mode?).to be(false)
end
end
end
describe '#destroy' do
context 'for regular users' do
it 'shows error page' do
get :destroy
expect(response).to have_gitlab_http_status(404)
expect(controller.send(:current_user_mode).admin_mode?).to be(false)
end
end
context 'for admin users' do
let(:user) { create(:admin) }
it 'disables admin mode and redirects to main page' do
expect(controller.send(:current_user_mode).admin_mode?).to be(false)
post :create, params: { password: user.password }
expect(controller.send(:current_user_mode).admin_mode?).to be(true)
get :destroy
expect(response).to have_gitlab_http_status(:found)
expect(response).to redirect_to(root_path)
expect(controller.send(:current_user_mode).admin_mode?).to be(false)
end
end
end
end
......@@ -777,4 +777,48 @@ describe ApplicationController do
end
end
end
describe '#current_user_mode', :do_not_mock_admin_mode do
include_context 'custom session'
controller(described_class) do
def index
render html: 'authenticated'
end
end
before do
allow(ActiveSession).to receive(:list_sessions).with(user).and_return([session])
sign_in(user)
get :index
end
context 'with a regular user' do
it 'admin mode is not set' do
expect(response).to have_gitlab_http_status(:ok)
expect(Gitlab::Auth::CurrentUserMode.new(user).admin_mode?).to be(false)
end
end
context 'with an admin user' do
let(:user) { create(:admin) }
it 'admin mode is not set' do
expect(response).to have_gitlab_http_status(:ok)
expect(Gitlab::Auth::CurrentUserMode.new(user).admin_mode?).to be(false)
end
context 'that re-authenticated' do
before do
Gitlab::Auth::CurrentUserMode.new(user).enable_admin_mode!(password: user.password)
end
it 'admin mode is set' do
expect(response).to have_gitlab_http_status(:ok)
expect(Gitlab::Auth::CurrentUserMode.new(user).admin_mode?).to be(true)
end
end
end
end
end
......@@ -2,7 +2,9 @@
require 'spec_helper'
describe EnforcesAdminAuthentication do
describe EnforcesAdminAuthentication, :do_not_mock_admin_mode do
include AdminModeHelper
let(:user) { create(:user) }
before do
......@@ -10,30 +12,86 @@ describe EnforcesAdminAuthentication do
end
controller(ApplicationController) do
# `described_class` is not available in this context
include EnforcesAdminAuthentication # rubocop:disable RSpec/DescribedClass
include EnforcesAdminAuthentication
def index
head :ok
end
end
describe 'authenticate_admin!' do
context 'as an admin' do
let(:user) { create(:admin) }
context 'feature flag :user_mode_in_session is enabled' do
describe 'authenticate_admin!' do
context 'as an admin' do
let(:user) { create(:admin) }
it 'renders ok' do
get :index
it 'renders redirect for re-authentication and does not set admin mode' do
get :index
expect(response).to redirect_to new_admin_session_path
expect(assigns(:current_user_mode)&.admin_mode?).to be(false)
end
context 'when admin mode is active' do
before do
enable_admin_mode!(user)
end
it 'renders ok' do
get :index
expect(response).to have_gitlab_http_status(200)
end
end
end
context 'as a user' do
it 'renders a 404' do
get :index
expect(response).to have_gitlab_http_status(404)
end
it 'does not set admin mode' do
get :index
expect(response).to have_gitlab_http_status(200)
# check for nil too since on 404, current_user_mode might not be initialized
expect(assigns(:current_user_mode)&.admin_mode?).to be_falsey
end
end
end
end
context 'feature flag :user_mode_in_session is disabled' do
before do
stub_feature_flags(user_mode_in_session: false)
end
context 'as a user' do
it 'renders a 404' do
describe 'authenticate_admin!' do
before do
get :index
end
context 'as an admin' do
let(:user) { create(:admin) }
it 'allows direct access to page' do
expect(response).to have_gitlab_http_status(200)
end
it 'does not set admin mode' do
expect(assigns(:current_user_mode)&.admin_mode?).to be_falsey
end
end
context 'as a user' do
it 'renders a 404' do
expect(response).to have_gitlab_http_status(404)
end
expect(response).to have_gitlab_http_status(404)
it 'does not set admin mode' do
# check for nil too since on 404, current_user_mode might not be initialized
expect(assigns(:current_user_mode)&.admin_mode?).to be_falsey
end
end
end
end
......
This diff is collapsed.
require 'spec_helper'
describe NavHelper do
describe NavHelper, :do_not_mock_admin_mode do
describe '#header_links' do
include_context 'custom session'
before do
allow(helper).to receive(:session) { {} }
allow(helper).to receive(:session).and_return(session)
end
context 'when the user is logged in' do
let(:user) { build(:user) }
let(:user) { create(:user) }
let(:current_user_mode) { Gitlab::Auth::CurrentUserMode.new(user) }
before do
allow(helper).to receive(:current_user).and_return(user)
allow(helper).to receive(:current_user_mode).and_return(current_user_mode)
allow(helper).to receive(:can?) { true }
end
......@@ -26,6 +30,46 @@ describe NavHelper do
expect(helper.header_links).to include(:admin_impersonation)
end
context 'as admin' do
let(:user) { create(:user, :admin) }
context 'feature flag :user_mode_in_session is enabled' do
it 'does not contain the admin mode link by default' do
expect(helper.header_links).not_to include(:admin_mode)
end
context 'with admin mode enabled' do
before do
current_user_mode.enable_admin_mode!(password: user.password)
end
it 'contains the admin mode link' do
expect(helper.header_links).to include(:admin_mode)
end
end
end
context 'feature flag :user_mode_in_session is disabled' do
before do
stub_feature_flags(user_mode_in_session: false)
end
it 'does not contain the admin mode link' do
expect(helper.header_links).not_to include(:admin_mode)
end
context 'with admin mode enabled' do
before do
current_user_mode.enable_admin_mode!(password: user.password)
end
it 'has no effect on header links' do
expect(helper.header_links).not_to include(:admin_mode)
end
end
end
end
context 'when the user cannot read cross project' do
before do
allow(helper).to receive(:can?).with(user, :read_cross_project) { false }
......
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Auth::CurrentUserMode, :do_not_mock_admin_mode do
include_context 'custom session'
let(:user) { build(:user) }
subject { described_class.new(user) }
before do
allow(ActiveSession).to receive(:list_sessions).with(user).and_return([session])
end
describe '#admin_mode?', :request_store do
context 'when the user is a regular user' do
it 'is false by default' do
expect(subject.admin_mode?).to be(false)
end
it 'cannot be enabled with a valid password' do
subject.enable_admin_mode!(password: user.password)
expect(subject.admin_mode?).to be(false)
end
it 'cannot be enabled with an invalid password' do
subject.enable_admin_mode!(password: nil)
expect(subject.admin_mode?).to be(false)
end
it 'cannot be enabled with empty params' do
subject.enable_admin_mode!
expect(subject.admin_mode?).to be(false)
end
it 'disable has no effect' do
subject.enable_admin_mode!
subject.disable_admin_mode!
expect(subject.admin_mode?).to be(false)
end
context 'skipping password validation' do
it 'cannot be enabled with a valid password' do
subject.enable_admin_mode!(password: user.password, skip_password_validation: true)
expect(subject.admin_mode?).to be(false)
end
it 'cannot be enabled with an invalid password' do
subject.enable_admin_mode!(skip_password_validation: true)
expect(subject.admin_mode?).to be(false)
end
end
end
context 'when the user is an admin' do
let(:user) { build(:user, :admin) }
it 'is false by default' do
expect(subject.admin_mode?).to be(false)
end
it 'cannot be enabled with an invalid password' do
subject.enable_admin_mode!(password: nil)
expect(subject.admin_mode?).to be(false)
end
it 'can be enabled with a valid password' do
subject.enable_admin_mode!(password: user.password)
expect(subject.admin_mode?).to be(true)
end
it 'can be disabled' do
subject.enable_admin_mode!(password: user.password)
subject.disable_admin_mode!
expect(subject.admin_mode?).to be(false)
end
it 'will expire in the future' do
subject.enable_admin_mode!(password: user.password)
expect(subject.admin_mode?).to be(true), 'admin mode is not active in the present'
Timecop.freeze(Gitlab::Auth::CurrentUserMode::MAX_ADMIN_MODE_TIME.from_now) do
# in the future this will be a new request, simulate by clearing the RequestStore
Gitlab::SafeRequestStore.clear!
expect(subject.admin_mode?).to be(false), 'admin mode did not expire in the future'
end
end
context 'skipping password validation' do
it 'can be enabled with a valid password' do
subject.enable_admin_mode!(password: user.password, skip_password_validation: true)
expect(subject.admin_mode?).to be(true)
end
it 'can be enabled with an invalid password' do
subject.enable_admin_mode!(skip_password_validation: true)
expect(subject.admin_mode?).to be(true)
end
end
context 'with two independent sessions' do
let(:another_session) { {} }
let(:another_subject) { described_class.new(user) }
before do
allow(ActiveSession).to receive(:list_sessions).with(user).and_return([session, another_session])
end
it 'can be enabled in one and seen in the other' do
Gitlab::Session.with_session(another_session) do
another_subject.enable_admin_mode!(password: user.password)
end
expect(subject.admin_mode?).to be(true)
end
end
end
end
describe '#enable_admin_mode!' do
let(:user) { build(:user, :admin) }
it 'creates a timestamp in the session' do
subject.enable_admin_mode!(password: user.password)
expect(session).to include(expected_session_entry(be_within(1.second).of Time.now))
end
end
describe '#disable_admin_mode!' do
let(:user) { build(:user, :admin) }
it 'sets the session timestamp to nil' do
subject.disable_admin_mode!
expect(session).to include(expected_session_entry(be_nil))
end
end
def expected_session_entry(value_matcher)
{
Gitlab::Auth::CurrentUserMode::SESSION_STORE_KEY => a_hash_including(
Gitlab::Auth::CurrentUserMode::ADMIN_MODE_START_TIME_KEY => value_matcher)
}
end
end
......@@ -343,6 +343,8 @@ describe API::Helpers do
end
context 'sudo' do
include_context 'custom session'
shared_examples 'successful sudo' do
it 'sets current_user' do
expect(current_user).to eq(user)
......
......@@ -3,9 +3,14 @@ require 'spec_helper'
describe BuildActionEntity do
let(:job) { create(:ci_build, name: 'test_job') }
let(:request) { double('request') }
let(:user) { create(:user) }
let(:entity) do
described_class.new(job, request: spy('request'))
described_class.new(job, request: request)
end
before do
allow(request).to receive(:current_user).and_return(user)
end
describe '#as_json' do
......
......@@ -160,6 +160,25 @@ RSpec.configure do |config|
allow(Gitlab::Git::KeepAround).to receive(:execute)
Gitlab::ThreadMemoryCache.cache_backend.clear
# Temporary patch to force admin mode to be active by default in tests when
# using the feature flag :user_mode_in_session, since this will require
# modifying a significant number of specs to test both states for admin
# mode enabled / disabled.
#
# See https://gitlab.com/gitlab-org/gitlab/issues/31511
# See gitlab/spec/support/helpers/admin_mode_helpers.rb
#
# If it is required to have the real behaviour that an admin is signed in
# with normal user mode and needs to switch to admin mode, it is possible to
# mark such tests with the `do_not_mock_admin_mode` metadata tag, e.g:
#
# context 'some test with normal user mode', :do_not_mock_admin_mode do ... end
unless example.metadata[:do_not_mock_admin_mode]
allow_any_instance_of(Gitlab::Auth::CurrentUserMode).to receive(:admin_mode?) do |current_user_mode|
current_user_mode.send(:user)&.admin?
end
end
end
config.around(:example, :quarantine) do |example|
......
# frozen_string_literal: true
# Helper for enabling admin mode in tests
module AdminModeHelper
# Users are logged in by default in user mode and have to switch to admin
# mode for accessing any administrative functionality. This helper lets a user
# be in admin mode without requiring a second authentication step (provided
# the user is an admin)
def enable_admin_mode!(user)
fake_user_mode = instance_double(Gitlab::Auth::CurrentUserMode)
allow(Gitlab::Auth::CurrentUserMode).to receive(:new).with(user).and_return(fake_user_mode)
allow(fake_user_mode).to receive(:admin_mode?).and_return(user&.admin?)
end
end
......@@ -48,6 +48,14 @@ module LoginHelpers
@current_user = user
end
def gitlab_enable_admin_mode_sign_in(user)
visit new_admin_session_path
fill_in 'password', with: user.password
click_button 'Enter admin mode'
end
def gitlab_sign_in_via(provider, user, uid, saml_response = nil)
mock_auth_hash_with_saml_xml(provider, uid, user.email, saml_response)
visit new_user_session_path
......
# frozen_string_literal: true
# the session is empty by default; you can overwrite it by defining your own
# let(:session) variable
# we do not use a parameter such as |session| because it does not play nice
# with let variables
shared_context 'custom session' do
let!(:session) { {} }
around do |example|
Gitlab::Session.with_session(session) do
example.run
end
end
end
require 'spec_helper'
describe 'admin/sessions/new.html.haml' do
context 'admin has password set' do
before do
allow(view).to receive(:password_authentication_enabled_for_web?).and_return(true)
end
it "shows enter password form" do
render
expect(rendered).to have_css('#login-pane.active')
expect(rendered).to have_selector('input[name="password"]')
end
end
context 'admin has no password set' do
before do
allow(view).to receive(:password_authentication_enabled_for_web?).and_return(false)
end
it "warns authentication not possible" do
render
expect(rendered).not_to have_css('#login-pane')
expect(rendered).to have_content 'No authentication methods configured'
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment