Module: Gitlab::Auth::AuthFinders

Includes:
ActionController::HttpAuthentication::Basic, ActionController::HttpAuthentication::Token, Utils::StrongMemoize
Included in:
API::APIGuard::HelperMethods, 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

Instance Method Summary collapse

Methods included from Utils::StrongMemoize

#clear_memoization, #strong_memoize, #strong_memoized?

Instance Method Details

#cluster_agent_token_from_authorization_tokenObject


163
164
165
166
167
168
169
170
# 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]
  return unless current_request.authorization.present?

  authorization_token, _options = token_and_options(current_request)

  ::Clusters::AgentToken.active.find_by_token(authorization_token)
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


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

def deploy_token_from_request
  return unless route_authentication_setting[:deploy_token_allowed]

  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)
  @current_authenticated_deploy_token = deploy_token # rubocop:disable Gitlab/ModuleWithInstanceVariables

  deploy_token
end

#find_runner_from_tokenObject


172
173
174
175
176
177
178
179
# File 'lib/gitlab/auth/auth_finders.rb', line 172

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) || raise(UnauthorizedError)
end

#find_user_from_access_tokenObject


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

def find_user_from_access_token
  return unless access_token

  validate_access_token!

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

  access_token.user || raise(UnauthorizedError)
end

#find_user_from_basic_auth_jobObject


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

def find_user_from_basic_auth_job
  return unless has_basic_credentials?(current_request)

  , password = user_name_and_password(current_request)
  return unless .present? && password.present?
  return unless ::Gitlab::Auth::CI_JOB_USER == 

  job = find_valid_running_job_by_token!(password)
  @current_authenticated_job = job # rubocop:disable Gitlab/ModuleWithInstanceVariables

  job.user
end

#find_user_from_basic_auth_passwordObject


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

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(, password)
end

#find_user_from_bearer_tokenObject


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

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


48
49
50
51
52
53
54
55
56
57
58
# File 'lib/gitlab/auth/auth_finders.rb', line 48

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

  User.find_by_feed_token(token) || raise(UnauthorizedError)
end

#find_user_from_job_tokenObject


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

def find_user_from_job_token
  return unless route_authentication_setting[:job_token_allowed]
  return find_user_from_basic_auth_job if route_authentication_setting[:job_token_allowed] == :basic_auth

  token = current_request.params[JOB_TOKEN_PARAM].presence ||
    current_request.params[RUNNER_JOB_TOKEN_PARAM].presence ||
    current_request.env[JOB_TOKEN_HEADER].presence
  return unless token

  job = find_valid_running_job_by_token!(token)
  @current_authenticated_job = job # rubocop:disable Gitlab/ModuleWithInstanceVariables

  job.user
end

#find_user_from_lfs_tokenObject


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

def find_user_from_lfs_token
  return unless has_basic_credentials?(current_request)

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

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

#find_user_from_personal_access_tokenObject


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

def find_user_from_personal_access_token
  return unless access_token

  validate_access_token!

  access_token&.user || raise(UnauthorizedError)
end

#find_user_from_static_object_token(request_format) ⇒ Object


39
40
41
42
43
44
45
46
# File 'lib/gitlab/auth/auth_finders.rb', line 39

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) || raise(UnauthorizedError)
end

#find_user_from_wardenObject

Check the Rails session for valid authentication details


35
36
37
# File 'lib/gitlab/auth/auth_finders.rb', line 35

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.


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

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

  validate_access_token!(scopes: scopes)

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

  access_token.user || raise(UnauthorizedError)
end

#validate_access_token!(scopes: []) ⇒ Object


181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/gitlab/auth/auth_finders.rb', line 181

def validate_access_token!(scopes: [])
  # 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
    raise InsufficientScopeError, scopes
  when AccessTokenValidationService::EXPIRED
    raise ExpiredError
  when AccessTokenValidationService::REVOKED
    raise RevokedError
  when AccessTokenValidationService::IMPERSONATION_DISABLED
    raise ImpersonationDisabled
  end
end