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.
104 105 106 107 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 104 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!’
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 33 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
56 57 58 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 56 def bypass_session_admin_id Gitlab::SafeRequestStore[CURRENT_REQUEST_BYPASS_SESSION_ADMIN_ID_RS_KEY] end |
.current_admin ⇒ Object
85 86 87 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 85 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.
91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 91 def optionally_run_in_admin_mode(user) raise NonSidekiqEnvironmentError unless Gitlab::Runtime.sidekiq? return yield unless Gitlab::CurrentSettings.admin_mode && user.admin? bypass_session!(user.id) do with_current_admin(user) do yield end end end |
.reset_bypass_session!(admin_id = nil) ⇒ Object
50 51 52 53 54 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 50 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
60 61 62 63 64 65 66 67 68 69 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 60 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
73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 73 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
109 110 111 112 113 114 115 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 109 def admin_mode? return false unless user Gitlab::SafeRequestStore.fetch(admin_mode_rs_key) do user.admin? && (privileged_runtime? || session_with_admin_mode?) end end |
#admin_mode_requested? ⇒ Boolean
117 118 119 120 121 122 123 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 117 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? end end |
#current_session_data ⇒ Object
158 159 160 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 158 def current_session_data Gitlab::NamespacedSessionStore.new(SESSION_STORE_KEY, @session) end |
#disable_admin_mode! ⇒ Object
141 142 143 144 145 146 147 148 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 141 def disable_admin_mode! return unless user&.admin? 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
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 125 def enable_admin_mode!(password: nil, skip_password_validation: false) return false unless user&.admin? 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
150 151 152 153 154 155 156 |
# File 'lib/gitlab/auth/current_user_mode.rb', line 150 def request_admin_mode! return unless user&.admin? reset_request_store_cache_entries current_session_data[ADMIN_MODE_REQUESTED_TIME_KEY] = Time.now end |