You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							120 lines
						
					
					
						
							2.7 KiB
						
					
					
				
			
		
		
	
	
							120 lines
						
					
					
						
							2.7 KiB
						
					
					
				| 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
 |