Project

General

Profile

« Previous | Next » 

Revision 2ef6f4da

Added by Daniel Lobato Garcia over 8 years ago

Fixes #11407 - Uppercase logins from LDAP break external user group sync

On LDAP the login can contain uppercase chars, for instance, "FOO". However
when we log in Foreman for the first time and have that account auto-created,
we can login using "foo". After that, our login will be saved as "foo" on
Foreman.

When a user group that contains said group is refreshed, we pull the names
from LDAP, auth_source.users_in_group(name). This will return an array
containing "FOO". After that, we will call usergroup.add_users(["FOO"])
which in turn calls User.where(:login => ["FOO"]). This will be empty since
our login in the database is "foo".

This commit fixes this issue in two places:
One, by saving the login as it comes from LDAP (case aware), so that
in the previous example 'FOO' would've been saved even if the user had
try to login as 'foo'.

Two, by making add_users and remove_users case insensitive.

View differences:

app/models/auth_sources/auth_source_ldap.rb
end
logger.debug "Updating user groups for user #{login}"
internal = User.find(login).external_usergroups.map(&:name)
internal = User.find_by_login(login).external_usergroups.map(&:name)
external = ldap_con.group_list(login) # this list may return all groups in lowercase
(internal | external).each do |name|
begin
......
{ :firstname => attr_firstname,
:lastname => attr_lastname,
:mail => attr_mail,
:login => attr_login,
:dn => :dn,
}
end
app/models/user.rb
logger.debug("Updating user #{user.login} attributes from auth source: #{attrs.keys}")
user.update_attributes(valid_attrs)
end
user.auth_source.update_usergroups(login)
user.auth_source.update_usergroups(user.login)
end
# clean up old avatar if it exists and the image isn't in use by anyone else
......
if (attrs = AuthSource.authenticate(login, password))
attrs.delete(:dn)
user = new(attrs)
user.login = login
# The default user can't auto create users, we need to change to Admin for this to work
User.as_anonymous_admin do
if user.save
AuthSource.find(attrs[:auth_source_id]).update_usergroups(login)
AuthSource.find(attrs[:auth_source_id]).update_usergroups(user.login)
logger.info "User '#{user.login}' auto-created from #{user.auth_source}"
else
logger.info "Failed to save User '#{user.login}' #{user.errors.full_messages}"
app/models/usergroup.rb
end
def add_users(userlist)
users << User.where( {:login => userlist } )
users << User.where(:lower_login => userlist.map(&:downcase))
end
def remove_users(userlist)
old_users = User.select { |user| userlist.include?(user.login) }
self.users = self.users - old_users
self.users = self.users - User.where(:lower_login => userlist.map(&:downcase))
end
protected
test/unit/user_test.rb
end
end
test ".try_to_login if password is empty should return nil" do
assert_nil User.try_to_login("anything", "")
end
context "try to login" do
test "when password is empty should return nil" do
assert_nil User.try_to_login("anything", "")
......
context 'auto create users' do
setup do
ldap_attrs = { :firstname => "Foo", :lastname => "Bar", :mail => "baz@qux.com" }
AuthSourceLdap.any_instance.stubs(:authenticate).
returns(ldap_attrs)
ldap_attrs = { :firstname => "Foo", :lastname => "Bar", :mail => "baz@qux.com",
:login => 'FoOBaR' }
AuthSourceLdap.any_instance.stubs(:authenticate).returns(ldap_attrs)
@ldap_server = AuthSource.find_by_name("ldap-server")
end
test "enabled on-the-fly registration" do
AuthSourceLdap.any_instance.expects(:update_usergroups).
with('fakeuser').returns(true)
with('FoOBaR').returns(true)
@ldap_server.update_attribute(:onthefly_register, true)
assert_difference("User.count", 1) do
assert User.try_to_auto_create_user('fakeuser','fakepass')
assert User.try_to_auto_create_user('foobar','fakepass')
end
end
test "disabled on-the-fly registration" do
@ldap_server.update_attribute(:onthefly_register, false)
assert_difference("User.count", 0) do
refute User.try_to_auto_create_user('fakeuser','fakepass')
refute User.try_to_auto_create_user('foobar','fakepass')
end
end
test "use LDAP login attribute as login" do
AuthSourceLdap.any_instance.expects(:update_usergroups).
with('FoOBaR').returns(true)
created_user = User.try_to_auto_create_user('foobar','fakepass')
assert_equal created_user.login, "FoOBaR"
end
end
context "editing self?" do
test/unit/usergroup_test.rb
assert_equal 3, user.reload.cached_user_roles.size
end
test 'add_users adds users in list and does not add nonexistent users' do
test 'add_users is case insensitive and does not add nonexistent users' do
usergroup = FactoryGirl.create(:usergroup)
usergroup.send(:add_users, ['one', 'two', 'three'])
usergroup.send(:add_users, ['OnE', 'TwO', 'tHREE'])
# users 'one' 'two' are defined in fixtures, 'three' is not defined
assert_equal ['one', 'two'], usergroup.users.map(&:login).sort
end
test 'remove_users removes user list' do
test 'remove_users removes user list and is case insensitive' do
usergroup = FactoryGirl.create(:usergroup)
usergroup.send(:add_users, ['one', 'two'])
usergroup.send(:add_users, ['OnE', 'tWo'])
assert_equal ['one', 'two'], usergroup.users.map(&:login).sort
usergroup.send(:remove_users, ['one', 'two'])
usergroup.send(:remove_users, ['ONE', 'TWO'])
assert_equal [], usergroup.users
end

Also available in: Unified diff