ldap: don't crash on duplicated users (#27697)

Keep roles on the more recently used user, then delete the other ones'.
This commit is contained in:
Serghei Mihai 2018-11-06 15:15:26 +01:00
parent 422bd6a5d7
commit 4db66981f0
2 changed files with 32 additions and 6 deletions

View File

@ -834,12 +834,23 @@ class LDAPBackend(object):
external_id = self.build_external_id(eid_tuple, attributes)
if not external_id:
continue
try:
log.debug('lookup using external_id %r: %r', eid_tuple, external_id)
return LDAPUser.objects.prefetch_related('groups').get(
userexternalid__external_id__iexact=external_id, userexternalid__source=block['realm'])
except User.DoesNotExist:
pass
log.debug('lookup using external_id %r: %r', eid_tuple, external_id)
users = LDAPUser.objects.prefetch_related('groups').filter(
userexternalid__external_id__iexact=external_id,
userexternalid__source=block['realm']).order_by('-last_login')
# ordering of NULLs cannot be done through the ORM
users = sorted(users, reverse=True, key=lambda u: (u.last_login is not None, u.last_login))
if users:
user = users[0]
if len(users) > 1:
log.info('found %d users, collectings roles into the first one and deleting the other ones.',
len(users))
for other in users[1:]:
for r in other.roles.all():
user.roles.add(r)
other.delete()
return user
return None
def lookup_existing_user(self, username, block, attributes):
for lookup_type in block['lookups']:

View File

@ -11,6 +11,7 @@ from django.contrib.auth import get_user_model
from django.core.exceptions import ImproperlyConfigured
from django.core import mail
from django.utils.encoding import force_text
from django.utils import timezone
from authentic2.a2_rbac.utils import get_default_ou
from django_rbac.utils import get_ou_model
@ -416,6 +417,20 @@ def test_get_users(slapd, settings):
assert save.call_count == 0
assert bulk_create.call_count == 0
# create user with the same username, but case-different
save.reset_mock()
bulk_create.reset_mock()
u = ldap_backend.LDAPUser.objects.create(username=UID.capitalize())
eid = ldap_backend.UserExternalId.objects.create(external_id=UID.capitalize(),
source='ldap', user=u)
# set user login time as if he logged in
user = ldap_backend.LDAPUser.objects.get(username='%s@ldap'%UID)
user.last_login = timezone.now()
user.save()
assert ldap_backend.LDAPUser.objects.count() == 102
users = list(ldap_backend.LDAPBackend.get_users())
assert len(users) == 101
assert ldap_backend.LDAPUser.objects.filter(username='%s' % UID.capitalize()).count() == 0
@pytest.mark.django_db
def test_set_mandatory_roles(slapd, settings):