项目的结构是这样的:
客户端通过Apache来访问后端的gitlab(gitlab的版本是10.4,手动从源码安装的简体中文版) , Apache作为gitlab的反向代理服务器
Apache内置了CAS的客户端,未登录的用户会重定向到CAS去登录,登录之后,跳转到gitlab,带上一个名为 remote_user的http header 来标识用户的身份
gitlab需要接收这个header,并让用户登录,若系统中不存在该用户,gitlab要从ldap中拿到用户的信息,创建用户,然后让用户登录
实现的方法:
gitlab没有现成的配置来实现这个需求, omniauth-http-header等方案,原理上是可行的,但是在实际操作过程中,很难集成到gitlab中去(因为要修改Gemfile)
所以,我在做的过程中,采用了如下的方法: 参考 omniauth-http-header的代码,自己实现一个 omniauth的provider,添加到gitlab中去(不使用gem包的方式)
首先,在/home/git/gitlab/lib文件夹下,新建http_header.rb,并修改文件的归属为git用户,内容如下:
require 'omniauth'
module OmniAuth
module Strategies
class HttpHeader
include OmniAuth::Strategy
option :name, 'http_header'
option :authorization_uri, nil
option :uid_header, 'remote_user'
option :info_headers, {}
option :remote_ip, nil
def request_phase
redirect callback_url
end
def callback_phase
if options.remote_ip && !Array(options.remote_ip).include?(request.ip)
raise ::OmniAuth::Error, "Callback from unauthorized IP #{request.ip}"
end
super
end
uid do
fetch_header options.uid_header
end
info do
options.info_headers.each_with_object({}) do |(attribute, header), info|
info[attribute] = fetch_header header
end
end
private
def fetch_header(header)
print request.env
request.env.fetch "HTTP_#{header.upcase.gsub('-', '_')}"
end
end
end
end
在omniauth的初始化文件(/home/git/gitlab/config/initializers/omniauth.rb)里require和加载这个文件:
增加了首行的require
require '/home/git/gitlab/lib/http_header.rb'
和最后的
Rails.application.config.middleware.use OmniAuth::Builder do
provider :http_header,
uid_header: 'remote_user'
end
整个文件如下:
require '/home/git/gitlab/lib/http_header.rb'
if Gitlab::LDAP::Config.enabled?
module OmniAuth::Strategies
Gitlab::LDAP::Config.available_servers.each do |server|
# do not redeclare LDAP
next if server['provider_name'] == 'ldap'
const_set(server['provider_class'], Class.new(LDAP))
end
end
end
OmniAuth.config.full_host = Settings.gitlab['base_url']
OmniAuth.config.allowed_request_methods = [:post]
# In case of auto sign-in, the GET method is used (users don't get to click on a button)
OmniAuth.config.allowed_request_methods << :get if Gitlab.config.omniauth.auto_sign_in_with_provider.present?
OmniAuth.config.before_request_phase do |env|
Gitlab::RequestForgeryProtection.call(env)
end
if Gitlab.config.omniauth.enabled
provider_names = Gitlab.config.omniauth.providers.map(&:name)
require 'omniauth-kerberos' if provider_names.include?('kerberos')
end
module OmniAuth
module Strategies
autoload :Bitbucket, Rails.root.join('lib', 'omni_auth', 'strategies', 'bitbucket')
end
end
Rails.application.config.middleware.use OmniAuth::Builder do
provider :http_header,
uid_header: 'remote_user'
end
3.在gitlab.yml文件里配置ldap和omniauth的provider,没有的信息从ldap中拿到
相关配置如下(ldap配置和主题无关,被省略了):
omniauth:
enabled: true
auto_sign_in_with_provider: http_header
auto_link_ldap_user: true
providers:
- { name: 'http_header',
label: 'http_header',
args: {
uid_header: 'remote_user'
} }
4.nginx默认是会去掉带下划线的header,所以,remote_user在经过nginx的时候被干掉了,需要在nginx的server结点下配置这个指令:
underscores_in_headers on;
关于单点退出的问题:让apache拦截gitlab的退出地址,重定向到cas的退出地址上,在cas退出的时候,清除掉gitlab设置的sessioncookie _gitlab_session即可实现单点退出