Welcome to mirror list, hosted at ThFree Co, Russian Federation.

token_resolver.rb « api_authentication « gitlab « lib - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 9234837cdf72863be87fd4e6b414dd275518351b (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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# 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_with_username
          job_token_with_username
          deploy_token_with_username
          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

        when :personal_access_token_with_username
          resolve_personal_access_token_with_username raw

        when :job_token_with_username
          resolve_job_token_with_username raw

        when :deploy_token_with_username
          resolve_deploy_token_with_username raw
        end
      end

      private

      def resolve_personal_access_token_with_username(raw)
        raise ::Gitlab::Auth::UnauthorizedError unless raw.username

        with_personal_access_token(raw) do |pat|
          break 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
      end

      def resolve_job_token_with_username(raw)
        # Only look for a job if the username is correct
        return if ::Gitlab::Auth::CI_JOB_USER != raw.username

        with_job_token(raw) do |job|
          job
        end
      end

      def resolve_deploy_token_with_username(raw)
        with_deploy_token(raw) do |token|
          break 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

      def resolve_personal_access_token(raw)
        with_personal_access_token(raw) do |pat|
          pat
        end
      end

      def resolve_job_token(raw)
        with_job_token(raw) do |job|
          job
        end
      end

      def resolve_deploy_token(raw)
        with_deploy_token(raw) do |token|
          token
        end
      end

      def with_personal_access_token(raw, &block)
        pat = ::PersonalAccessToken.find_by_token(raw.password)
        return unless pat

        yield(pat)
      end

      def with_deploy_token(raw, &block)
        token = ::DeployToken.active.find_by_token(raw.password)
        return unless token

        yield(token)
      end

      def with_job_token(raw, &block)
        job = ::Ci::AuthJobFinder.new(token: raw.password).execute
        raise ::Gitlab::Auth::UnauthorizedError unless job

        yield(job)
      end
    end
  end
end