debian-mirror-gitlab/lib/gitlab/auth/current_user_mode.rb

189 lines
6.3 KiB
Ruby
Raw Normal View History

2019-12-21 20:55:43 +05:30
# 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
2020-01-01 13:55:28 +05:30
NotRequestedError = Class.new(StandardError)
2020-03-13 15:44:24 +05:30
# RequestStore entries
CURRENT_REQUEST_BYPASS_SESSION_ADMIN_ID_RS_KEY = { res: :current_user_mode, data: :bypass_session_admin_id }.freeze
CURRENT_REQUEST_ADMIN_MODE_USER_RS_KEY = { res: :current_user_mode, data: :current_admin }.freeze
# SessionStore entries
2019-12-21 20:55:43 +05:30
SESSION_STORE_KEY = :current_user_mode
2020-03-13 15:44:24 +05:30
ADMIN_MODE_START_TIME_KEY = :admin_mode
ADMIN_MODE_REQUESTED_TIME_KEY = :admin_mode_requested
2019-12-21 20:55:43 +05:30
MAX_ADMIN_MODE_TIME = 6.hours
2020-01-01 13:55:28 +05:30
ADMIN_MODE_REQUESTED_GRACE_PERIOD = 5.minutes
2019-12-21 20:55:43 +05:30
2020-03-13 15:44:24 +05:30
class << self
# Admin mode activation requires storing a flag in the user session. Using this
2020-04-08 14:13:33 +05:30
# method when scheduling jobs in sessionless environments (e.g. Sidekiq, API)
# will bypass the session check for a user that was already in admin mode
#
# If passed a block, it will surround the block execution and reset the session
2021-09-04 01:27:46 +05:30
# bypass at the end; otherwise you must remember to call '.reset_bypass_session!'
2020-03-13 15:44:24 +05:30
def bypass_session!(admin_id)
Gitlab::SafeRequestStore[CURRENT_REQUEST_BYPASS_SESSION_ADMIN_ID_RS_KEY] = admin_id
2021-09-04 01:27:46 +05:30
# Bypassing the session invalidates the cached value of admin_mode?
# Any new calls need to be re-computed.
uncache_admin_mode_state(admin_id)
2020-03-13 15:44:24 +05:30
Gitlab::AppLogger.debug("Bypassing session in admin mode for: #{admin_id}")
2021-09-04 01:27:46 +05:30
return unless block_given?
begin
yield
ensure
reset_bypass_session!(admin_id)
2020-04-08 14:13:33 +05:30
end
end
2021-09-04 01:27:46 +05:30
def reset_bypass_session!(admin_id = nil)
# Restoring the session bypass invalidates the cached value of admin_mode?
uncache_admin_mode_state(admin_id)
2020-03-13 15:44:24 +05:30
Gitlab::SafeRequestStore.delete(CURRENT_REQUEST_BYPASS_SESSION_ADMIN_ID_RS_KEY)
end
def bypass_session_admin_id
Gitlab::SafeRequestStore[CURRENT_REQUEST_BYPASS_SESSION_ADMIN_ID_RS_KEY]
end
2021-09-04 01:27:46 +05:30
def uncache_admin_mode_state(admin_id = nil)
if admin_id
key = { res: :current_user_mode, user: admin_id, method: :admin_mode? }
Gitlab::SafeRequestStore.delete(key)
else
Gitlab::SafeRequestStore.delete_if do |key|
key.is_a?(Hash) && key[:res] == :current_user_mode && key[:method] == :admin_mode?
end
end
end
2020-03-13 15:44:24 +05:30
# Store in the current request the provided user model (only if in admin mode)
# and yield
def with_current_admin(admin)
2021-09-04 01:27:46 +05:30
return yield unless new(admin).admin_mode?
2020-03-13 15:44:24 +05:30
Gitlab::SafeRequestStore[CURRENT_REQUEST_ADMIN_MODE_USER_RS_KEY] = admin
Gitlab::AppLogger.debug("Admin mode active for: #{admin.username}")
yield
ensure
Gitlab::SafeRequestStore.delete(CURRENT_REQUEST_ADMIN_MODE_USER_RS_KEY)
end
def current_admin
Gitlab::SafeRequestStore[CURRENT_REQUEST_ADMIN_MODE_USER_RS_KEY]
end
end
2019-12-21 20:55:43 +05:30
def initialize(user)
@user = user
end
def admin_mode?
return false unless user
2020-01-01 13:55:28 +05:30
Gitlab::SafeRequestStore.fetch(admin_mode_rs_key) do
2021-04-17 20:07:23 +05:30
user.admin? && (privileged_runtime? || session_with_admin_mode?)
2020-01-01 13:55:28 +05:30
end
end
def admin_mode_requested?
return false unless user
Gitlab::SafeRequestStore.fetch(admin_mode_requested_rs_key) do
user.admin? && admin_mode_requested_in_grace_period?
2019-12-21 20:55:43 +05:30
end
end
def enable_admin_mode!(password: nil, skip_password_validation: false)
2023-03-04 22:38:38 +05:30
return false unless user&.admin?
return false unless skip_password_validation || user&.valid_password?(password)
2019-12-21 20:55:43 +05:30
2020-01-01 13:55:28 +05:30
raise NotRequestedError unless admin_mode_requested?
2020-03-13 15:44:24 +05:30
reset_request_store_cache_entries
2020-01-01 13:55:28 +05:30
current_session_data[ADMIN_MODE_REQUESTED_TIME_KEY] = nil
2019-12-21 20:55:43 +05:30
current_session_data[ADMIN_MODE_START_TIME_KEY] = Time.now
2023-03-04 22:38:38 +05:30
audit_user_enable_admin_mode
true
2019-12-21 20:55:43 +05:30
end
def disable_admin_mode!
2020-01-01 13:55:28 +05:30
return unless user&.admin?
2020-03-13 15:44:24 +05:30
reset_request_store_cache_entries
2020-01-01 13:55:28 +05:30
current_session_data[ADMIN_MODE_REQUESTED_TIME_KEY] = nil
2019-12-21 20:55:43 +05:30
current_session_data[ADMIN_MODE_START_TIME_KEY] = nil
2020-01-01 13:55:28 +05:30
end
def request_admin_mode!
return unless user&.admin?
2020-03-13 15:44:24 +05:30
reset_request_store_cache_entries
2020-01-01 13:55:28 +05:30
current_session_data[ADMIN_MODE_REQUESTED_TIME_KEY] = Time.now
2019-12-21 20:55:43 +05:30
end
private
attr_reader :user
2020-03-13 15:44:24 +05:30
# RequestStore entry to cache #admin_mode? result
2020-01-01 13:55:28 +05:30
def admin_mode_rs_key
@admin_mode_rs_key ||= { res: :current_user_mode, user: user.id, method: :admin_mode? }
end
2020-03-13 15:44:24 +05:30
# RequestStore entry to cache #admin_mode_requested? result
2020-01-01 13:55:28 +05:30
def admin_mode_requested_rs_key
@admin_mode_requested_rs_key ||= { res: :current_user_mode, user: user.id, method: :admin_mode_requested? }
2019-12-21 20:55:43 +05:30
end
def current_session_data
@current_session ||= Gitlab::NamespacedSessionStore.new(SESSION_STORE_KEY)
end
2020-04-22 19:07:51 +05:30
def session_with_admin_mode?
2020-03-13 15:44:24 +05:30
return true if bypass_session?
2019-12-21 20:55:43 +05:30
2020-04-22 19:07:51 +05:30
current_session_data.initiated? && current_session_data[ADMIN_MODE_START_TIME_KEY].to_i > MAX_ADMIN_MODE_TIME.ago.to_i
2019-12-21 20:55:43 +05:30
end
2020-01-01 13:55:28 +05:30
def admin_mode_requested_in_grace_period?
current_session_data[ADMIN_MODE_REQUESTED_TIME_KEY].to_i > ADMIN_MODE_REQUESTED_GRACE_PERIOD.ago.to_i
end
2020-03-13 15:44:24 +05:30
def bypass_session?
user&.id && user.id == self.class.bypass_session_admin_id
end
def reset_request_store_cache_entries
2020-01-01 13:55:28 +05:30
Gitlab::SafeRequestStore.delete(admin_mode_rs_key)
Gitlab::SafeRequestStore.delete(admin_mode_requested_rs_key)
end
2021-04-17 20:07:23 +05:30
# Runtimes which imply shell access get admin mode automatically, see Gitlab::Runtime
def privileged_runtime?
Gitlab::Runtime.rake? || Gitlab::Runtime.rails_runner? || Gitlab::Runtime.console?
end
2023-03-04 22:38:38 +05:30
def audit_user_enable_admin_mode; end
2019-12-21 20:55:43 +05:30
end
end
end
2023-03-04 22:38:38 +05:30
Gitlab::Auth::CurrentUserMode.prepend_mod_with('Gitlab::Auth::CurrentUserMode')