summaryrefslogtreecommitdiff
path: root/lib/api/helpers/authentication.rb
blob: a6cfe930190bb7e9a08851e837b73daf68a64685 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# frozen_string_literal: true

module API
  module Helpers
    module Authentication
      extend ActiveSupport::Concern

      class_methods do
        def authenticate_with(&block)
          strategies = ::Gitlab::APIAuthentication::Builder.new.build(&block)
          namespace_inheritable :authentication, strategies
        end
      end

      included do
        helpers ::Gitlab::Utils::StrongMemoize

        helpers do
          def token_from_namespace_inheritable
            strong_memoize(:token_from_namespace_inheritable) do
              strategies = namespace_inheritable(:authentication)
              next unless strategies&.any?

              # Extract credentials from the request
              found = strategies.to_h { |location, _| [location, ::Gitlab::APIAuthentication::TokenLocator.new(location).extract(current_request)] }
              found.filter! { |location, raw| raw }
              next unless found.any?

              # Specifying multiple credentials is an error
              # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38627#note_475984136
              bad_request!('Found more than one set of credentials') if found.size > 1

              location, raw = found.first
              find_token_from_raw_credentials(strategies[location], raw)
            end

          rescue ::Gitlab::Auth::UnauthorizedError
            # TODO: this should be rescued and converted by the exception handling middleware
            # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38627#note_475174516
            unauthorized!
          end

          def access_token_from_namespace_inheritable
            token = token_from_namespace_inheritable
            token if token.is_a? PersonalAccessToken
          end

          def user_from_namespace_inheritable
            token = token_from_namespace_inheritable
            return token if token.is_a? DeployToken

            token&.user
          end

          private

          def find_token_from_raw_credentials(token_types, raw)
            token_types.each do |token_type|
              # Resolve a token from the raw credentials
              token = ::Gitlab::APIAuthentication::TokenResolver.new(token_type).resolve(raw)
              return token if token
            end

            # If a request provides credentials via an allowed transport, the
            # credentials must be valid. If we reach this point, the credentials
            # must not be valid credentials of an allowed type.
            raise ::Gitlab::Auth::UnauthorizedError
          end
        end
      end
    end
  end
end