Get Grack::Auth tests to pass
This commit is contained in:
parent
19a5e7c95e
commit
55f5a68f09
|
@ -10,9 +10,6 @@ class Projects::ApplicationController < ApplicationController
|
|||
|
||||
def project
|
||||
unless @project
|
||||
namespace = params[:namespace_id]
|
||||
id = params[:project_id] || params[:id]
|
||||
|
||||
# Redirect from
|
||||
# localhost/group/project.git
|
||||
# to
|
||||
|
@ -23,8 +20,7 @@ class Projects::ApplicationController < ApplicationController
|
|||
return
|
||||
end
|
||||
|
||||
project_path = "#{namespace}/#{id}"
|
||||
@project = Project.find_with_namespace(project_path)
|
||||
@project = find_project
|
||||
|
||||
if @project && can?(current_user, :read_project, @project)
|
||||
if @project.path_with_namespace != project_path
|
||||
|
@ -44,6 +40,22 @@ class Projects::ApplicationController < ApplicationController
|
|||
@project
|
||||
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
|
||||
@repository ||= project.repository
|
||||
end
|
||||
|
|
|
@ -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
|
|
@ -59,9 +59,6 @@ Rails.application.routes.draw do
|
|||
mount Sidekiq::Web, at: '/admin/sidekiq', as: :sidekiq
|
||||
end
|
||||
|
||||
# Enable Grack support
|
||||
mount Grack::AuthSpawner, at: '/', constraints: lambda { |request| /[-\/\w\.]+\.git\//.match(request.path_info) }, via: [:get, :post, :put]
|
||||
|
||||
# Help
|
||||
get 'help' => 'help#index'
|
||||
get 'help/:category/:file' => 'help#show', as: :help_page, constraints: { category: /.*/, file: /[^\/\.]+/ }
|
||||
|
@ -426,6 +423,13 @@ Rails.application.routes.draw do
|
|||
end
|
||||
|
||||
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:
|
||||
get '/new/*id', to: 'blob#new', constraints: { id: /.+/ }, as: 'new_blob'
|
||||
post '/create/*id', to: 'blob#create', constraints: { id: /.+/ }, as: 'create_blob'
|
||||
|
|
Loading…
Reference in New Issue