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

git_http_client_controller.rb « repositories « controllers « app - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: c002c9b83f9c7f5f1283f71cfaf1f85b6cc9110a (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
142
# frozen_string_literal: true

module Repositories
  class GitHttpClientController < Repositories::ApplicationController
    include ActionController::HttpAuthentication::Basic
    include KerberosSpnegoHelper
    include Gitlab::Utils::StrongMemoize

    attr_reader :authentication_result, :redirected_path

    delegate :authentication_abilities, to: :authentication_result, allow_nil: true
    delegate :type, to: :authentication_result, allow_nil: true, prefix: :auth_result

    # Git clients will not know what authenticity token to send along
    skip_around_action :set_session_storage
    skip_before_action :verify_authenticity_token

    prepend_before_action :authenticate_user, :parse_repo_path

    feature_category :source_code_management

    def authenticated_user
      authentication_result&.user || authentication_result&.deploy_token
    end

    private

    def user
      authenticated_user
    end

    def download_request?
      raise NotImplementedError
    end

    def upload_request?
      raise NotImplementedError
    end

    def authenticate_user
      @authentication_result = Gitlab::Auth::Result::EMPTY

      if allow_basic_auth? && basic_auth_provided?
        login, password = user_name_and_password(request)

        if handle_basic_authentication(login, password)
          return # Allow access
        end
      elsif allow_kerberos_spnego_auth? && spnego_provided?
        kerberos_user = find_kerberos_user

        if kerberos_user
          @authentication_result = Gitlab::Auth::Result.new(
            kerberos_user, nil, :kerberos, Gitlab::Auth.full_authentication_abilities)

          send_final_spnego_response
          return # Allow access
        end
      elsif http_download_allowed?

        @authentication_result = Gitlab::Auth::Result.new(nil, project, :none, [:download_code])

        return # Allow access
      end

      send_challenges
      render plain: "HTTP Basic: Access denied\n", status: :unauthorized
    rescue Gitlab::Auth::MissingPersonalAccessTokenError
      render_missing_personal_access_token
    end

    def basic_auth_provided?
      has_basic_credentials?(request)
    end

    def send_challenges
      challenges = []
      challenges << 'Basic realm="GitLab"' if allow_basic_auth?
      challenges << spnego_challenge if allow_kerberos_spnego_auth?
      headers['Www-Authenticate'] = challenges.join("\n") if challenges.any?
    end

    def container
      parse_repo_path unless defined?(@container)

      @container
    end

    def project
      parse_repo_path unless defined?(@project)

      @project
    end

    def repository_path
      @repository_path ||= params[:repository_path]
    end

    def parse_repo_path
      @container, @project, @repo_type, @redirected_path = Gitlab::RepoPath.parse(repository_path)
    end

    def render_missing_personal_access_token
      render plain: "HTTP Basic: Access denied\n" \
                    "You must use a personal access token with 'read_repository' or 'write_repository' scope for Git over HTTP.\n" \
                    "You can generate one at #{profile_personal_access_tokens_url}",
            status: :unauthorized
    end

    def repository
      strong_memoize(:repository) do
        repo_type.repository_for(container)
      end
    end

    def repo_type
      parse_repo_path unless defined?(@repo_type)

      @repo_type
    end

    def handle_basic_authentication(login, password)
      @authentication_result = Gitlab::Auth.find_for_git_client(
        login, password, project: project, ip: request.ip)

      @authentication_result.success?
    end

    def ci?
      authentication_result.ci?(project)
    end

    def http_download_allowed?
      Gitlab::ProtocolAccess.allowed?('http') &&
      download_request? &&
      container &&
      Guest.can?(repo_type.guest_read_ability, container)
    end
  end
end

Repositories::GitHttpClientController.prepend_mod_with('Repositories::GitHttpClientController')