diff options
author | Robert Speicher <rspeicher@gmail.com> | 2021-01-20 22:34:23 +0300 |
---|---|---|
committer | Robert Speicher <rspeicher@gmail.com> | 2021-01-20 22:34:23 +0300 |
commit | 6438df3a1e0fb944485cebf07976160184697d72 (patch) | |
tree | 00b09bfd170e77ae9391b1a2f5a93ef6839f2597 /lib/gitlab/api_authentication | |
parent | 42bcd54d971da7ef2854b896a7b34f4ef8601067 (diff) |
Add latest changes from gitlab-org/gitlab@13-8-stable-eev13.8.0-rc42
Diffstat (limited to 'lib/gitlab/api_authentication')
-rw-r--r-- | lib/gitlab/api_authentication/builder.rb | 18 | ||||
-rw-r--r-- | lib/gitlab/api_authentication/sent_through_builder.rb | 19 | ||||
-rw-r--r-- | lib/gitlab/api_authentication/token_locator.rb | 37 | ||||
-rw-r--r-- | lib/gitlab/api_authentication/token_resolver.rb | 87 | ||||
-rw-r--r-- | lib/gitlab/api_authentication/token_type_builder.rb | 18 |
5 files changed, 179 insertions, 0 deletions
diff --git a/lib/gitlab/api_authentication/builder.rb b/lib/gitlab/api_authentication/builder.rb new file mode 100644 index 00000000000..717c664826a --- /dev/null +++ b/lib/gitlab/api_authentication/builder.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +# Authentication Strategies Builder +# +# AuthBuilder and its child classes, TokenType and SentThrough, support +# declaring allowed authentication strategies with patterns like +# `accept.token_type(:job_token).sent_through(:http_basic)`. +module Gitlab + module APIAuthentication + class Builder + def build + strategies = Hash.new([]) + yield ::Gitlab::APIAuthentication::TokenTypeBuilder.new(strategies) + strategies + end + end + end +end diff --git a/lib/gitlab/api_authentication/sent_through_builder.rb b/lib/gitlab/api_authentication/sent_through_builder.rb new file mode 100644 index 00000000000..f66e5960019 --- /dev/null +++ b/lib/gitlab/api_authentication/sent_through_builder.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +# See Gitlab::APIAuthentication::Builder +module Gitlab + module APIAuthentication + class SentThroughBuilder + def initialize(strategies, resolvers) + @strategies = strategies + @resolvers = resolvers + end + + def sent_through(*locators) + locators.each do |locator| + @strategies[locator] |= @resolvers + end + end + end + end +end diff --git a/lib/gitlab/api_authentication/token_locator.rb b/lib/gitlab/api_authentication/token_locator.rb new file mode 100644 index 00000000000..32a98908e5b --- /dev/null +++ b/lib/gitlab/api_authentication/token_locator.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module Gitlab + module APIAuthentication + class TokenLocator + UsernameAndPassword = Struct.new(:username, :password) + + include ActiveModel::Validations + include ActionController::HttpAuthentication::Basic + + attr_reader :location + + validates :location, inclusion: { in: %i[http_basic_auth] } + + def initialize(location) + @location = location + validate! + end + + def extract(request) + case @location + when :http_basic_auth + extract_from_http_basic_auth request + end + end + + private + + def extract_from_http_basic_auth(request) + username, password = user_name_and_password(request) + return unless username.present? && password.present? + + UsernameAndPassword.new(username, password) + end + end + end +end diff --git a/lib/gitlab/api_authentication/token_resolver.rb b/lib/gitlab/api_authentication/token_resolver.rb new file mode 100644 index 00000000000..5b30777b6ec --- /dev/null +++ b/lib/gitlab/api_authentication/token_resolver.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +module Gitlab + module APIAuthentication + class TokenResolver + include ActiveModel::Validations + + attr_reader :token_type + + validates :token_type, inclusion: { in: %i[personal_access_token job_token deploy_token] } + + def initialize(token_type) + @token_type = token_type + validate! + end + + # Existing behavior is known to be inconsistent across authentication + # methods with regards to whether to silently ignore present but invalid + # credentials or to raise an error/respond with 401. + # + # If a token can be located from the provided credentials, but the token + # or credentials are in some way invalid, this implementation opts to + # raise an error. + # + # For example, if the raw credentials include a username and password, and + # a token is resolved from the password, but the username does not match + # the token, an error will be raised. + # + # See https://gitlab.com/gitlab-org/gitlab/-/issues/246569 + + def resolve(raw) + case @token_type + when :personal_access_token + resolve_personal_access_token raw + + when :job_token + resolve_job_token raw + + when :deploy_token + resolve_deploy_token raw + end + end + + private + + def resolve_personal_access_token(raw) + # Check if the password is a personal access token + pat = ::PersonalAccessToken.find_by_token(raw.password) + return unless pat + + # Ensure that the username matches the token. This check is a subtle + # departure from the existing behavior of #find_personal_access_token_from_http_basic_auth. + # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38627#note_435907856 + raise ::Gitlab::Auth::UnauthorizedError unless pat.user.username == raw.username + + pat + end + + def resolve_job_token(raw) + # Only look for a job if the username is correct + return if ::Gitlab::Auth::CI_JOB_USER != raw.username + + job = ::Ci::AuthJobFinder.new(token: raw.password).execute + + # Actively reject credentials with the username `gitlab-ci-token` if + # the password is not a valid job token. This replicates existing + # behavior of #find_user_from_job_token. + raise ::Gitlab::Auth::UnauthorizedError unless job + + job + end + + def resolve_deploy_token(raw) + # Check if the password is a deploy token + token = ::DeployToken.active.find_by_token(raw.password) + return unless token + + # Ensure that the username matches the token. This check is a subtle + # departure from the existing behavior of #deploy_token_from_request. + # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38627#note_474826205 + raise ::Gitlab::Auth::UnauthorizedError unless token.username == raw.username + + token + end + end + end +end diff --git a/lib/gitlab/api_authentication/token_type_builder.rb b/lib/gitlab/api_authentication/token_type_builder.rb new file mode 100644 index 00000000000..4a57cdc2742 --- /dev/null +++ b/lib/gitlab/api_authentication/token_type_builder.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +# See Gitlab::Auth::AuthBuilder +module Gitlab + module APIAuthentication + class TokenTypeBuilder + def initialize(strategies) + @strategies = strategies + end + + def token_types(*resolvers) + ::Gitlab::APIAuthentication::SentThroughBuilder.new(@strategies, resolvers) + end + + alias_method :token_type, :token_types + end + end +end |