require_relative 'shell_env' require_relative 'grack_ldap' require_relative 'grack_helpers' module Grack class Auth < Rack::Auth::Basic include LDAP include Helpers attr_accessor :user, :project, :ref, :env def call(env) @env = env @request = Rack::Request.new(env) @auth = Request.new(env) # Need this patch due to the rails mount @env['PATH_INFO'] = @request.path @env['SCRIPT_NAME'] = "" auth! end private def auth! return render_not_found unless project if @auth.provided? return bad_request unless @auth.basic? # Authentication with username and password login, password = @auth.credentials @user = authenticate_user(login, password) if @user Gitlab::ShellEnv.set_env(@user) @env['REMOTE_USER'] = @auth.username else return unauthorized end else return unauthorized unless project.public end if authorized_git_request? @app.call(env) else unauthorized end end def authorized_git_request? # Git upload and receive if @request.get? authorize_request(@request.params['service']) elsif @request.post? authorize_request(File.basename(@request.path)) else false end end def authenticate_user(login, password) user = User.find_by_email(login) || User.find_by_username(login) # If the provided login was not a known email or username # then user is nil if user.nil? || user.ldap_user? # Second chance - try LDAP authentication return nil unless ldap_conf.enabled auth = Gitlab::Auth.new auth.ldap_auth(login, password) else return user if user.valid_password?(password) end end def authorize_request(service) case service when 'git-upload-pack' project.public || can?(user, :download_code, project) when'git-receive-pack' action = if project.protected_branch?(ref) :push_code_to_protected_branches else :push_code end can?(user, action, project) else false end end def project @project ||= project_by_path(@request.path_info) end def ref @ref ||= parse_ref end def parse_ref input = if @env["HTTP_CONTENT_ENCODING"] =~ /gzip/ Zlib::GzipReader.new(@request.body).read else @request.body.read end # Need to reset seek point @request.body.rewind /refs\/heads\/([\w\.-]+)/n.match(input.force_encoding('ascii-8bit')).to_a.last end end end