Commit 83b2d4b1 authored by Imre Farkas's avatar Imre Farkas

Merge branch 'refactor/convert-admin-mode-feature-flag-to-setting' into 'master'

Convert admin mode feature flag to system application setting [RUN ALL RSPEC] [RUN AS-IF-FOSS]

See merge request gitlab-org/gitlab!53610
parents c38d4346 02f7afd6
...@@ -482,7 +482,7 @@ class ApplicationController < ActionController::Base ...@@ -482,7 +482,7 @@ class ApplicationController < ActionController::Base
end end
def set_current_admin(&block) def set_current_admin(&block)
return yield unless Feature.enabled?(:user_mode_in_session) return yield unless Gitlab::CurrentSettings.admin_mode
return yield unless current_user return yield unless current_user
Gitlab::Auth::CurrentUserMode.with_current_admin(current_user, &block) Gitlab::Auth::CurrentUserMode.with_current_admin(current_user, &block)
......
...@@ -15,7 +15,7 @@ module EnforcesAdminAuthentication ...@@ -15,7 +15,7 @@ module EnforcesAdminAuthentication
def authenticate_admin! def authenticate_admin!
return render_404 unless current_user.admin? return render_404 unless current_user.admin?
return unless Feature.enabled?(:user_mode_in_session) return unless Gitlab::CurrentSettings.admin_mode
unless current_user_mode.admin_mode? unless current_user_mode.admin_mode?
current_user_mode.request_admin_mode! current_user_mode.request_admin_mode!
......
...@@ -27,7 +27,7 @@ module SessionlessAuthentication ...@@ -27,7 +27,7 @@ module SessionlessAuthentication
end end
def sessionless_bypass_admin_mode!(&block) def sessionless_bypass_admin_mode!(&block)
return yield unless Feature.enabled?(:user_mode_in_session) return yield unless Gitlab::CurrentSettings.admin_mode
Gitlab::Auth::CurrentUserMode.bypass_session!(current_user.id, &block) Gitlab::Auth::CurrentUserMode.bypass_session!(current_user.id, &block)
end end
......
...@@ -16,7 +16,7 @@ class Ldap::OmniauthCallbacksController < OmniauthCallbacksController ...@@ -16,7 +16,7 @@ class Ldap::OmniauthCallbacksController < OmniauthCallbacksController
def ldap def ldap
return unless Gitlab::Auth::Ldap::Config.sign_in_enabled? return unless Gitlab::Auth::Ldap::Config.sign_in_enabled?
if Feature.enabled?(:user_mode_in_session) if Gitlab::CurrentSettings.admin_mode
return admin_mode_flow(Gitlab::Auth::Ldap::User) if current_user_mode.admin_mode_requested? return admin_mode_flow(Gitlab::Auth::Ldap::User) if current_user_mode.admin_mode_requested?
end end
......
...@@ -95,7 +95,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController ...@@ -95,7 +95,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
end end
def after_omniauth_failure_path_for(scope) def after_omniauth_failure_path_for(scope)
if Feature.enabled?(:user_mode_in_session) if Gitlab::CurrentSettings.admin_mode
return new_admin_session_path if current_user_mode.admin_mode_requested? return new_admin_session_path if current_user_mode.admin_mode_requested?
end end
...@@ -112,7 +112,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController ...@@ -112,7 +112,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
log_audit_event(current_user, with: oauth['provider']) log_audit_event(current_user, with: oauth['provider'])
if Feature.enabled?(:user_mode_in_session) if Gitlab::CurrentSettings.admin_mode
return admin_mode_flow(auth_module::User) if current_user_mode.admin_mode_requested? return admin_mode_flow(auth_module::User) if current_user_mode.admin_mode_requested?
end end
......
...@@ -179,6 +179,7 @@ module ApplicationSettingsHelper ...@@ -179,6 +179,7 @@ module ApplicationSettingsHelper
def visible_attributes def visible_attributes
[ [
:abuse_notification_email, :abuse_notification_email,
:admin_mode,
:after_sign_out_path, :after_sign_out_path,
:after_sign_up_text, :after_sign_up_text,
:akismet_api_key, :akismet_api_key,
......
...@@ -92,10 +92,8 @@ module NavHelper ...@@ -92,10 +92,8 @@ module NavHelper
links << :admin_impersonation links << :admin_impersonation
end end
if Feature.enabled?(:user_mode_in_session) if Gitlab::CurrentSettings.admin_mode && current_user_mode.admin_mode?
if current_user_mode.admin_mode? links << :admin_mode
links << :admin_mode
end
end end
links links
......
...@@ -465,6 +465,9 @@ class ApplicationSetting < ApplicationRecord ...@@ -465,6 +465,9 @@ class ApplicationSetting < ApplicationRecord
length: { maximum: 100, message: N_('is too long (maximum is 100 entries)') }, length: { maximum: 100, message: N_('is too long (maximum is 100 entries)') },
allow_nil: false allow_nil: false
validates :admin_mode,
inclusion: { in: [true, false], message: _('must be a boolean value') }
attr_encrypted :asset_proxy_secret_key, attr_encrypted :asset_proxy_secret_key,
mode: :per_attribute_iv, mode: :per_attribute_iv,
key: Settings.attr_encrypted_db_key_base_truncated, key: Settings.attr_encrypted_db_key_base_truncated,
......
...@@ -35,6 +35,7 @@ module ApplicationSettingImplementation ...@@ -35,6 +35,7 @@ module ApplicationSettingImplementation
class_methods do class_methods do
def defaults def defaults
{ {
admin_mode: false,
after_sign_up_text: nil, after_sign_up_text: nil,
akismet_enabled: false, akismet_enabled: false,
allow_local_requests_from_system_hooks: true, allow_local_requests_from_system_hooks: true,
......
...@@ -6,7 +6,7 @@ class BasePolicy < DeclarativePolicy::Base ...@@ -6,7 +6,7 @@ class BasePolicy < DeclarativePolicy::Base
desc "User is an instance admin" desc "User is an instance admin"
with_options scope: :user, score: 0 with_options scope: :user, score: 0
condition(:admin) do condition(:admin) do
if Feature.enabled?(:user_mode_in_session) if Gitlab::CurrentSettings.admin_mode
Gitlab::Auth::CurrentUserMode.new(@user).admin_mode? Gitlab::Auth::CurrentUserMode.new(@user).admin_mode?
else else
@user&.admin? @user&.admin?
......
...@@ -31,6 +31,15 @@ ...@@ -31,6 +31,15 @@
= f.check_box :require_two_factor_authentication, class: 'form-check-input' = f.check_box :require_two_factor_authentication, class: 'form-check-input'
= f.label :require_two_factor_authentication, class: 'form-check-label' do = f.label :require_two_factor_authentication, class: 'form-check-label' do
Require all users to set up Two-factor authentication Require all users to set up Two-factor authentication
.form-group
= f.label :admin_mode, _('Admin Mode'), class: 'label-bold'
= sprite_icon('lock', css_class: 'gl-icon')
.form-check
= f.check_box :admin_mode, class: 'form-check-input'
= f.label :admin_mode, class: 'form-check-label' do
= _('Require additional authentication for administrative tasks')
.form-text.text-muted
= link_to _('Learn more.'), help_page_path('user/admin_area/settings/sign_in_restrictions', anchor: 'admin-mode')
.form-group .form-group
= f.label :unknown_sign_in, _('Email notification for unknown sign-ins'), class: 'label-bold' = f.label :unknown_sign_in, _('Email notification for unknown sign-ins'), class: 'label-bold'
.form-check .form-check
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
= nav_link(controller: 'admin/dashboard') do = nav_link(controller: 'admin/dashboard') do
= link_to admin_root_path, class: 'admin-icon qa-admin-area-link d-xl-none' do = link_to admin_root_path, class: 'admin-icon qa-admin-area-link d-xl-none' do
= _('Admin Area') = _('Admin Area')
- if Feature.enabled?(:user_mode_in_session) - if Gitlab::CurrentSettings.admin_mode
- if header_link?(:admin_mode) - if header_link?(:admin_mode)
= nav_link(controller: 'admin/sessions') do = nav_link(controller: 'admin/sessions') do
= link_to destroy_admin_session_path, method: :post, class: 'd-lg-none lock-open-icon' do = link_to destroy_admin_session_path, method: :post, class: 'd-lg-none lock-open-icon' do
...@@ -69,7 +69,7 @@ ...@@ -69,7 +69,7 @@
= 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 = 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) = sprite_icon('admin', size: 18)
- if Feature.enabled?(:user_mode_in_session) - if Gitlab::CurrentSettings.admin_mode
- if header_link?(:admin_mode) - if header_link?(:admin_mode)
= nav_link(controller: 'admin/sessions', html_options: { class: "d-none d-lg-block"}) do = nav_link(controller: 'admin/sessions', html_options: { class: "d-none d-lg-block"}) do
= link_to destroy_admin_session_path, method: :post, title: _('Leave Admin Mode'), aria: { label: _('Leave Admin Mode') }, data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do = link_to destroy_admin_session_path, method: :post, title: _('Leave Admin Mode'), aria: { label: _('Leave Admin Mode') }, data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
......
---
title: Convert admin mode feature flag to system application setting
merge_request: 53610
author: Diego Louzán
type: added
---
name: user_mode_in_session
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/16981
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/321025
milestone: 12.4
type: development
group: group::access
default_enabled: false
# frozen_string_literal: true
class AddAdminModeToApplicationSetting < ActiveRecord::Migration[6.0]
DOWNTIME = false
def change
add_column :application_settings, :admin_mode, :boolean, default: false, null: false
end
end
968ba7808c969e29f1c3b6b635bff22f986b60e56cb001737ad8aba1825fd945
\ No newline at end of file
...@@ -9473,6 +9473,7 @@ CREATE TABLE application_settings ( ...@@ -9473,6 +9473,7 @@ CREATE TABLE application_settings (
kroki_formats jsonb DEFAULT '{}'::jsonb NOT NULL, kroki_formats jsonb DEFAULT '{}'::jsonb NOT NULL,
in_product_marketing_emails_enabled boolean DEFAULT true NOT NULL, in_product_marketing_emails_enabled boolean DEFAULT true NOT NULL,
asset_proxy_whitelist text, asset_proxy_whitelist text,
admin_mode boolean DEFAULT false NOT NULL,
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)), CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
CONSTRAINT app_settings_registry_exp_policies_worker_capacity_positive CHECK ((container_registry_expiration_policies_worker_capacity >= 0)), CONSTRAINT app_settings_registry_exp_policies_worker_capacity_positive CHECK ((container_registry_expiration_policies_worker_capacity >= 0)),
CONSTRAINT check_17d9558205 CHECK ((char_length(kroki_url) <= 1024)), CONSTRAINT check_17d9558205 CHECK ((char_length(kroki_url) <= 1024)),
...@@ -86,7 +86,8 @@ Example response: ...@@ -86,7 +86,8 @@ Example response:
"require_admin_approval_after_user_signup": false, "require_admin_approval_after_user_signup": false,
"personal_access_token_prefix": "GL-", "personal_access_token_prefix": "GL-",
"rate_limiting_response_text": null, "rate_limiting_response_text": null,
"keep_latest_artifact": true "keep_latest_artifact": true,
"admin_mode": false
} }
``` ```
...@@ -181,7 +182,8 @@ Example response: ...@@ -181,7 +182,8 @@ Example response:
"require_admin_approval_after_user_signup": false, "require_admin_approval_after_user_signup": false,
"personal_access_token_prefix": "GL-", "personal_access_token_prefix": "GL-",
"rate_limiting_response_text": null, "rate_limiting_response_text": null,
"keep_latest_artifact": true "keep_latest_artifact": true,
"admin_mode": false
} }
``` ```
...@@ -208,6 +210,7 @@ listed in the descriptions of the relevant settings. ...@@ -208,6 +210,7 @@ listed in the descriptions of the relevant settings.
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
|------------------------------------------|------------------|:------------------------------------:|-------------| |------------------------------------------|------------------|:------------------------------------:|-------------|
| `admin_mode` | boolean | no | Require admins to enable Admin Mode by re-authenticating for administrative tasks. |
| `admin_notification_email` | string | no | Deprecated: Use `abuse_notification_email` instead. If set, [abuse reports](../user/admin_area/abuse_reports.md) are sent to this address. Abuse reports are always available in the Admin Area. | | `admin_notification_email` | string | no | Deprecated: Use `abuse_notification_email` instead. If set, [abuse reports](../user/admin_area/abuse_reports.md) are sent to this address. Abuse reports are always available in the Admin Area. |
| `abuse_notification_email` | string | no | If set, [abuse reports](../user/admin_area/abuse_reports.md) are sent to this address. Abuse reports are always available in the Admin Area. | | `abuse_notification_email` | string | no | If set, [abuse reports](../user/admin_area/abuse_reports.md) are sent to this address. Abuse reports are always available in the Admin Area. |
| `after_sign_out_path` | string | no | Where to redirect users after logout. | | `after_sign_out_path` | string | no | Where to redirect users after logout. |
......
...@@ -565,7 +565,7 @@ In some scenarios such as [this one](https://gitlab.com/gitlab-org/gitlab/-/issu ...@@ -565,7 +565,7 @@ In some scenarios such as [this one](https://gitlab.com/gitlab-org/gitlab/-/issu
return unless user return unless user
# Sessions are enforced to be unavailable for API calls, so ignore them for admin mode # Sessions are enforced to be unavailable for API calls, so ignore them for admin mode
Gitlab::Auth::CurrentUserMode.bypass_session!(user.id) if Feature.enabled?(:user_mode_in_session) Gitlab::Auth::CurrentUserMode.bypass_session!(user.id) if Gitlab::CurrentSettings.admin_mode
unless api_access_allowed?(user) unless api_access_allowed?(user)
forbidden!(api_access_denied_message(user)) forbidden!(api_access_denied_message(user))
...@@ -581,7 +581,7 @@ In order to prevent this from happening, it is recommended to use the method `us ...@@ -581,7 +581,7 @@ In order to prevent this from happening, it is recommended to use the method `us
user = find_user_from_sources user = find_user_from_sources
return unless user return unless user
if user.is_a?(User) && Feature.enabled?(:user_mode_in_session) if user.is_a?(User) && Gitlab::CurrentSettings.admin_mode
# Sessions are enforced to be unavailable for API calls, so ignore them for admin mode # Sessions are enforced to be unavailable for API calls, so ignore them for admin mode
Gitlab::Auth::CurrentUserMode.bypass_session!(user.id) Gitlab::Auth::CurrentUserMode.bypass_session!(user.id)
end end
......
...@@ -23,9 +23,63 @@ You can restrict the password authentication for web interface and Git over HTTP ...@@ -23,9 +23,63 @@ You can restrict the password authentication for web interface and Git over HTTP
- **Web interface**: When this feature is disabled, an [external authentication provider](../../../administration/auth/README.md) must be used. - **Web interface**: When this feature is disabled, an [external authentication provider](../../../administration/auth/README.md) must be used.
- **Git over HTTP(S)**: When this feature is disabled, a [Personal Access Token](../../profile/personal_access_tokens.md) must be used to authenticate. - **Git over HTTP(S)**: When this feature is disabled, a [Personal Access Token](../../profile/personal_access_tokens.md) must be used to authenticate.
## Admin Mode
When this feature is enabled, instance administrators are limited as regular users. During that period,
they do not have access to all projects, groups, or the **Admin Area** menu.
To access potentially dangerous resources, an administrator can activate Admin Mode by:
- Selecting the *Enable Admin Mode* button
- Trying to access any part of the UI that requires an administrator role, specifically those which call `/admin` endpoints.
The main use case allows administrators to perform their regular tasks as a regular
user, based on their memberships, without having to set up a second account for
security reasons.
When Admin Mode status is disabled, administrative users cannot access resources unless
they've been explicitly granted access. For example, when Admin Mode is disabled, they
get a `404` error if they try to open a private group or project, unless
they are members of that group or project.
2FA should be enabled for administrators and is supported for the Admin Mode flow, as are
OmniAuth providers and LDAP auth. The Admin Mode status is stored in the active user
session and remains active until it is explicitly disabled (it will be disabled
automatically after a timeout otherwise).
### Limitations
The following access methods are **not** protected by Admin Mode:
- Git client access (SSH using public keys or HTTPS using Personal Access Tokens).
- API access using a Personal Access Token.
In other words, administrators who are otherwise limited by Admin Mode can still use
Git clients, and access RESTful API endpoints as administrators, without additional
authentication steps.
We may address these limitations in the future. For more information see the following epic:
[Admin mode for GitLab Administrators](https://gitlab.com/groups/gitlab-org/-/epics/2158).
### Troubleshooting
If necessary, you can disable **Admin Mode** as an administrator by using one of these two methods:
- **API**:
```shell
curl --request PUT --header "PRIVATE-TOKEN:$ADMIN_TOKEN" "<gitlab-url>/api/v4/application/settings?admin_mode=false"
```
- [**Rails console**](../../../administration/operations/rails_console.md#starting-a-rails-console-session):
```ruby
::Gitlab::CurrentSettings.update_attributes!(admin_mode: false)
```
## Two-factor authentication ## Two-factor authentication
When this feature enabled, all users must use the [two-factor authentication](../../profile/account/two_factor_authentication.md). When this feature is enabled, all users must use the [two-factor authentication](../../profile/account/two_factor_authentication.md).
After the two-factor authentication is configured as mandatory, users are allowed After the two-factor authentication is configured as mandatory, users are allowed
to skip forced configuration of two-factor authentication for the configurable grace to skip forced configuration of two-factor authentication for the configurable grace
......
...@@ -5,7 +5,6 @@ require 'spec_helper' ...@@ -5,7 +5,6 @@ require 'spec_helper'
RSpec.describe 'Admin interacts with merge requests approvals settings' do RSpec.describe 'Admin interacts with merge requests approvals settings' do
include StubENV include StubENV
let_it_be(:application_settings) { create(:application_setting) }
let_it_be(:user) { create(:admin) } let_it_be(:user) { create(:admin) }
let_it_be(:project) { create(:project, creator: user) } let_it_be(:project) { create(:project, creator: user) }
......
...@@ -53,9 +53,7 @@ RSpec.describe Geo::DeletedProject, :geo, type: :model do ...@@ -53,9 +53,7 @@ RSpec.describe Geo::DeletedProject, :geo, type: :model do
end end
it 'picks storage from ApplicationSetting when value is not initialized' do it 'picks storage from ApplicationSetting when value is not initialized' do
allow_next_instance_of(ApplicationSetting) do |instance| stub_application_setting(pick_repository_storage: 'bar')
allow(instance).to receive(:pick_repository_storage).and_return('bar')
end
subject = described_class.new(id: 1, name: 'sample', disk_path: 'root/sample', repository_storage: nil) subject = described_class.new(id: 1, name: 'sample', disk_path: 'root/sample', repository_storage: nil)
......
...@@ -55,7 +55,7 @@ module API ...@@ -55,7 +55,7 @@ module API
user = find_user_from_sources user = find_user_from_sources
return unless user return unless user
if user.is_a?(User) && Feature.enabled?(:user_mode_in_session) if user.is_a?(User) && Gitlab::CurrentSettings.admin_mode
# Sessions are enforced to be unavailable for API calls, so ignore them for admin mode # Sessions are enforced to be unavailable for API calls, so ignore them for admin mode
Gitlab::Auth::CurrentUserMode.bypass_session!(user.id) Gitlab::Auth::CurrentUserMode.bypass_session!(user.id)
end end
...@@ -236,7 +236,7 @@ module API ...@@ -236,7 +236,7 @@ module API
def after def after
# Use a Grape middleware since the Grape `after` blocks might run # Use a Grape middleware since the Grape `after` blocks might run
# before we are finished rendering the `Grape::Entity` classes # before we are finished rendering the `Grape::Entity` classes
Gitlab::Auth::CurrentUserMode.reset_bypass_session! if Feature.enabled?(:user_mode_in_session) Gitlab::Auth::CurrentUserMode.reset_bypass_session! if Gitlab::CurrentSettings.admin_mode
# Explicit nil is needed or the api call return value will be overwritten # Explicit nil is needed or the api call return value will be overwritten
nil nil
......
...@@ -52,7 +52,7 @@ module API ...@@ -52,7 +52,7 @@ module API
actor.update_last_used_at! actor.update_last_used_at!
check_result = begin check_result = begin
Gitlab::Auth::CurrentUserMode.bypass_session!(actor.user&.id) do with_admin_mode_bypass!(actor.user&.id) do
access_check!(actor, params) access_check!(actor, params)
end end
rescue Gitlab::GitAccess::ForbiddenError => e rescue Gitlab::GitAccess::ForbiddenError => e
...@@ -120,6 +120,14 @@ module API ...@@ -120,6 +120,14 @@ module API
def two_factor_otp_check def two_factor_otp_check
{ success: false, message: 'Feature is not available' } { success: false, message: 'Feature is not available' }
end end
def with_admin_mode_bypass!(actor_id)
return yield unless Gitlab::CurrentSettings.admin_mode
Gitlab::Auth::CurrentUserMode.bypass_session!(actor_id) do
yield
end
end
end end
namespace 'internal' do namespace 'internal' do
......
...@@ -30,6 +30,7 @@ module API ...@@ -30,6 +30,7 @@ module API
success Entities::ApplicationSetting success Entities::ApplicationSetting
end end
params do params do
optional :admin_mode, type: Boolean, desc: 'Require admin users to re-authenticate for administrative (i.e. potentially dangerous) operations'
optional :admin_notification_email, type: String, desc: 'Deprecated: Use :abuse_notification_email instead. Abuse reports will be sent to this address if it is set. Abuse reports are always available in the admin area.' optional :admin_notification_email, type: String, desc: 'Deprecated: Use :abuse_notification_email instead. Abuse reports will be sent to this address if it is set. Abuse reports are always available in the admin area.'
optional :abuse_notification_email, type: String, desc: 'Abuse reports will be sent to this address if it is set. Abuse reports are always available in the admin area.' optional :abuse_notification_email, type: String, desc: 'Abuse reports will be sent to this address if it is set. Abuse reports are always available in the admin area.'
optional :after_sign_up_text, type: String, desc: 'Text shown after sign up' optional :after_sign_up_text, type: String, desc: 'Text shown after sign up'
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
module Constraints module Constraints
class AdminConstrainer class AdminConstrainer
def matches?(request) def matches?(request)
if Feature.enabled?(:user_mode_in_session) if Gitlab::CurrentSettings.admin_mode
admin_mode_enabled?(request) admin_mode_enabled?(request)
else else
user_is_admin?(request) user_is_admin?(request)
......
...@@ -8,7 +8,8 @@ module Gitlab ...@@ -8,7 +8,8 @@ module Gitlab
# If enabled then it injects a job field that persists through the job execution # If enabled then it injects a job field that persists through the job execution
class Client class Client
def call(_worker_class, job, _queue, _redis_pool) def call(_worker_class, job, _queue, _redis_pool)
return yield unless ::Feature.enabled?(:user_mode_in_session) # Not calling Gitlab::CurrentSettings.admin_mode on purpose on sidekiq middleware
# Only when admin mode application setting is enabled might the admin_mode_user_id be non-nil here
# Admin mode enabled in the original request or in a nested sidekiq job # Admin mode enabled in the original request or in a nested sidekiq job
admin_mode_user_id = find_admin_user_id admin_mode_user_id = find_admin_user_id
......
...@@ -5,7 +5,8 @@ module Gitlab ...@@ -5,7 +5,8 @@ module Gitlab
module AdminMode module AdminMode
class Server class Server
def call(_worker, job, _queue) def call(_worker, job, _queue)
return yield unless Feature.enabled?(:user_mode_in_session) # Not calling Gitlab::CurrentSettings.admin_mode on purpose on sidekiq middleware
# Only when admin_mode setting is enabled can it be true here
admin_mode_user_id = job['admin_mode_user_id'] admin_mode_user_id = job['admin_mode_user_id']
......
...@@ -2096,6 +2096,9 @@ msgstr "" ...@@ -2096,6 +2096,9 @@ msgstr ""
msgid "Admin Area" msgid "Admin Area"
msgstr "" msgstr ""
msgid "Admin Mode"
msgstr ""
msgid "Admin Note" msgid "Admin Note"
msgstr "" msgstr ""
...@@ -25900,6 +25903,9 @@ msgstr "" ...@@ -25900,6 +25903,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com." msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr "" msgstr ""
msgid "Require additional authentication for administrative tasks"
msgstr ""
msgid "Require admin approval for new sign-ups" msgid "Require admin approval for new sign-ups"
msgstr "" msgstr ""
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Admin::ApplicationSettingsController do RSpec.describe Admin::ApplicationSettingsController, :do_not_mock_admin_mode_setting do
include StubENV include StubENV
include UsageDataHelpers include UsageDataHelpers
...@@ -164,6 +164,13 @@ RSpec.describe Admin::ApplicationSettingsController do ...@@ -164,6 +164,13 @@ RSpec.describe Admin::ApplicationSettingsController do
expect(ApplicationSetting.current.default_branch_name).to eq("example_branch_name") expect(ApplicationSetting.current.default_branch_name).to eq("example_branch_name")
end end
it "updates admin_mode setting" do
put :update, params: { application_setting: { admin_mode: true } }
expect(response).to redirect_to(general_admin_application_settings_path)
expect(ApplicationSetting.current.admin_mode).to be(true)
end
context "personal access token prefix settings" do context "personal access token prefix settings" do
let(:application_settings) { ApplicationSetting.current } let(:application_settings) { ApplicationSetting.current }
......
...@@ -19,7 +19,7 @@ RSpec.describe EnforcesAdminAuthentication do ...@@ -19,7 +19,7 @@ RSpec.describe EnforcesAdminAuthentication do
end end
end end
context 'feature flag :user_mode_in_session is enabled' do context 'application setting :admin_mode is enabled' do
describe 'authenticate_admin!' do describe 'authenticate_admin!' do
context 'as an admin' do context 'as an admin' do
let(:user) { create(:admin) } let(:user) { create(:admin) }
...@@ -61,9 +61,9 @@ RSpec.describe EnforcesAdminAuthentication do ...@@ -61,9 +61,9 @@ RSpec.describe EnforcesAdminAuthentication do
end end
end end
context 'feature flag :user_mode_in_session is disabled' do context 'application setting :admin_mode is disabled' do
before do before do
stub_feature_flags(user_mode_in_session: false) stub_application_setting(admin_mode: false)
end end
describe 'authenticate_admin!' do describe 'authenticate_admin!' do
......
...@@ -1446,9 +1446,7 @@ RSpec.describe Projects::IssuesController do ...@@ -1446,9 +1446,7 @@ RSpec.describe Projects::IssuesController do
expect_next_instance_of(Spam::AkismetService) do |akismet_service| expect_next_instance_of(Spam::AkismetService) do |akismet_service|
expect(akismet_service).to receive_messages(submit_spam: true) expect(akismet_service).to receive_messages(submit_spam: true)
end end
expect_next_instance_of(ApplicationSetting) do |setting| stub_application_setting(akismet_enabled: true)
expect(setting).to receive_messages(akismet_enabled: true)
end
end end
def post_spam def post_spam
......
...@@ -14,7 +14,7 @@ RSpec.describe 'Admin mode' do ...@@ -14,7 +14,7 @@ RSpec.describe 'Admin mode' do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
end end
context 'feature flag :user_mode_in_session is enabled', :request_store do context 'application setting :admin_mode is enabled', :request_store do
before do before do
sign_in(admin) sign_in(admin)
end end
...@@ -157,9 +157,9 @@ RSpec.describe 'Admin mode' do ...@@ -157,9 +157,9 @@ RSpec.describe 'Admin mode' do
end end
end end
context 'feature flag :user_mode_in_session is disabled' do context 'application setting :admin_mode is disabled' do
before do before do
stub_feature_flags(user_mode_in_session: false) stub_application_setting(admin_mode: false)
sign_in(admin) sign_in(admin)
end end
......
...@@ -9,7 +9,7 @@ RSpec.describe 'Admin updates settings' do ...@@ -9,7 +9,7 @@ RSpec.describe 'Admin updates settings' do
let(:admin) { create(:admin) } let(:admin) { create(:admin) }
context 'feature flag :user_mode_in_session is enabled', :request_store do context 'application setting :admin_mode is enabled', :request_store do
before do before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
sign_in(admin) sign_in(admin)
...@@ -615,9 +615,9 @@ RSpec.describe 'Admin updates settings' do ...@@ -615,9 +615,9 @@ RSpec.describe 'Admin updates settings' do
end end
end end
context 'feature flag :user_mode_in_session is disabled' do context 'application setting :admin_mode is disabled' do
before do before do
stub_feature_flags(user_mode_in_session: false) stub_application_setting(admin_mode: false)
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
......
...@@ -7,9 +7,7 @@ RSpec.describe 'IDE Clientside Preview CSP' do ...@@ -7,9 +7,7 @@ RSpec.describe 'IDE Clientside Preview CSP' do
shared_context 'disable feature' do shared_context 'disable feature' do
before do before do
allow_next_instance_of(ApplicationSetting) do |instance| stub_application_setting(web_ide_clientside_preview_enabled: false)
allow(instance).to receive(:web_ide_clientside_preview_enabled?).and_return(false)
end
end end
end end
...@@ -24,10 +22,8 @@ RSpec.describe 'IDE Clientside Preview CSP' do ...@@ -24,10 +22,8 @@ RSpec.describe 'IDE Clientside Preview CSP' do
end end
before do before do
allow_next_instance_of(ApplicationSetting) do |instance| stub_application_setting(web_ide_clientside_preview_enabled: true)
allow(instance).to receive(:web_ide_clientside_preview_enabled?).and_return(true) stub_application_setting(web_ide_clientside_preview_bundler_url: whitelisted_url)
allow(instance).to receive(:web_ide_clientside_preview_bundler_url).and_return(whitelisted_url)
end
sign_in(user) sign_in(user)
end end
......
...@@ -44,7 +44,7 @@ RSpec.describe GitlabSchema.types['UsageTrendsMeasurement'] do ...@@ -44,7 +44,7 @@ RSpec.describe GitlabSchema.types['UsageTrendsMeasurement'] do
let(:user) { create(:user, :admin) } let(:user) { create(:user, :admin) }
before do before do
stub_feature_flags(user_mode_in_session: false) stub_application_setting(admin_mode: false)
end end
it 'returns data' do it 'returns data' do
......
...@@ -316,9 +316,7 @@ RSpec.describe ApplicationHelper do ...@@ -316,9 +316,7 @@ RSpec.describe ApplicationHelper do
let(:user) { create(:user, static_object_token: 'hunter1') } let(:user) { create(:user, static_object_token: 'hunter1') }
before do before do
allow_next_instance_of(ApplicationSetting) do |instance| stub_application_setting(static_objects_external_storage_url: 'https://cdn.gitlab.com')
allow(instance).to receive(:static_objects_external_storage_url).and_return('https://cdn.gitlab.com')
end
allow(helper).to receive(:current_user).and_return(user) allow(helper).to receive(:current_user).and_return(user)
end end
......
...@@ -35,7 +35,7 @@ RSpec.describe NavHelper do ...@@ -35,7 +35,7 @@ RSpec.describe NavHelper do
context 'as admin' do context 'as admin' do
let(:user) { create(:user, :admin) } let(:user) { create(:user, :admin) }
context 'feature flag :user_mode_in_session is enabled' do context 'application setting :admin_mode is enabled' do
it 'does not contain the admin mode link by default' do it 'does not contain the admin mode link by default' do
expect(helper.header_links).not_to include(:admin_mode) expect(helper.header_links).not_to include(:admin_mode)
end end
...@@ -52,9 +52,9 @@ RSpec.describe NavHelper do ...@@ -52,9 +52,9 @@ RSpec.describe NavHelper do
end end
end end
context 'feature flag :user_mode_in_session is disabled' do context 'application setting :admin_mode is disabled' do
before do before do
stub_feature_flags(user_mode_in_session: false) stub_application_setting(admin_mode: false)
end end
it 'does not contain the admin mode link' do it 'does not contain the admin mode link' do
......
...@@ -16,7 +16,7 @@ RSpec.describe Constraints::AdminConstrainer do ...@@ -16,7 +16,7 @@ RSpec.describe Constraints::AdminConstrainer do
end end
describe '#matches' do describe '#matches' do
context 'feature flag :user_mode_in_session is enabled' do context 'application setting :admin_mode is enabled' do
context 'when user is a regular user' do context 'when user is a regular user' do
it 'forbids access' do it 'forbids access' do
expect(subject.matches?(request)).to be(false) expect(subject.matches?(request)).to be(false)
...@@ -46,9 +46,9 @@ RSpec.describe Constraints::AdminConstrainer do ...@@ -46,9 +46,9 @@ RSpec.describe Constraints::AdminConstrainer do
end end
end end
context 'feature flag :user_mode_in_session is disabled' do context 'application setting :admin_mode is disabled' do
before do before do
stub_feature_flags(user_mode_in_session: false) stub_application_setting(admin_mode: false)
end end
context 'when user is a regular user' do context 'when user is a regular user' do
......
...@@ -38,7 +38,7 @@ RSpec.describe Gitlab::DatabaseImporters::InstanceAdministrators::CreateGroup do ...@@ -38,7 +38,7 @@ RSpec.describe Gitlab::DatabaseImporters::InstanceAdministrators::CreateGroup do
end end
end end
context 'with application settings and admin users' do context 'with application settings and admin users', :do_not_mock_admin_mode_setting do
let(:group) { result[:group] } let(:group) { result[:group] }
let(:application_setting) { Gitlab::CurrentSettings.current_application_settings } let(:application_setting) { Gitlab::CurrentSettings.current_application_settings }
......
...@@ -74,9 +74,9 @@ RSpec.describe Gitlab::SidekiqMiddleware::AdminMode::Client, :request_store do ...@@ -74,9 +74,9 @@ RSpec.describe Gitlab::SidekiqMiddleware::AdminMode::Client, :request_store do
end end
end end
context 'admin mode feature disabled' do context 'admin mode setting disabled' do
before do before do
stub_feature_flags(user_mode_in_session: false) stub_application_setting(admin_mode: false)
end end
it 'yields block' do it 'yields block' do
......
...@@ -52,9 +52,9 @@ RSpec.describe Gitlab::SidekiqMiddleware::AdminMode::Server, :request_store do ...@@ -52,9 +52,9 @@ RSpec.describe Gitlab::SidekiqMiddleware::AdminMode::Server, :request_store do
end end
end end
context 'admin mode feature disabled' do context 'admin mode setting disabled' do
before do before do
stub_feature_flags(user_mode_in_session: false) stub_application_setting(admin_mode: false)
end end
it 'yields block' do it 'yields block' do
......
...@@ -205,7 +205,7 @@ RSpec.describe CacheableAttributes do ...@@ -205,7 +205,7 @@ RSpec.describe CacheableAttributes do
end end
end end
it 'uses RequestStore in addition to process memory cache', :request_store do it 'uses RequestStore in addition to process memory cache', :request_store, :do_not_mock_admin_mode_setting do
# Warm up the cache # Warm up the cache
create(:application_setting).cache! create(:application_setting).cache!
......
...@@ -347,7 +347,7 @@ RSpec.describe Clusters::ClusterPresenter do ...@@ -347,7 +347,7 @@ RSpec.describe Clusters::ClusterPresenter do
before do before do
project.add_maintainer(user) project.add_maintainer(user)
stub_feature_flags(user_mode_in_session: false) stub_application_setting(admin_mode: false)
end end
context 'user can read logs' do context 'user can read logs' do
...@@ -363,7 +363,7 @@ RSpec.describe Clusters::ClusterPresenter do ...@@ -363,7 +363,7 @@ RSpec.describe Clusters::ClusterPresenter do
before do before do
project.add_developer(user) project.add_developer(user)
stub_feature_flags(user_mode_in_session: false) stub_application_setting(admin_mode: false)
end end
it 'returns nil' do it 'returns nil' do
......
...@@ -1115,7 +1115,7 @@ RSpec.describe API::Internal::Base do ...@@ -1115,7 +1115,7 @@ RSpec.describe API::Internal::Base do
end end
end end
context 'feature flag :user_mode_in_session is enabled' do context 'application setting :admin_mode is enabled' do
context 'with an admin user' do context 'with an admin user' do
let(:user) { create(:admin) } let(:user) { create(:admin) }
...@@ -1147,9 +1147,9 @@ RSpec.describe API::Internal::Base do ...@@ -1147,9 +1147,9 @@ RSpec.describe API::Internal::Base do
end end
end end
context 'feature flag :user_mode_in_session is disabled' do context 'application setting :admin_mode is disabled' do
before do before do
stub_feature_flags(user_mode_in_session: false) stub_application_setting(admin_mode: false)
end end
context 'with an admin user' do context 'with an admin user' do
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe API::Settings, 'Settings' do RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting do
let(:user) { create(:user) } let(:user) { create(:user) }
let_it_be(:admin) { create(:admin) } let_it_be(:admin) { create(:admin) }
...@@ -44,6 +44,7 @@ RSpec.describe API::Settings, 'Settings' do ...@@ -44,6 +44,7 @@ RSpec.describe API::Settings, 'Settings' do
expect(json_response['wiki_page_max_content_bytes']).to be_a(Integer) expect(json_response['wiki_page_max_content_bytes']).to be_a(Integer)
expect(json_response['require_admin_approval_after_user_signup']).to eq(true) expect(json_response['require_admin_approval_after_user_signup']).to eq(true)
expect(json_response['personal_access_token_prefix']).to be_nil expect(json_response['personal_access_token_prefix']).to be_nil
expect(json_response['admin_mode']).to be(false)
end end
end end
...@@ -124,7 +125,8 @@ RSpec.describe API::Settings, 'Settings' do ...@@ -124,7 +125,8 @@ RSpec.describe API::Settings, 'Settings' do
disabled_oauth_sign_in_sources: 'unknown', disabled_oauth_sign_in_sources: 'unknown',
import_sources: 'github,bitbucket', import_sources: 'github,bitbucket',
wiki_page_max_content_bytes: 12345, wiki_page_max_content_bytes: 12345,
personal_access_token_prefix: "GL-" personal_access_token_prefix: "GL-",
admin_mode: true
} }
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
...@@ -169,6 +171,7 @@ RSpec.describe API::Settings, 'Settings' do ...@@ -169,6 +171,7 @@ RSpec.describe API::Settings, 'Settings' do
expect(json_response['import_sources']).to match_array(%w(github bitbucket)) expect(json_response['import_sources']).to match_array(%w(github bitbucket))
expect(json_response['wiki_page_max_content_bytes']).to eq(12345) expect(json_response['wiki_page_max_content_bytes']).to eq(12345)
expect(json_response['personal_access_token_prefix']).to eq("GL-") expect(json_response['personal_access_token_prefix']).to eq("GL-")
expect(json_response['admin_mode']).to be(true)
end end
end end
......
...@@ -180,10 +180,11 @@ RSpec.describe JwtController do ...@@ -180,10 +180,11 @@ RSpec.describe JwtController do
end end
context 'when internal auth is disabled' do context 'when internal auth is disabled' do
before do
stub_application_setting(password_authentication_enabled_for_git: false)
end
it 'rejects the authorization attempt with personal access token message' do it 'rejects the authorization attempt with personal access token message' do
allow_next_instance_of(ApplicationSetting) do |instance|
allow(instance).to receive(:password_authentication_enabled_for_git?) { false }
end
get '/jwt/auth', params: parameters, headers: headers get '/jwt/auth', params: parameters, headers: headers
expect(response).to have_gitlab_http_status(:unauthorized) expect(response).to have_gitlab_http_status(:unauthorized)
......
...@@ -297,7 +297,7 @@ RSpec.configure do |config| ...@@ -297,7 +297,7 @@ RSpec.configure do |config|
Sidekiq::Worker.clear_all Sidekiq::Worker.clear_all
# Administrators have to re-authenticate in order to access administrative # Administrators have to re-authenticate in order to access administrative
# functionality when feature flag :user_mode_in_session is active. Any spec # functionality when application setting admin_mode is active. Any spec
# that requires administrative access can use the tag :enable_admin_mode # that requires administrative access can use the tag :enable_admin_mode
# to avoid the second auth step (provided the user is already an admin): # to avoid the second auth step (provided the user is already an admin):
# #
...@@ -314,6 +314,9 @@ RSpec.configure do |config| ...@@ -314,6 +314,9 @@ RSpec.configure do |config|
end end
end end
# Make sure specs test by default admin mode setting on, unless forced to the opposite
stub_application_setting(admin_mode: true) unless example.metadata[:do_not_mock_admin_mode_setting]
allow(Gitlab::CurrentSettings).to receive(:current_application_settings?).and_return(false) allow(Gitlab::CurrentSettings).to receive(:current_application_settings?).and_return(false)
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