Project

General

Profile

« Previous | Next » 

Revision 01f8b024

Added by Daniel Lobato Garcia over 9 years ago

Fixes #7369 - External user groups update on login

View differences:

app/controllers/usergroups_controller.rb
class UsergroupsController < ApplicationController
include Foreman::Controller::AutoCompleteSearch
before_filter :find_resource, :only => [:edit, :update, :destroy]
after_filter :refresh_external_usergroups, :only => [:create, :update]
def index
@usergroups = resource_base.paginate :page => params[:page]
......
def find_by_id(permission = :view_usergroups)
Usergroup.authorized(permission).find(params[:id])
end
def refresh_external_usergroups
@usergroup.external_usergroups.map(&:refresh)
end
end
app/models/auth_source.rb
end
# Called after creating a new user at login
def update_usergroups(login, password)
def update_usergroups(login)
end
# Try to authenticate a user not yet registered against available sources
app/models/auth_sources/auth_source_ldap.rb
end
end
def update_usergroups(login, password)
ldap_con(login, password).group_list(login).each do |name|
def update_usergroups(login)
internal = User.find(login).external_usergroups.map(&:name)
external = ldap_con(account, account_password).group_list(login)
(internal | external).each do |name|
begin
external_usergroup = external_usergroups.find_by_name(name)
external_usergroup.refresh if external_usergroup.present?
......
def users_in_group(name)
ldap_con.user_list(name)
rescue
# To be fixed after ldap_fluff returns [] for an empty group
# instead of raising an exception
[]
end
private
app/models/user.rb
# update with returned attrs, maybe some info changed in LDAP
old_hash = user.avatar_hash
User.as_anonymous_admin do
user.update_attributes(attrs.slice(:firstname, :lastname, :mail, :avatar_hash).delete_if { |k, v| v.blank? })
end if attrs.is_a? Hash
user.update_attributes(attrs.slice(:firstname, :lastname, :mail, :avatar_hash).delete_if { |k, v| v.blank? }) if attrs.is_a? Hash
user.auth_source.update_usergroups(login)
end
# clean up old avatar if it exists and the image isn't in use by anyone else
if old_hash.present? && user.avatar_hash != old_hash && !User.unscoped.where(:avatar_hash => old_hash).any?
......
sweeper.expire_fragment(TopbarSweeper.fragment_name(id))
end
def external_usergroups
usergroups.flat_map(&:external_usergroups).select { |group| group.auth_source == self.auth_source }
end
private
def prepare_password
......
# 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, password)
AuthSource.find(attrs[:auth_source_id]).update_usergroups(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}"
test/unit/auth_source_ldap_test.rb
setup_ldap_stubs
ExternalUsergroup.any_instance.expects(:refresh).never
LdapFluff.any_instance.expects(:group_list).with('test').returns([])
@auth_source_ldap.send(:update_usergroups, 'test', 'pass')
@auth_source_ldap.send(:update_usergroups, 'test')
end
test 'update_usergroups calls refresh_ldap if entry belongs to some group' do
setup_ldap_stubs
ExternalUsergroup.expects(:find_by_name).with('ipausers').returns(ExternalUsergroup.new)
ExternalUsergroup.any_instance.expects(:present?).returns(true)
ExternalUsergroup.any_instance.expects(:refresh).returns(true)
LdapFluff.any_instance.expects(:group_list).with('test').returns(['ipausers'])
@auth_source_ldap.send(:update_usergroups, 'test', 'pass')
context 'refresh ldap' do
setup do
setup_ldap_stubs
LdapFluff.any_instance.expects(:group_list).with('test').returns(['ipausers'])
end
test 'update_usergroups calls refresh_ldap if entry belongs to some group' do
ExternalUsergroup.expects(:find_by_name).with('ipausers').returns(ExternalUsergroup.new)
@auth_source_ldap.send(:update_usergroups, 'test')
end
test 'update_usergroups refreshes on all external user groups, in LDAP and in Foreman auth source' do
@auth_source_ldap.stubs(:valid_group?).returns(true)
external = FactoryGirl.create(:external_usergroup, :auth_source => @auth_source_ldap)
User.any_instance.expects(:external_usergroups).returns([external])
@auth_source_ldap.send(:update_usergroups, 'test')
end
end
test '#to_config with dedicated service account returns hash' do
test/unit/user_test.rb
assert_nil User.try_to_login("anything", "")
end
test "when a user login, his last login time should be updated" do
user = users(:internal)
last_login = user.last_login_on
assert_not_nil User.try_to_login(user.login, "changeme")
assert_not_equal last_login, User.find(user.id).last_login_on
end
context "try to login" do
test "when password is empty should return nil" do
assert_nil User.try_to_login("anything", "")
end
test "ldap user attribute should be updated when not blank" do
AuthSourceLdap.any_instance.stubs(:authenticate).returns({ :firstname => "Foo" })
u = User.try_to_login("foo", "password")
assert_equal u.firstname, "Foo"
end
test "when a user logs in, last login time should be updated" do
user = users(:internal)
last_login = user.last_login_on
assert_not_nil User.try_to_login(user.login, "changeme")
assert_not_equal last_login, User.find(user.id).last_login_on
end
test "ldap user attribute should not be updated when blank" do
AuthSourceLdap.any_instance.stubs(:authenticate).returns({ :mail => "" })
u = User.try_to_login("foo", "password")
assert_equal u.mail, "foo@bar.com"
end
test ".try_to_login on unknown user should return nil" do
User.expects(:try_to_auto_create_user).with('unknown user account', 'secret')
refute User.try_to_login('unknown user account', 'secret')
end
test ".try_to_login on unknown user should return nil" do
User.expects(:try_to_auto_create_user).with('unknown user account', 'secret')
refute User.try_to_login('unknown user account', 'secret')
end
test ".try_to_login and failing AuthSource should return nil" do
u = FactoryGirl.create(:user)
AuthSourceInternal.any_instance.expects(:authenticate).with(u.login, 'password').returns(nil)
refute User.try_to_login(u.login, 'password')
end
test ".try_to_login and failing AuthSource should return nil" do
u = FactoryGirl.create(:user)
AuthSourceInternal.any_instance.expects(:authenticate).with(u.login, 'password').returns(nil)
refute User.try_to_login(u.login, 'password')
end
test ".try_to_login should return user on successful login" do
u = FactoryGirl.create(:user)
assert_equal u, User.try_to_login(u.login, 'password')
end
test ".try_to_login should return user on successful login" do
u = FactoryGirl.create(:user)
assert_equal u, User.try_to_login(u.login, 'password')
test "updates usergroups on login" do
AuthSourceLdap.any_instance.stubs(:authenticate).returns({})
AuthSourceLdap.any_instance.expects(:update_usergroups).returns(true)
User.try_to_login("foo", "password")
end
context "ldap attributes" do
setup do
AuthSourceLdap.any_instance.stubs(:update_usergroups).returns(true)
end
test "ldap user attribute should be updated when not blank (firstname)" do
AuthSourceLdap.any_instance.stubs(:authenticate).returns({ :firstname => "Foo" })
logged_in_user = User.try_to_login("foo", "password")
assert_equal "Foo", logged_in_user.firstname
end
test "ldap user attribute should not be updated when blank (mail)" do
AuthSourceLdap.any_instance.stubs(:authenticate).returns({ :mail => "" })
logged_in_user = User.try_to_login("foo", "password")
assert_equal "foo@bar.com", logged_in_user.mail
end
end
end
def setup_user(operation)
......
end
end
test ".find_or_create_external_user" do
count = User.count
# existing user
assert User.find_or_create_external_user({:login => users(:one).login}, nil)
assert_equal count, User.count
# not existing user without auth source specified
refute User.find_or_create_external_user({:login => 'not_existing_user'}, nil)
assert_equal count, User.count
# not existing user with existing AuthSource
apache_source = AuthSourceExternal.find_or_create_by_name('apache_module')
source_count = AuthSource.count
assert User.find_or_create_external_user({:login => 'not_existing_user'}, apache_source.name)
assert_equal count + 1, User.count
assert_equal source_count, AuthSource.count
user = User.find_by_login('not_existing_user')
assert_equal apache_source.name, user.auth_source.name
count = User.count
assert User.find_or_create_external_user({:login => 'not_existing_user_2'}, 'new_external_source')
assert_equal count + 1, User.count
assert_equal source_count + 1, AuthSource.count
user = User.find_by_login('not_existing_user_2')
new_source = AuthSourceExternal.find_by_name('new_external_source')
assert_equal new_source.name, user.auth_source.name
# with other attributes which gets saved as well
apache_source = AuthSourceExternal.find_or_create_by_name('apache_module')
assert User.find_or_create_external_user({:login => 'not_existing_user_3',
:mail => 'foobar@example.com',
:firstname => 'Foo',
:lastname => 'Bar'},
apache_source.name)
user = User.find_by_login('not_existing_user_3')
assert_equal 'foobar@example.com', user.mail
assert_equal 'Foo', user.firstname
assert_equal 'Bar', user.lastname
# with existing user groups that are assigned
apache_source = AuthSourceExternal.find_or_create_by_name('apache_module')
usergroup = FactoryGirl.create :usergroup
external = FactoryGirl.create :external_usergroup, :usergroup => usergroup,
:auth_source => apache_source,
:name => usergroup.name
assert User.find_or_create_external_user({:login => 'not_existing_user_4',
:groups => [external.name, 'does-not-exists-for-sure-123']},
apache_source.name)
user = User.find_by_login('not_existing_user_4')
assert_equal [usergroup], user.usergroups
end
test ".find_or_create_external_user updates external groups" do
apache_source = AuthSourceExternal.find_or_create_by_name('apache_module')
user = FactoryGirl.create(:user, :auth_source => apache_source)
external1 = FactoryGirl.create(:external_usergroup, :auth_source => apache_source)
external2 = FactoryGirl.create(:external_usergroup, :auth_source => apache_source)
usergroup = FactoryGirl.create(:usergroup)
user.usergroups << [external1.usergroup, usergroup]
refute_equal 'foo@example.com', user.mail
assert User.find_or_create_external_user({:login => user.login,
:groups => [external2.name],
:mail => 'foo@example.com'},
apache_source.name)
user.reload
assert_includes user.usergroups, external2.usergroup
assert_includes user.usergroups, usergroup
assert_equal 'foo@example.com', user.mail
end
test ".try_to_auto_create_user" do
AuthSourceLdap.any_instance.stubs(:authenticate).returns({ :firstname => "Foo", :lastname => "Bar", :mail => "baz@qux.com" })
AuthSourceLdap.any_instance.expects(:update_usergroups).with('non_existing_user_1', 'password').returns(true)
ldap_server = AuthSource.find_by_name("ldap-server")
# AuthSource that allows onthefly registration
count = User.count
ldap_server.update_attribute(:onthefly_register, true)
assert User.try_to_auto_create_user('non_existing_user_1','password')
assert_equal count + 1, User.count
# AuthSource that forbids onthefly registration
count = User.count
ldap_server.update_attribute(:onthefly_register, false)
refute User.try_to_auto_create_user('non_existing_user_2','password')
assert_equal count, User.count
end
test 'user should allow editing self?' do
User.current = users(:one)
# edit self
options = {:controller => 'users', :action => 'edit', :id => User.current.id}
assert User.current.editing_self?(options)
# update self
options = {:controller => 'users', :action => 'update', :id => User.current.id}
assert User.current.editing_self?(options)
# update someone else
options = {:controller => 'users', :action => 'update', :id => users(:two).id}
assert_not User.current.editing_self?(options)
# update for another controller
options = {:controller => 'hosts', :action => 'update', :id => User.current.id}
assert_not User.current.editing_self?(options)
context "find_or_create_external_user" do
context "internal or not existing AuthSource" do
test 'existing user' do
assert_difference('User.count', 0) do
assert User.find_or_create_external_user({:login => users(:one).login}, nil)
end
end
test 'not existing user without auth source specified' do
assert_difference('User.count', 0) do
refute User.find_or_create_external_user({:login => 'not_existing_user'}, nil)
end
end
test 'not existing user with non existing auth source' do
assert_difference('User.count', 1) do
assert_difference('AuthSource.count', 1) do
assert User.find_or_create_external_user({:login => 'not_existing_user'},
'new_external_source')
end
end
created_user = User.find_by_login('not_existing_user')
new_source = AuthSourceExternal.find_by_name('new_external_source')
assert_equal new_source.name, created_user.auth_source.name
end
end
context "existing AuthSource" do
setup do
@apache_source = AuthSourceExternal.find_or_create_by_name('apache_module')
end
test "not existing" do
assert_difference('User.count', 1) do
assert_difference('AuthSource.count', 0) do
assert User.find_or_create_external_user({:login => 'not_existing_user'},
@apache_source.name)
end
end
end
test "not existing with attributes" do
assert User.find_or_create_external_user({:login => 'not_existing_user',
:mail => 'foobar@example.com',
:firstname => 'Foo',
:lastname => 'Bar'},
@apache_source.name)
created_user = User.find_by_login('not_existing_user')
assert_equal @apache_source.name, created_user.auth_source.name
assert_equal 'foobar@example.com', created_user.mail
assert_equal 'Foo', created_user.firstname
assert_equal 'Bar', created_user.lastname
end
context 'with external user groups' do
setup do
@user = FactoryGirl.create(:user, :auth_source => @apache_source)
@external = FactoryGirl.create(:external_usergroup, :auth_source => @apache_source)
@usergroup = FactoryGirl.create(:usergroup)
end
test "existing user groups that are assigned" do
@external.update_attributes(:usergroup => @usergroup, :name => @usergroup.name)
assert User.find_or_create_external_user({:login => "not_existing_user",
:groups => [@external.name,
"notexistentexternal"]},
@apache_source.name)
created_user = User.find_by_login("not_existing_user")
assert_equal [@usergroup], created_user.usergroups
end
end
end
end
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_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)
@ldap_server.update_attribute(:onthefly_register, true)
assert_difference("User.count", 1) do
assert User.try_to_auto_create_user('fakeuser','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')
end
end
end
context "editing self?" do
# A regular setup block would run before the global setup
# leaving User.current = users :admin
def editing_self_helper
User.current = users(:one)
@options = {:controller => "users", :action => "edit", :id => User.current.id}
end
test "edit self" do
editing_self_helper
assert User.current.editing_self?(@options)
end
test "update self" do
editing_self_helper
@options.merge!({ :action => "update" })
assert User.current.editing_self?(@options)
end
test "update other user" do
editing_self_helper
@options.merge!({ :id => users(:two).id })
refute User.current.editing_self?(@options)
end
test "update through other controller" do
editing_self_helper
@options.merge!({ :controller => "hosts", :id => User.current.id })
refute User.current.editing_self?(@options)
end
end
test "#can? for admin" do

Also available in: Unified diff