Skip to content
Snippets Groups Projects
Commit b4e8fea2 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets
Browse files

Refactor grack auth module. Add git over http wiki support

parent a8bcb9a5
No related branches found
No related tags found
No related merge requests found
require_relative 'shell_env'
require 'omniauth-ldap'
require_relative 'grack_ldap'
require_relative 'grack_helpers'
 
module Grack
class Auth < Rack::Auth::Basic
attr_accessor :user, :project
include LDAP
include Helpers
attr_accessor :user, :project, :ref, :env
 
def call(env)
@env = env
Loading
Loading
@@ -14,42 +18,52 @@ module Grack
@env['PATH_INFO'] = @request.path
@env['SCRIPT_NAME'] = ""
 
return render_not_found unless project
return unauthorized unless project.public || @auth.provided?
return bad_request if @auth.provided? && !@auth.basic?
if valid?
if @auth.provided?
@env['REMOTE_USER'] = @auth.username
end
return @app.call(env)
else
unauthorized
end
auth!
end
 
def valid?
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(login, password)
return false unless @user
@user = authenticate_user(login, password)
 
Gitlab::ShellEnv.set_env(@user)
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?
validate_get_request
authorize_request(@request.params['service'])
elsif @request.post?
validate_post_request
authorize_request(File.basename(@request.path))
else
false
end
end
 
def authenticate(login, password)
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
Loading
Loading
@@ -65,34 +79,12 @@ module Grack
end
end
 
def ldap_auth(login, password)
# Check user against LDAP backend if user is not authenticated
# Only check with valid login and password to prevent anonymous bind results
return nil unless ldap_conf.enabled && !login.blank? && !password.blank?
ldap = OmniAuth::LDAP::Adaptor.new(ldap_conf)
ldap_user = ldap.bind_as(
filter: Net::LDAP::Filter.eq(ldap.uid, login),
size: 1,
password: password
)
User.find_by_extern_uid_and_provider(ldap_user.dn, 'ldap') if ldap_user
end
def validate_get_request
validate_request(@request.params['service'])
end
def validate_post_request
validate_request(File.basename(@request.path))
end
def validate_request(service)
if service == 'git-upload-pack'
def authorize_request(service)
case service
when 'git-upload-pack'
project.public || can?(user, :download_code, project)
elsif service == 'git-receive-pack'
action = if project.protected_branch?(current_ref)
when'git-receive-pack'
action = if project.protected_branch?(ref)
:push_code_to_protected_branches
else
:push_code
Loading
Loading
@@ -104,49 +96,24 @@ module Grack
end
end
 
def can?(object, action, subject)
abilities.allowed?(object, action, subject)
end
def current_ref
if @env["HTTP_CONTENT_ENCODING"] =~ /gzip/
input = Zlib::GzipReader.new(@request.body).read
else
input = @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
def project
unless instance_variable_defined? :@project
# Find project by PATH_INFO from env
if m = /^\/([\w\.\/-]+)\.git/.match(@request.path_info).to_a
@project = Project.find_with_namespace(m.last)
end
end
return @project
@project ||= project_by_path(@request.path_info)
end
 
PLAIN_TYPE = {"Content-Type" => "text/plain"}
def render_not_found
[404, PLAIN_TYPE, ["Not Found"]]
def ref
@ref ||= parse_ref
end
 
protected
def parse_ref
input = if @env["HTTP_CONTENT_ENCODING"] =~ /gzip/
Zlib::GzipReader.new(@request.body).read
else
@request.body.read
end
 
def abilities
@abilities ||= begin
abilities = Six.new
abilities << Ability
abilities
end
end
def ldap_conf
@ldap_conf ||= Gitlab.config.ldap
# Need to reset seek point
@request.body.rewind
/refs\/heads\/([\w\.-]+)/n.match(input.force_encoding('ascii-8bit')).to_a.last
end
end# Auth
end# Grack
end
end
module Grack
module Helpers
def project_by_path(path)
if m = /^\/([\w\.\/-]+)\.git/.match(path).to_a
path_with_namespace = m.last
path_with_namespace.gsub!(/.wiki$/, '')
Project.find_with_namespace(path_with_namespace)
end
end
def render_not_found
[404, {"Content-Type" => "text/plain"}, ["Not Found"]]
end
def can?(object, action, subject)
abilities.allowed?(object, action, subject)
end
def abilities
@abilities ||= begin
abilities = Six.new
abilities << Ability
abilities
end
end
end
end
require 'omniauth-ldap'
module Grack
module LDAP
def ldap_auth(login, password)
# Check user against LDAP backend if user is not authenticated
# Only check with valid login and password to prevent anonymous bind results
return nil unless ldap_conf.enabled && !login.blank? && !password.blank?
ldap = OmniAuth::LDAP::Adaptor.new(ldap_conf)
ldap_user = ldap.bind_as(
filter: Net::LDAP::Filter.eq(ldap.uid, login),
size: 1,
password: password
)
User.find_by_extern_uid_and_provider(ldap_user.dn, 'ldap') if ldap_user
end
def ldap_conf
@ldap_conf ||= Gitlab.config.ldap
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment