Get Grack::Auth tests to pass
This commit is contained in:
parent
19a5e7c95e
commit
55f5a68f09
3 changed files with 191 additions and 8 deletions
|
@ -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
|
||||||
|
|
167
app/controllers/projects/git_http_controller.rb
Normal file
167
app/controllers/projects/git_http_controller.rb
Normal 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
|
|
@ -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'
|
||||||
|
|
Loading…
Reference in a new issue