jwt_controller.rb 2.7 KB
Newer Older
K
Kamil Trzcinski 已提交
1 2 3
class JwtController < ApplicationController
  skip_before_action :authenticate_user!
  skip_before_action :verify_authenticity_token
K
Kamil Trzcinski 已提交
4
  before_action :authenticate_project_or_user
K
Kamil Trzcinski 已提交
5

6
  SERVICES = {
7
    Auth::ContainerRegistryAuthenticationService::AUDIENCE => Auth::ContainerRegistryAuthenticationService,
8 9
  }

K
Kamil Trzcinski 已提交
10
  def auth
11 12
    service = SERVICES[params[:service]]
    head :not_found unless service
K
Kamil Trzcinski 已提交
13

14
    result = service.new(@project, @user, auth_params).execute
K
Kamil Trzcinski 已提交
15

16
    render json: result, status: result[:http_status]
K
Kamil Trzcinski 已提交
17 18
  end

19
  private
K
Kamil Trzcinski 已提交
20

K
Kamil Trzcinski 已提交
21 22 23 24 25 26 27 28 29
  def authenticate_project_or_user
    authenticate_with_http_basic do |login, password|
      # if it's possible we first try to authenticate project with login and password
      @project = authenticate_project(login, password)
      return if @project

      @user = authenticate_user(login, password)
      return if @user

30
      render_403
K
Kamil Trzcinski 已提交
31 32 33
    end
  end

34 35
  def auth_params
    params.permit(:service, :scope, :offline_token, :account, :client_id)
K
Kamil Trzcinski 已提交
36 37
  end

38
  def authenticate_project(login, password)
K
Kamil Trzcinski 已提交
39 40
    if login == 'gitlab_ci_token'
      Project.find_by(builds_enabled: true, runners_token: password)
K
Kamil Trzcinski 已提交
41 42 43 44
    end
  end

  def authenticate_user(login, password)
K
Kamil Trzcinski 已提交
45 46 47
    # TODO: this is a copy and paste from grack_auth,
    # it should be refactored in the future

K
Kamil Trzcinski 已提交
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
    user = Gitlab::Auth.new.find(login, password)

    # If the user authenticated successfully, we reset the auth failure count
    # from Rack::Attack for that IP. A client may attempt to authenticate
    # with a username and blank password first, and only after it receives
    # a 401 error does it present a password. Resetting the count prevents
    # false positives from occurring.
    #
    # Otherwise, we let Rack::Attack know there was a failed authentication
    # attempt from this IP. This information is stored in the Rails cache
    # (Redis) and will be used by the Rack::Attack middleware to decide
    # whether to block requests from this IP.
    config = Gitlab.config.rack_attack.git_basic_auth

    if config.enabled
      if user
        # A successful login will reset the auth failure count from this IP
        Rack::Attack::Allow2Ban.reset(request.ip, config)
      else
        banned = Rack::Attack::Allow2Ban.filter(request.ip, config) do
          # Unless the IP is whitelisted, return true so that Allow2Ban
          # increments the counter (stored in Rails.cache) for the IP
          if config.ip_whitelist.include?(request.ip)
            false
          else
            true
          end
        end

        if banned
          Rails.logger.info "IP #{request.ip} failed to login " \
              "as #{login} but has been temporarily banned from Git auth"
K
Kamil Trzcinski 已提交
80
          return
K
Kamil Trzcinski 已提交
81 82 83 84 85 86 87
        end
      end
    end

    user
  end
end