Commit c50b98da authored by Drew Blessing's avatar Drew Blessing

Centralize LDAP config/filter logic

Centralize all LDAP config logic in `GitLab::LDAP::Config`. Previously,
some logic was in the Devise initializer and it was not honoring the
`user_filter`. If a user outside the configured `user_filter` signed
in, an account would be created but they would then be denied access.
Now that logic is centralized, the filter is honored and users outside
the filter are never created.
parent 6eeff67c
...@@ -3,7 +3,7 @@ module AuthHelper ...@@ -3,7 +3,7 @@ module AuthHelper
FORM_BASED_PROVIDERS = [/\Aldap/, 'crowd'].freeze FORM_BASED_PROVIDERS = [/\Aldap/, 'crowd'].freeze
def ldap_enabled? def ldap_enabled?
Gitlab.config.ldap.enabled Gitlab::LDAP::Config.enabled?
end end
def omniauth_enabled? def omniauth_enabled?
......
---
title: Centralize LDAP config/filter logic
merge_request: 6606
author:
...@@ -213,22 +213,9 @@ Devise.setup do |config| ...@@ -213,22 +213,9 @@ Devise.setup do |config|
end end
if Gitlab::LDAP::Config.enabled? if Gitlab::LDAP::Config.enabled?
Gitlab.config.ldap.servers.values.each do |server| Gitlab::LDAP::Config.providers.each do |provider|
if server['allow_username_or_email_login'] ldap_config = Gitlab::LDAP::Config.new(provider)
email_stripping_proc = ->(name) {name.gsub(/@.*\z/, '')} config.omniauth(provider, ldap_config.omniauth_options)
else
email_stripping_proc = ->(name) {name}
end
config.omniauth server['provider_name'],
host: server['host'],
base: server['base'],
uid: server['uid'],
port: server['port'],
method: server['method'],
bind_dn: server['bind_dn'],
password: server['password'],
name_proc: email_stripping_proc
end end
end end
......
...@@ -89,9 +89,7 @@ module Gitlab ...@@ -89,9 +89,7 @@ module Gitlab
end end
def user_filter(filter = nil) def user_filter(filter = nil)
if config.user_filter.present? user_filter = config.constructed_user_filter if config.user_filter.present?
user_filter = Net::LDAP::Filter.construct(config.user_filter)
end
if user_filter && filter if user_filter && filter
Net::LDAP::Filter.join(filter, user_filter) Net::LDAP::Filter.join(filter, user_filter)
......
...@@ -54,11 +54,9 @@ module Gitlab ...@@ -54,11 +54,9 @@ module Gitlab
# Apply LDAP user filter if present # Apply LDAP user filter if present
if config.user_filter.present? if config.user_filter.present?
filter = Net::LDAP::Filter.join( filter = Net::LDAP::Filter.join(filter, config.constructed_user_filter)
filter,
Net::LDAP::Filter.construct(config.user_filter)
)
end end
filter filter
end end
......
...@@ -13,7 +13,7 @@ module Gitlab ...@@ -13,7 +13,7 @@ module Gitlab
end end
def self.providers def self.providers
servers.map {|server| server['provider_name'] } servers.map { |server| server['provider_name'] }
end end
def self.valid_provider?(provider) def self.valid_provider?(provider)
...@@ -38,13 +38,31 @@ module Gitlab ...@@ -38,13 +38,31 @@ module Gitlab
end end
def adapter_options def adapter_options
{ opts = base_options.merge(
host: options['host'], encryption: encryption,
port: options['port'], )
encryption: encryption
}.tap do |options| opts.merge!(auth_options) if has_auth?
options.merge!(auth_options) if has_auth?
opts
end
def omniauth_options
opts = base_options.merge(
base: base,
method: options['method'],
filter: omniauth_user_filter,
name_proc: name_proc
)
if has_auth?
opts.merge!(
bind_dn: options['bind_dn'],
password: options['password']
)
end end
opts
end end
def base def base
...@@ -68,6 +86,10 @@ module Gitlab ...@@ -68,6 +86,10 @@ module Gitlab
options['user_filter'] options['user_filter']
end end
def constructed_user_filter
@constructed_user_filter ||= Net::LDAP::Filter.construct(user_filter)
end
def group_base def group_base
options['group_base'] options['group_base']
end end
...@@ -96,8 +118,27 @@ module Gitlab ...@@ -96,8 +118,27 @@ module Gitlab
options['password'] || options['bind_dn'] options['password'] || options['bind_dn']
end end
def allow_username_or_email_login
options['allow_username_or_email_login']
end
def name_proc
if allow_username_or_email_login
Proc.new { |name| name.gsub(/@.*\z/, '') }
else
Proc.new { |name| name }
end
end
protected protected
def base_options
{
host: options['host'],
port: options['port']
}
end
def base_config def base_config
Gitlab.config.ldap Gitlab.config.ldap
end end
...@@ -126,6 +167,16 @@ module Gitlab ...@@ -126,6 +167,16 @@ module Gitlab
} }
} }
end end
def omniauth_user_filter
uid_filter = Net::LDAP::Filter.eq(uid, '%{username}')
if user_filter.present?
Net::LDAP::Filter.join(uid_filter, constructed_user_filter).to_s
else
uid_filter.to_s
end
end
end end
end end
end end
...@@ -19,6 +19,87 @@ describe Gitlab::LDAP::Config, lib: true do ...@@ -19,6 +19,87 @@ describe Gitlab::LDAP::Config, lib: true do
end end
end end
describe '#adapter_options' do
it 'constructs basic options' do
stub_ldap_config(
options: {
'host' => 'ldap.example.com',
'port' => 386,
'method' => 'plain'
}
)
expect(config.adapter_options).to eq(
host: 'ldap.example.com',
port: 386,
encryption: nil
)
end
it 'includes authentication options when auth is configured' do
stub_ldap_config(
options: {
'host' => 'ldap.example.com',
'port' => 686,
'method' => 'ssl',
'bind_dn' => 'uid=admin,dc=example,dc=com',
'password' => 'super_secret'
}
)
expect(config.adapter_options).to eq(
host: 'ldap.example.com',
port: 686,
encryption: :simple_tls,
auth: {
method: :simple,
username: 'uid=admin,dc=example,dc=com',
password: 'super_secret'
}
)
end
end
describe '#omniauth_options' do
it 'constructs basic options' do
stub_ldap_config(
options: {
'host' => 'ldap.example.com',
'port' => 386,
'base' => 'ou=users,dc=example,dc=com',
'method' => 'plain',
'uid' => 'uid'
}
)
expect(config.omniauth_options).to include(
host: 'ldap.example.com',
port: 386,
base: 'ou=users,dc=example,dc=com',
method: 'plain',
filter: '(uid=%{username})'
)
expect(config.omniauth_options.keys).not_to include(:bind_dn, :password)
end
it 'includes authentication options when auth is configured' do
stub_ldap_config(
options: {
'uid' => 'sAMAccountName',
'user_filter' => '(memberOf=cn=group1,ou=groups,dc=example,dc=com)',
'bind_dn' => 'uid=admin,dc=example,dc=com',
'password' => 'super_secret'
}
)
expect(config.omniauth_options).to include(
filter: '(&(sAMAccountName=%{username})(memberOf=cn=group1,ou=groups,dc=example,dc=com))',
bind_dn: 'uid=admin,dc=example,dc=com',
password: 'super_secret'
)
end
end
describe '#has_auth?' do describe '#has_auth?' do
it 'is true when password is set' do it 'is true when password is set' do
stub_ldap_config( stub_ldap_config(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment