Module: Gitlab::Auth::AuthFinders

Includes:
ActionController::HttpAuthentication::Basic, ActionController::HttpAuthentication::Token, Utils::StrongMemoize
Included in:
API::APIGuard::HelperMethods, ApplicationCable::Channel, ApplicationCable::Connection, RequestAuthenticator
Defined in:
lib/gitlab/auth/auth_finders.rb

Constant Summary collapse

PRIVATE_TOKEN_HEADER =
'HTTP_PRIVATE_TOKEN'
PRIVATE_TOKEN_PARAM =
:private_token
JOB_TOKEN_HEADER =
'HTTP_JOB_TOKEN'
JOB_TOKEN_PARAM =
:job_token
DEPLOY_TOKEN_HEADER =
'HTTP_DEPLOY_TOKEN'
RUNNER_TOKEN_PARAM =
:token
RUNNER_JOB_TOKEN_PARAM =
:token
PATH_DEPENDENT_FEED_TOKEN_REGEX =
/\A#{User::FEED_TOKEN_PREFIX}(\h{64})-(\d+)\z/
PARAM_TOKEN_KEYS =
[
  PRIVATE_TOKEN_PARAM,
  JOB_TOKEN_PARAM,
  RUNNER_JOB_TOKEN_PARAM
].map(&:to_s).freeze
HEADER_TOKEN_KEYS =
[
  PRIVATE_TOKEN_HEADER,
  JOB_TOKEN_HEADER,
  DEPLOY_TOKEN_HEADER
].freeze

Instance Method Summary collapse

Instance Method Details

#authentication_token_present?Boolean

Returns:

  • (Boolean)


219
220
221
222
223
# File 'lib/gitlab/auth/auth_finders.rb', line 219

def authentication_token_present?
  PARAM_TOKEN_KEYS.intersection(current_request.params.keys).any? ||
    HEADER_TOKEN_KEYS.intersection(current_request.env.keys).any? ||
    parsed_oauth_token.present?
end

#cluster_agent_token_from_authorization_tokenObject



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/gitlab/auth/auth_finders.rb', line 163

def cluster_agent_token_from_authorization_token
  return unless route_authentication_setting[:cluster_agent_token_allowed]

  # We are migrating from the `Authorization` header to one specific to cluster
  # agents, `Gitlab-Agentk-Api-Request`. Both must be supported until KAS has
  # been updated to use the new header, and then this first lookup can be removed.
  # See https://gitlab.com/gitlab-org/gitlab/-/issues/406582.
  token, _ = if current_request.authorization.present?
               token_and_options(current_request)
             else
               current_request.headers[Gitlab::Kas::INTERNAL_API_AGENTK_REQUEST_HEADER]
             end

  return unless token.present?

  ::Clusters::AgentToken.active.find_by_token(token.to_s)
end

#deploy_token_from_requestObject

This returns a deploy token, not a user since a deploy token does not belong to a user.

deploy tokens are accepted with deploy token headers and basic auth headers



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/gitlab/auth/auth_finders.rb', line 147

def deploy_token_from_request
  return unless route_authentication_setting[:deploy_token_allowed]
  return unless Gitlab::ExternalAuthorization.allow_deploy_tokens_and_deploy_keys?

  token = current_request.env[DEPLOY_TOKEN_HEADER].presence || parsed_oauth_token

  if has_basic_credentials?(current_request)
    _, token = user_name_and_password(current_request)
  end

  deploy_token = DeployToken.active.find_by_token(token.to_s)
  @current_authenticated_deploy_token = deploy_token # rubocop:disable Gitlab/ModuleWithInstanceVariables

  deploy_token
end

#find_runner_from_tokenObject



181
182
183
184
185
186
187
188
# File 'lib/gitlab/auth/auth_finders.rb', line 181

def find_runner_from_token
  return unless api_request?

  token = current_request.params[RUNNER_TOKEN_PARAM].presence
  return unless token

  ::Ci::Runner.find_by_token(token.to_s) || raise(UnauthorizedError)
end

#find_user_from_access_tokenObject



133
134
135
136
137
138
139
140
141
# File 'lib/gitlab/auth/auth_finders.rb', line 133

def find_user_from_access_token
  return unless access_token

  validate_and_save_access_token!

  ::PersonalAccessTokens::LastUsedService.new(access_token).execute

  access_token.user || raise(UnauthorizedError)
end

#find_user_from_basic_auth_passwordObject



91
92
93
94
95
96
97
98
# File 'lib/gitlab/auth/auth_finders.rb', line 91

def find_user_from_basic_auth_password
  return unless has_basic_credentials?(current_request)

  , password = user_name_and_password(current_request)
  return if ::Gitlab::Auth::CI_JOB_USER == 

  Gitlab::Auth.find_with_user_password(.to_s, password.to_s)
end

#find_user_from_bearer_tokenObject



78
79
80
# File 'lib/gitlab/auth/auth_finders.rb', line 78

def find_user_from_bearer_token
  find_user_from_job_bearer_token || find_user_from_access_token
end

#find_user_from_feed_token(request_format) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
# File 'lib/gitlab/auth/auth_finders.rb', line 66

def find_user_from_feed_token(request_format)
  return unless valid_rss_format?(request_format)
  return if Gitlab::CurrentSettings.disable_feed_token

  # NOTE: feed_token was renamed from rss_token but both needs to be supported because
  #       users might have already added the feed to their RSS reader before the rename
  token = current_request.params[:feed_token].presence || current_request.params[:rss_token].presence
  return unless token

  find_feed_token_user(token) || raise(UnauthorizedError)
end

#find_user_from_job_tokenObject



82
83
84
85
86
87
88
89
# File 'lib/gitlab/auth/auth_finders.rb', line 82

def find_user_from_job_token
  return unless route_authentication_setting[:job_token_allowed]

  user = find_user_from_job_token_basic_auth if can_authenticate_job_token_basic_auth?
  return user if user

  find_user_from_job_token_query_params_or_header if can_authenticate_job_token_request?
end

#find_user_from_lfs_tokenObject



100
101
102
103
104
105
106
107
# File 'lib/gitlab/auth/auth_finders.rb', line 100

def find_user_from_lfs_token
  return unless has_basic_credentials?(current_request)

  , token = user_name_and_password(current_request)
  user = User.(.to_s)

  user if user && Gitlab::LfsToken.new(user, nil).token_valid?(token.to_s)
end

#find_user_from_personal_access_tokenObject



109
110
111
112
113
114
115
# File 'lib/gitlab/auth/auth_finders.rb', line 109

def find_user_from_personal_access_token
  return unless access_token

  validate_and_save_access_token!

  access_token&.user || raise(UnauthorizedError)
end

#find_user_from_static_object_token(request_format) ⇒ Object



57
58
59
60
61
62
63
64
# File 'lib/gitlab/auth/auth_finders.rb', line 57

def find_user_from_static_object_token(request_format)
  return unless valid_static_objects_format?(request_format)

  token = current_request.params[:token].presence || current_request.headers['X-Gitlab-Static-Object-Token'].presence
  return unless token

  User.find_by_static_object_token(token.to_s) || raise(UnauthorizedError)
end

#find_user_from_wardenObject

Check the Rails session for valid authentication details



53
54
55
# File 'lib/gitlab/auth/auth_finders.rb', line 53

def find_user_from_warden
  current_request.env['warden']&.authenticate if verified_request?
end

#find_user_from_web_access_token(request_format, scopes: [:api]) ⇒ Object

We allow private access tokens with ‘api` scope to be used by web requests on RSS feeds or ICS files for backwards compatibility. It is also used by GraphQL/API requests. And to allow accessing /archive programatically as it was a big pain point for users gitlab.com/gitlab-org/gitlab/-/issues/28978. Used for release downloading as well



123
124
125
126
127
128
129
130
131
# File 'lib/gitlab/auth/auth_finders.rb', line 123

def find_user_from_web_access_token(request_format, scopes: [:api])
  return unless access_token && valid_web_access_format?(request_format)

  validate_and_save_access_token!(scopes: scopes)

  ::PersonalAccessTokens::LastUsedService.new(access_token).execute

  access_token.user || raise(UnauthorizedError)
end

#validate_and_save_access_token!(scopes: [], save_auth_context: true) ⇒ Object



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/gitlab/auth/auth_finders.rb', line 190

def validate_and_save_access_token!(scopes: [], save_auth_context: true)
  # return early if we've already authenticated via a job token
  return if @current_authenticated_job.present? # rubocop:disable Gitlab/ModuleWithInstanceVariables

  # return early if we've already authenticated via a deploy token
  return if @current_authenticated_deploy_token.present? # rubocop:disable Gitlab/ModuleWithInstanceVariables

  return unless access_token

  case AccessTokenValidationService.new(access_token, request: request).validate(scopes: scopes)
  when AccessTokenValidationService::INSUFFICIENT_SCOPE
    save_auth_failure_in_application_context(access_token, :insufficient_scope, scopes) if save_auth_context
    raise InsufficientScopeError, scopes
  when AccessTokenValidationService::EXPIRED
    save_auth_failure_in_application_context(access_token, :token_expired, scopes) if save_auth_context
    raise ExpiredError
  when AccessTokenValidationService::REVOKED
    save_auth_failure_in_application_context(access_token, :token_revoked, scopes) if save_auth_context
    revoke_token_family(access_token)

    raise RevokedError
  when AccessTokenValidationService::IMPERSONATION_DISABLED
    save_auth_failure_in_application_context(access_token, :impersonation_disabled, scopes) if save_auth_context
    raise ImpersonationDisabled
  end

  save_current_token_in_env
end