Created
December 3, 2012 13:30
-
-
Save elvanja/4195057 to your computer and use it in GitHub Desktop.
Gitlab grack authentication with ldap and possibly other providers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "net/ldap" | |
# assumes ldap login is present in User.username | |
# flow in general: | |
# * find user either by email or username (using provided login) | |
# * if ldap enabled and user provider is ldap, authenticate over ldap | |
# * else validate plain password | |
module Grack | |
class Auth < Rack::Auth::Basic | |
attr_accessor :user, :project | |
def valid? | |
# Authentication | |
login, password = @auth.credentials | |
self.user = User.find_by_email(login) || User.find_by_username(login) | |
return false unless authenticate_user(user, password) | |
email = user.email | |
# Set GL_USER env variable | |
ENV['GL_USER'] = email | |
# Pass Gitolite update hook | |
ENV['GL_BYPASS_UPDATE_HOOK'] = "true" | |
# Need this patch due to the rails mount | |
@env['PATH_INFO'] = @request.path | |
@env['SCRIPT_NAME'] = "" | |
# Find project by PATH_INFO from env | |
if m = /^\/([\w\.\/-]+)\.git/.match(@request.path_info).to_a | |
self.project = Project.find_with_namespace(m.last) | |
return false unless project | |
end | |
# Git upload and receive | |
if @request.get? | |
validate_get_request | |
elsif @request.post? | |
validate_post_request | |
else | |
false | |
end | |
end | |
def validate_get_request | |
true | |
end | |
def validate_post_request | |
if @request.path_info.end_with?('git-upload-pack') | |
can?(user, :push_code, project) | |
elsif @request.path_info.end_with?('git-receive-pack') | |
action = if project.protected_branch?(current_ref) | |
:push_code_to_protected_branches | |
else | |
:push_code | |
end | |
can?(user, action, project) | |
else | |
false | |
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\.-]+)/.match(input).to_a.first | |
end | |
protected | |
def abilities | |
@abilities ||= begin | |
abilities = Six.new | |
abilities << Ability | |
abilities | |
end | |
end | |
private | |
def authenticate_user(user, password) | |
return false unless user | |
if user.provider == "ldap" && Gitlab.config.ldap_enabled? | |
authenticate_user_from_ldap(user, password) | |
else | |
authenticate_user_with_plain_password(user, password) | |
end | |
end | |
def authenticate_user_with_plain_password(user, password) | |
user.valid_password?(password) | |
end | |
def authenticate_user_from_ldap(user, password) | |
gl = Gitlab.config | |
return false unless gl.ldap_enabled? | |
ldap = Net::LDAP.new( | |
host: gl.ldap['host'], | |
port: gl.ldap['port'], | |
auth: { | |
method: :simple, | |
username: gl.ldap['bind_dn'], | |
password: gl.ldap['password'] | |
} | |
) | |
ldap.bind_as( | |
:base => gl.ldap['base'], | |
:filter => Net::LDAP::Filter.eq(gl.ldap['uid'], user.username), | |
:password => password | |
) | |
end | |
end# Auth | |
end# Grack |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment