Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouwe Maan <douwe@gitlab.com>2018-01-05 12:22:40 +0300
committerDouwe Maan <douwe@gitlab.com>2018-01-05 12:22:40 +0300
commit4dbf32d1098478c4ab48b723b812b58d4f2aac1c (patch)
tree2866ecaeafbb52726ea48c3938a3f4c7f9d2d2ae
parent1560c234d2410ccbd163b9aedecf2d8b7a596627 (diff)
parent7d1fdcdc836921d2f2324265752107519f47a6de (diff)
Merge branch 'ldap_username_attributes' into 'master'
Modify `LDAP::Person` to return username value based on attributes Closes #39691 See merge request gitlab-org/gitlab-ce!15286
-rw-r--r--changelogs/unreleased/ldap_username_attributes.yml5
-rw-r--r--lib/gitlab/ldap/adapter.rb2
-rw-r--r--lib/gitlab/ldap/config.rb2
-rw-r--r--lib/gitlab/ldap/person.rb36
-rw-r--r--spec/lib/gitlab/ldap/adapter_spec.rb10
-rw-r--r--spec/lib/gitlab/ldap/person_spec.rb73
-rw-r--r--spec/lib/gitlab/o_auth/user_spec.rb20
7 files changed, 135 insertions, 13 deletions
diff --git a/changelogs/unreleased/ldap_username_attributes.yml b/changelogs/unreleased/ldap_username_attributes.yml
new file mode 100644
index 00000000000..89bbca58fc9
--- /dev/null
+++ b/changelogs/unreleased/ldap_username_attributes.yml
@@ -0,0 +1,5 @@
+---
+title: Modify `LDAP::Person` to return username value based on attributes
+merge_request:
+author:
+type: fixed
diff --git a/lib/gitlab/ldap/adapter.rb b/lib/gitlab/ldap/adapter.rb
index 0afaa2306b5..76863e77dc3 100644
--- a/lib/gitlab/ldap/adapter.rb
+++ b/lib/gitlab/ldap/adapter.rb
@@ -74,7 +74,7 @@ module Gitlab
def user_options(fields, value, limit)
options = {
- attributes: Gitlab::LDAP::Person.ldap_attributes(config).compact.uniq,
+ attributes: Gitlab::LDAP::Person.ldap_attributes(config),
base: config.base
}
diff --git a/lib/gitlab/ldap/config.rb b/lib/gitlab/ldap/config.rb
index c8f19cd52d5..0d9a554fc18 100644
--- a/lib/gitlab/ldap/config.rb
+++ b/lib/gitlab/ldap/config.rb
@@ -148,7 +148,7 @@ module Gitlab
def default_attributes
{
- 'username' => %w(uid userid sAMAccountName),
+ 'username' => %w(uid sAMAccountName userid),
'email' => %w(mail email userPrincipalName),
'name' => 'cn',
'first_name' => 'givenName',
diff --git a/lib/gitlab/ldap/person.rb b/lib/gitlab/ldap/person.rb
index 38d7a9ba2f5..e81cec6ba1a 100644
--- a/lib/gitlab/ldap/person.rb
+++ b/lib/gitlab/ldap/person.rb
@@ -6,6 +6,8 @@ module Gitlab
# Source: http://ctogonewild.com/2009/09/03/bitmask-searches-in-ldap/
AD_USER_DISABLED = Net::LDAP::Filter.ex("userAccountControl:1.2.840.113556.1.4.803", "2")
+ InvalidEntryError = Class.new(StandardError)
+
attr_accessor :entry, :provider
def self.find_by_uid(uid, adapter)
@@ -29,11 +31,12 @@ module Gitlab
def self.ldap_attributes(config)
[
- 'dn', # Used in `dn`
- config.uid, # Used in `uid`
- *config.attributes['name'], # Used in `name`
- *config.attributes['email'] # Used in `email`
- ]
+ 'dn',
+ config.uid,
+ *config.attributes['name'],
+ *config.attributes['email'],
+ *config.attributes['username']
+ ].compact.uniq
end
def self.normalize_dn(dn)
@@ -60,6 +63,8 @@ module Gitlab
Rails.logger.debug { "Instantiating #{self.class.name} with LDIF:\n#{entry.to_ldif}" }
@entry = entry
@provider = provider
+
+ validate_entry
end
def name
@@ -71,7 +76,13 @@ module Gitlab
end
def username
- uid
+ username = attribute_value(:username)
+
+ # Depending on the attribute, multiple values may
+ # be returned. We need only one for username.
+ # Ex. `uid` returns only one value but `mail` may
+ # return an array of multiple email addresses.
+ [username].flatten.first
end
def email
@@ -104,6 +115,19 @@ module Gitlab
entry.public_send(selected_attr) # rubocop:disable GitlabSecurity/PublicSend
end
+
+ def validate_entry
+ allowed_attrs = self.class.ldap_attributes(config).map(&:downcase)
+
+ # Net::LDAP::Entry transforms keys to symbols. Change to strings to compare.
+ entry_attrs = entry.attribute_names.map { |n| n.to_s.downcase }
+ invalid_attrs = entry_attrs - allowed_attrs
+
+ if invalid_attrs.any?
+ raise InvalidEntryError,
+ "#{self.class.name} initialized with Net::LDAP::Entry containing invalid attributes(s): #{invalid_attrs}"
+ end
+ end
end
end
end
diff --git a/spec/lib/gitlab/ldap/adapter_spec.rb b/spec/lib/gitlab/ldap/adapter_spec.rb
index d9ddb4326be..6132abd9b35 100644
--- a/spec/lib/gitlab/ldap/adapter_spec.rb
+++ b/spec/lib/gitlab/ldap/adapter_spec.rb
@@ -16,7 +16,7 @@ describe Gitlab::LDAP::Adapter do
expect(adapter).to receive(:ldap_search) do |arg|
expect(arg[:filter].to_s).to eq('(uid=johndoe)')
expect(arg[:base]).to eq('dc=example,dc=com')
- expect(arg[:attributes]).to match(%w{dn uid cn mail email userPrincipalName})
+ expect(arg[:attributes]).to match(ldap_attributes)
end.and_return({})
adapter.users('uid', 'johndoe')
@@ -26,7 +26,7 @@ describe Gitlab::LDAP::Adapter do
expect(adapter).to receive(:ldap_search).with(
base: 'uid=johndoe,ou=users,dc=example,dc=com',
scope: Net::LDAP::SearchScope_BaseObject,
- attributes: %w{dn uid cn mail email userPrincipalName},
+ attributes: ldap_attributes,
filter: nil
).and_return({})
@@ -63,7 +63,7 @@ describe Gitlab::LDAP::Adapter do
it 'uses the right uid attribute when non-default' do
stub_ldap_config(uid: 'sAMAccountName')
expect(adapter).to receive(:ldap_search).with(
- hash_including(attributes: %w{dn sAMAccountName cn mail email userPrincipalName})
+ hash_including(attributes: ldap_attributes)
).and_return({})
adapter.users('sAMAccountName', 'johndoe')
@@ -137,4 +137,8 @@ describe Gitlab::LDAP::Adapter do
end
end
end
+
+ def ldap_attributes
+ Gitlab::LDAP::Person.ldap_attributes(Gitlab::LDAP::Config.new('ldapmain'))
+ end
end
diff --git a/spec/lib/gitlab/ldap/person_spec.rb b/spec/lib/gitlab/ldap/person_spec.rb
index d204050ef66..ff29d9aa5be 100644
--- a/spec/lib/gitlab/ldap/person_spec.rb
+++ b/spec/lib/gitlab/ldap/person_spec.rb
@@ -8,13 +8,16 @@ describe Gitlab::LDAP::Person do
before do
stub_ldap_config(
options: {
+ 'uid' => 'uid',
'attributes' => {
- 'name' => 'cn',
- 'email' => %w(mail email userPrincipalName)
+ 'name' => 'cn',
+ 'email' => %w(mail email userPrincipalName),
+ 'username' => username_attribute
}
}
)
end
+ let(:username_attribute) { %w(uid sAMAccountName userid) }
describe '.normalize_dn' do
subject { described_class.normalize_dn(given) }
@@ -44,6 +47,34 @@ describe Gitlab::LDAP::Person do
end
end
+ describe '.ldap_attributes' do
+ it 'returns a compact and unique array' do
+ stub_ldap_config(
+ options: {
+ 'uid' => nil,
+ 'attributes' => {
+ 'name' => 'cn',
+ 'email' => 'mail',
+ 'username' => %w(uid mail memberof)
+ }
+ }
+ )
+ config = Gitlab::LDAP::Config.new('ldapmain')
+ ldap_attributes = described_class.ldap_attributes(config)
+
+ expect(ldap_attributes).to match_array(%w(dn uid cn mail memberof))
+ end
+ end
+
+ describe '.validate_entry' do
+ it 'raises InvalidEntryError' do
+ entry['foo'] = 'bar'
+
+ expect { described_class.new(entry, 'ldapmain') }
+ .to raise_error(Gitlab::LDAP::Person::InvalidEntryError)
+ end
+ end
+
describe '#name' do
it 'uses the configured name attribute and handles values as an array' do
name = 'John Doe'
@@ -72,6 +103,44 @@ describe Gitlab::LDAP::Person do
end
end
+ describe '#username' do
+ context 'with default uid username attribute' do
+ let(:username_attribute) { 'uid' }
+
+ it 'returns the proper username value' do
+ attr_value = 'johndoe'
+ entry[username_attribute] = attr_value
+ person = described_class.new(entry, 'ldapmain')
+
+ expect(person.username).to eq(attr_value)
+ end
+ end
+
+ context 'with a different username attribute' do
+ let(:username_attribute) { 'sAMAccountName' }
+
+ it 'returns the proper username value' do
+ attr_value = 'johndoe'
+ entry[username_attribute] = attr_value
+ person = described_class.new(entry, 'ldapmain')
+
+ expect(person.username).to eq(attr_value)
+ end
+ end
+
+ context 'with a non-standard username attribute' do
+ let(:username_attribute) { 'mail' }
+
+ it 'returns the proper username value' do
+ attr_value = 'john.doe@example.com'
+ entry[username_attribute] = attr_value
+ person = described_class.new(entry, 'ldapmain')
+
+ expect(person.username).to eq(attr_value)
+ end
+ end
+ end
+
def assert_generic_test(test_description, got, expected)
test_failure_message = "Failed test description: '#{test_description}'\n\n expected: #{expected}\n got: #{got}"
expect(got).to eq(expected), test_failure_message
diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb
index 6334bcd0156..45fff4c5787 100644
--- a/spec/lib/gitlab/o_auth/user_spec.rb
+++ b/spec/lib/gitlab/o_auth/user_spec.rb
@@ -275,6 +275,26 @@ describe Gitlab::OAuth::User do
end
end
+ context 'and a corresponding LDAP person with a non-default username' do
+ before do
+ allow(ldap_user).to receive(:uid) { uid }
+ allow(ldap_user).to receive(:username) { 'johndoe@example.com' }
+ allow(ldap_user).to receive(:email) { %w(johndoe@example.com john2@example.com) }
+ allow(ldap_user).to receive(:dn) { dn }
+ end
+
+ context 'and no account for the LDAP user' do
+ it 'creates a user favoring the LDAP username and strips email domain' do
+ allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(ldap_user)
+
+ oauth_user.save
+
+ expect(gl_user).to be_valid
+ expect(gl_user.username).to eql 'johndoe'
+ end
+ end
+ end
+
context "and no corresponding LDAP person" do
before do
allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(nil)