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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Vosmaer <contact@jacobvosmaer.nl>2016-03-23 20:34:16 +0300
committerJacob Vosmaer <contact@jacobvosmaer.nl>2016-03-23 20:34:16 +0300
commit55f5a68f092cc64ae4782c0d7fbbf1d3d1ce6284 (patch)
tree0ef4d194ccc156720b168c9852e87a7591355f31 /app/controllers/projects/git_http_controller.rb
parent19a5e7c95e91baca58836ad3ae189190c9ba4ca2 (diff)
Get Grack::Auth tests to pass
Diffstat (limited to 'app/controllers/projects/git_http_controller.rb')
-rw-r--r--app/controllers/projects/git_http_controller.rb167
1 files changed, 167 insertions, 0 deletions
diff --git a/app/controllers/projects/git_http_controller.rb b/app/controllers/projects/git_http_controller.rb
new file mode 100644
index 00000000000..129e87dbf13
--- /dev/null
+++ b/app/controllers/projects/git_http_controller.rb
@@ -0,0 +1,167 @@
+class Projects::GitHttpController < Projects::ApplicationController
+ skip_before_action :repository
+ before_action :authenticate_user
+ before_action :project_found?
+
+ def git_rpc
+ if upload_pack? && upload_pack_allowed?
+ render_ok and return
+ end
+
+ render_not_found
+ end
+
+ %i{info_refs git_receive_pack git_upload_pack}.each do |method|
+ alias_method method, :git_rpc
+ end
+
+ private
+
+ def authenticate_user
+ return if project && project.public? && upload_pack?
+
+ authenticate_or_request_with_http_basic do |login, password|
+ return @ci = true if ci_request?(login, password)
+
+ @user = Gitlab::Auth.new.find(login, password)
+ @user ||= oauth_access_token_check(login, password)
+ rate_limit_ip!(login, @user)
+ end
+ end
+
+ def project_found?
+ render_not_found if project.nil?
+ end
+
+ def ci_request?(login, password)
+ matched_login = /(?<s>^[a-zA-Z]*-ci)-token$/.match(login)
+
+ if project && matched_login.present? && upload_pack?
+ underscored_service = matched_login['s'].underscore
+
+ if underscored_service == 'gitlab_ci'
+ return project && project.valid_build_token?(password)
+ elsif Service.available_services_names.include?(underscored_service)
+ service_method = "#{underscored_service}_service"
+ service = project.send(service_method)
+
+ return service && service.activated? && service.valid_token?(password)
+ end
+ end
+
+ false
+ end
+
+ def oauth_access_token_check(login, password)
+ if login == "oauth2" && upload_pack? && password.present?
+ token = Doorkeeper::AccessToken.by_token(password)
+ token && token.accessible? && User.find_by(id: token.resource_owner_id)
+ end
+ end
+
+ def rate_limit_ip!(login, user)
+ # 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
+ return user unless 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"
+ end
+ end
+
+ user
+ end
+
+ def project
+ return @project if defined?(@project)
+ @project = find_project
+ end
+
+ def id
+ id = params[:project_id]
+ return if id.nil?
+
+ if id.end_with?('.wiki.git')
+ id.slice(0, id.length - 9)
+ elsif id.end_with?('.git')
+ id.slice(0, id.length - 4)
+ end
+ end
+
+ def repo_path
+ @repo_path ||= begin
+ if params[:project_id].end_with?('.wiki.git')
+ project.wiki.wiki.path
+ else
+ repository.path_to_repo
+ end
+ end
+ end
+
+ def upload_pack?
+ if action_name == 'info_refs'
+ params[:service] == 'git-upload-pack'
+ else
+ action_name == 'git_upload_pack'
+ end
+ end
+
+ def render_ok
+ render json: {
+ 'GL_ID' => Gitlab::ShellEnv.gl_id(@user),
+ 'RepoPath' => repo_path,
+ }
+ end
+
+ def render_not_found
+ render text: 'Not Found', status: :not_found
+ end
+
+ def ci?
+ !!@ci
+ end
+
+ def user
+ @user
+ end
+
+ def upload_pack_allowed?
+ if !Gitlab.config.gitlab_shell.upload_pack
+ false
+ elsif ci?
+ true
+ elsif user
+ Gitlab::GitAccess.new(user, project).download_access_check.allowed?
+ elsif project.public?
+ # Allow clone/fetch for public projects
+ true
+ else
+ false
+ end
+ end
+end