Class: Gitlab::Auth::CurrentUserMode
- Inherits:
-
Object
- Object
- Gitlab::Auth::CurrentUserMode
- Includes:
- Utils::StrongMemoize
- Defined in:
- lib/gitlab/auth/current_user_mode.rb
Overview
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
Constant Summary collapse
- NotRequestedError =
Class.new(StandardError)
- NonSidekiqEnvironmentError =
Class.new(StandardError)
- CURRENT_REQUEST_BYPASS_SESSION_ADMIN_ID_RS_KEY =
RequestStore entries
{ 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
- SESSION_STORE_KEY =
SessionStore entries
:current_user_mode- ADMIN_MODE_START_TIME_KEY =
:admin_mode- ADMIN_MODE_REQUESTED_TIME_KEY =
:admin_mode_requested- MAX_ADMIN_MODE_TIME =
6.hours
- ADMIN_MODE_REQUESTED_GRACE_PERIOD =
5.minutes
Class Method Summary collapse
-
.bypass_session!(admin_id) ⇒ Object
Admin mode activation requires storing a flag in the user session.
- .bypass_session_admin_id ⇒ Object
- .current_admin ⇒ Object
-
.optionally_run_in_admin_mode(user) ⇒ Object
Execute the given block with admin privileges if the user is an admin and admin mode is enabled.
- .reset_bypass_session!(admin_id = nil) ⇒ Object
- .uncache_admin_mode_state(admin_id = nil) ⇒ Object
-
.with_current_admin(admin) ⇒ Object
Store in the current request the provided user model (only if in admin mode) and yield.
Instance Method Summary collapse
- #admin_mode? ⇒ Boolean
- #admin_mode_requested? ⇒ Boolean
- #current_session_data ⇒ Object
- #disable_admin_mode! ⇒ Object
- #enable_admin_mode!(password: nil, skip_password_validation: false) ⇒ Object
-
#initialize(user, session = Gitlab::Session.current) ⇒ CurrentUserMode
constructor
A new instance of CurrentUserMode.
- #request_admin_mode! ⇒ Object
Constructor Details
#initialize(user, session = Gitlab::Session.current) ⇒ CurrentUserMode
Returns a new instance of CurrentUserMode.
105 106 107 108 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 105 def initialize(user, session = Gitlab::Session.current) @user = user @session = session end |
Class Method Details
.bypass_session!(admin_id) ⇒ Object
Admin mode activation requires storing a flag in the user session. Using this 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 bypass at the end; otherwise you must remember to call ‘.reset_bypass_session!’
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 34 def bypass_session!(admin_id) Gitlab::SafeRequestStore[CURRENT_REQUEST_BYPASS_SESSION_ADMIN_ID_RS_KEY] = admin_id # Bypassing the session invalidates the cached value of admin_mode? # Any new calls need to be re-computed. uncache_admin_mode_state(admin_id) Gitlab::AppLogger.debug("Bypassing session in admin mode for: #{admin_id}") return unless block_given? begin yield ensure reset_bypass_session!(admin_id) end end |
.bypass_session_admin_id ⇒ Object
57 58 59 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 57 def bypass_session_admin_id Gitlab::SafeRequestStore[CURRENT_REQUEST_BYPASS_SESSION_ADMIN_ID_RS_KEY] end |
.current_admin ⇒ Object
86 87 88 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 86 def current_admin Gitlab::SafeRequestStore[CURRENT_REQUEST_ADMIN_MODE_USER_RS_KEY] end |
.optionally_run_in_admin_mode(user) ⇒ Object
Execute the given block with admin privileges if the user is an admin and admin mode is enabled. Otherwise, execute the block with regular user permissions.
92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 92 def optionally_run_in_admin_mode(user) raise NonSidekiqEnvironmentError unless Gitlab::Runtime.sidekiq? return yield unless Gitlab::CurrentSettings.admin_mode && user.can_access_admin_area? bypass_session!(user.id) do with_current_admin(user) do yield end end end |
.reset_bypass_session!(admin_id = nil) ⇒ Object
51 52 53 54 55 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 51 def reset_bypass_session!(admin_id = nil) # Restoring the session bypass invalidates the cached value of admin_mode? uncache_admin_mode_state(admin_id) Gitlab::SafeRequestStore.delete(CURRENT_REQUEST_BYPASS_SESSION_ADMIN_ID_RS_KEY) end |
.uncache_admin_mode_state(admin_id = nil) ⇒ Object
61 62 63 64 65 66 67 68 69 70 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 61 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 |
.with_current_admin(admin) ⇒ Object
Store in the current request the provided user model (only if in admin mode) and yield
74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 74 def with_current_admin(admin) return yield unless new(admin).admin_mode? 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 |
Instance Method Details
#admin_mode? ⇒ Boolean
110 111 112 113 114 115 116 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 110 def admin_mode? return false unless user Gitlab::SafeRequestStore.fetch(admin_mode_rs_key) do user.can_access_admin_area? && (privileged_runtime? || session_with_admin_mode?) end end |
#admin_mode_requested? ⇒ Boolean
118 119 120 121 122 123 124 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 118 def admin_mode_requested? return false unless user Gitlab::SafeRequestStore.fetch(admin_mode_requested_rs_key) do user.can_access_admin_area? && admin_mode_requested_in_grace_period? end end |
#current_session_data ⇒ Object
159 160 161 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 159 def current_session_data Gitlab::NamespacedSessionStore.new(SESSION_STORE_KEY, @session) end |
#disable_admin_mode! ⇒ Object
142 143 144 145 146 147 148 149 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 142 def disable_admin_mode! return unless user&.can_access_admin_area? reset_request_store_cache_entries current_session_data[ADMIN_MODE_REQUESTED_TIME_KEY] = nil current_session_data[ADMIN_MODE_START_TIME_KEY] = nil end |
#enable_admin_mode!(password: nil, skip_password_validation: false) ⇒ Object
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 126 def enable_admin_mode!(password: nil, skip_password_validation: false) return false unless user&.can_access_admin_area? return false unless skip_password_validation || user&.valid_password?(password) raise NotRequestedError unless admin_mode_requested? reset_request_store_cache_entries current_session_data[ADMIN_MODE_REQUESTED_TIME_KEY] = nil current_session_data[ADMIN_MODE_START_TIME_KEY] = Time.now audit_user_enable_admin_mode true end |
#request_admin_mode! ⇒ Object
151 152 153 154 155 156 157 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 151 def request_admin_mode! return unless user&.can_access_admin_area? reset_request_store_cache_entries current_session_data[ADMIN_MODE_REQUESTED_TIME_KEY] = Time.now end |