Created
December 3, 2012 13:36
-
-
Save elvanja/4195080 to your computer and use it in GitHub Desktop.
Gitlab grack authentication with ldap when username is not in schema
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" | |
=begin | |
fix for older versions, without username in User model | |
flow in general: | |
* authenticate user with ldap | |
return user's email if authenticated, otherwise nil | |
* if email retrieved | |
(ldap authenticated the user) | |
- find user in Gitlab database by that email | |
- if user found, skip password validation because user is already authenticated with ldap | |
* else | |
(ldap didn't authenticate the user) | |
- find user in Gitlab database by email (from login data) | |
- if user found, validate plain password | |
=end | |
module Grack | |
class Auth < Rack::Auth::Basic | |
attr_accessor :user, :project | |
def valid? | |
# Authentication | |
login, password = @auth.credentials | |
ldap_email = authenticate_user_and_get_email_from_ldap(login, password) | |
self.user = User.find_by_email(ldap_email || login) | |
return false unless user && (ldap_email || user.valid_password?(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_and_get_email_from_ldap(login, password) | |
gl = Gitlab.config | |
return nil 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'] | |
} | |
) | |
result = ldap.bind_as( | |
:base => gl.ldap['base'], | |
:filter => Net::LDAP::Filter.eq(gl.ldap['uid'], login), | |
:password => password | |
) | |
result.first.mail if result | |
end | |
end# Auth | |
end# Grack |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment