Get Grack::Auth tests to pass

This commit is contained in:
Jacob Vosmaer 2016-03-23 18:34:16 +01:00
parent 19a5e7c95e
commit 55f5a68f09
3 changed files with 191 additions and 8 deletions

View file

@ -10,9 +10,6 @@ class Projects::ApplicationController < ApplicationController
def project def project
unless @project unless @project
namespace = params[:namespace_id]
id = params[:project_id] || params[:id]
# Redirect from # Redirect from
# localhost/group/project.git # localhost/group/project.git
# to # to
@ -23,8 +20,7 @@ class Projects::ApplicationController < ApplicationController
return return
end end
project_path = "#{namespace}/#{id}" @project = find_project
@project = Project.find_with_namespace(project_path)
if @project && can?(current_user, :read_project, @project) if @project && can?(current_user, :read_project, @project)
if @project.path_with_namespace != project_path if @project.path_with_namespace != project_path
@ -44,6 +40,22 @@ class Projects::ApplicationController < ApplicationController
@project @project
end end
def id
params[:project_id] || params[:id]
end
def namespace
params[:namespace_id]
end
def project_path
"#{namespace}/#{id}"
end
def find_project
Project.find_with_namespace(project_path)
end
def repository def repository
@repository ||= project.repository @repository ||= project.repository
end end

View file

@ -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

View file

@ -59,9 +59,6 @@ Rails.application.routes.draw do
mount Sidekiq::Web, at: '/admin/sidekiq', as: :sidekiq mount Sidekiq::Web, at: '/admin/sidekiq', as: :sidekiq
end end
# Enable Grack support
mount Grack::AuthSpawner, at: '/', constraints: lambda { |request| /[-\/\w\.]+\.git\//.match(request.path_info) }, via: [:get, :post, :put]
# Help # Help
get 'help' => 'help#index' get 'help' => 'help#index'
get 'help/:category/:file' => 'help#show', as: :help_page, constraints: { category: /.*/, file: /[^\/\.]+/ } get 'help/:category/:file' => 'help#show', as: :help_page, constraints: { category: /.*/, file: /[^\/\.]+/ }
@ -426,6 +423,13 @@ Rails.application.routes.draw do
end end
scope module: :projects do scope module: :projects do
# Git HTTP clients ('git clone' etc.)
scope constraints: { format: /(git|wiki\.git)/ } do
get '/info/refs', to: 'git_http#info_refs', only: :get
get '/git-upload-pack', to: 'git_http#git_upload_pack', only: :post
get '/git-receive-pack', to: 'git_http#git_receive_pack', only: :post
end
# Blob routes: # Blob routes:
get '/new/*id', to: 'blob#new', constraints: { id: /.+/ }, as: 'new_blob' get '/new/*id', to: 'blob#new', constraints: { id: /.+/ }, as: 'new_blob'
post '/create/*id', to: 'blob#create', constraints: { id: /.+/ }, as: 'create_blob' post '/create/*id', to: 'blob#create', constraints: { id: /.+/ }, as: 'create_blob'