前阵子搭了个Gitlab server玩,给其他人共享的时候想直接用公司LDAP进行验证登录。然后问题就来了:Gitlab需要提供一个LDAP的superuser,每次登录靠superuser使用filter查询进行验证。我没有superuser怎么办?
所以“自己动手,丰衣足食“。
说明放在 Github上,有兴趣可以尝试。
首先是gitlab的调试,为了简单,这里直接使用了Gitlab官方的docker镜像。docker run gitlab
就能有Gitlab了。下面就是动手术改造LDAP模块,先docker exec -it gitlab-container-id /bin/bash
进入Gitlab容器里再说。
刚开始按照官方网站配置LDAP,把东西配置好了,然后enable,接着gitlab-ctl reconfigure
,刷新页面,兴高采烈地看见了登录界面有了LDAP tab。输入用户名和密码,神奇的事情就是一直500错误。
开始搜索如何debug Gitlab,Stackoverflow一下,第一次无果,但是找到如何将log从info级设置为debug级。vi $(find /opt/gitlab/embedded/service/gitlab-rails -name production.rb)
。当gitlab-ctl restart
后,LDAP登录500的错误竟然消失了,Gitlab这里肯定还有bug,忽略。
用了一会gitlab-ctl
,help一下发现了gitlab-ctl tail
可以检测log改变。好办了,开两个bash,一个tail专用,一个改代码。500错误没有了之后,就一直报Invalid credentials
的错误。grep一下在哪:gems/gitlab_omniauth-ldap-1.2.1/lib/omniauth/strategies/ldap.rb
。发现了Gitlab比较诡异的地方,每次LDAP登录,它要先用配置里的用户去查询登录的用户信息然后bind去验证,有点复杂…
@ldap_user_info = @adaptor.bind_as(:filter => filter(@adaptor), :size => 1, :password => request[‘password’])
顺藤摸瓜,@adaptor.bind_as
,嗯,至少有了函数名,grep后发现gems/gitlab_omniauth-ldap-1.2.1/lib/omniauth-ldap/adaptor.rb
。刚开始还以为ruby-net-ldap库的版本太低,于是export GEM_HOME
并修改Gemfile.lock
,install了一个0.15.0替换原来的0.12.1,然并卵。那只能把bind_as
干掉重新写一个了:
def bind_as(args={})
result = {}
result[:uid] = ["#{args[:username]}"]
result[:email] = ["#{args[:username]}@example.com"]
login = "#{args[:username]}@example.com"
password = args[:password]
config = {
:host => @host,
:port => @port,
:encryption => method,
:base => @base
:auth => {}
}
config[:auth][:method] = @bind_method
config[:auth][:username] = login
config[:auth][:password] = password
@connection = Net::LDAP.new(config)
false
result if @connection.bind
end
重启Gitlab,LDAP登录——错误:nil没有provider。没有任何头绪。偶然在tail的log里发现了email is invalid,grep!找到了gitlab-rails/lib/gitlab/o_auth/user.rb
。上面的代码最初result[:email] = ["#{args[:username]}@example.com"]
不是数组,log.info
输出了每次的email发现都是username的第一个字符。改好以后还是不能登录,user在save的时候一直错。gitlab-rails/lib/gitlab/ldap/user.rb
里发现继承了o_auth的类,gl_user
获取的时候有find_by_uid_and_provider
,之后就是find_by_email
,那就把find_by_uid_and_provider
删除吧。
万分欢喜,终于pass了登录的所有步骤。我是先注册了一个非LDAP用户,但是用户名和邮箱都是用的自己的,那么find_by_email
就应该会找到这个注册的用户。果然如我所料,登录用户名密码输入正确,还是没有登录,显示用户已经被block,难道我的LDAP已经被公司封了,我没有写js脚本 T_T。
用root用户登录,发现注册的账户已经被block,是LDAP那边的信息,但我还能照常使用公司其他app。就是Gitlab有check咯。grep block,发现了主要的文件gitlab-rails/lib/gitlab/ldap/access.rb
,把里面的allowed判断直接return true
就好了。要是有兴趣的童鞋,可以再写点代码,连接一下LDAP server,用search方法去搜索好像是叫ee的key的value,然后返回true或false。这里就简单粗暴了。
重启,登录,完成!以为可以喝杯茶了,git clone
后git push
又挂了。从错误信息grep找到流程:gitlab-rails/app/controllers/projects/git_http_controller.rb
=> gitlab-rails/lib/gitlab/auth.rb
=> gitlab-rails/lib/gitlab/ldap/authentication.rb
。发现了filter的残党,改为username直接传。find_by_uid_and_provider
也改为find_by_email
。重启,登录,创建项目,clone,push。
Gitlab 至此手术结束。