Skip to content

Commit 954b0bb

Browse files
author
Jaap Roes
committed
Fix #245: Don't update user_main_attribute
1 parent 02184cc commit 954b0bb

File tree

2 files changed

+50
-7
lines changed

2 files changed

+50
-7
lines changed

djangosaml2/backends.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ def _update_user(self, user, attributes: dict, attribute_mapping: dict, force_sa
159159
user = self.save_user(user)
160160
return user
161161

162+
# Lookup key
163+
user_lookup_key = self._user_lookup_attribute
162164
has_updated_fields = False
163165
for saml_attr, django_attrs in attribute_mapping.items():
164166
attr_value_list = attributes.get(saml_attr)
@@ -168,7 +170,12 @@ def _update_user(self, user, attributes: dict, attribute_mapping: dict, force_sa
168170
continue
169171

170172
for attr in django_attrs:
171-
if hasattr(user, attr):
173+
if attr == user_lookup_key:
174+
# Don't update user_lookup_key (e.g. username) (issue #245)
175+
# It was just used to find/create this user and might have
176+
# been changed by `clean_user_main_attribute`
177+
continue
178+
elif hasattr(user, attr):
172179
user_attr = getattr(user, attr)
173180
if callable(user_attr):
174181
modified = user_attr(attr_value_list)

tests/testprofiles/tests.py

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -338,17 +338,18 @@ def is_authorized(self, attributes, attribute_mapping, idp_entityid: str, assert
338338
return attributes.get('is_staff', (None, ))[0] == True and assertion_info.get('assertion_id', None) != None
339339

340340
def clean_attributes(self, attributes: dict, idp_entityid: str, **kwargs) -> dict:
341-
''' Keep only age attribute '''
341+
''' Keep only certain attribute '''
342342
return {
343343
'age': attributes.get('age', (None, )),
344+
'mail': attributes.get('mail', (None, )),
344345
'is_staff': attributes.get('is_staff', (None, )),
345346
'uid': attributes.get('uid', (None, )),
346347
}
347348

348349
def clean_user_main_attribute(self, main_attribute):
349-
''' Replace all spaces an dashes by underscores '''
350+
''' Partition string on @ and return the first part '''
350351
if main_attribute:
351-
return main_attribute.replace('-', '_').replace(' ', '_')
352+
return main_attribute.partition('@')[0]
352353
return main_attribute
353354

354355

@@ -380,10 +381,13 @@ def test_is_authorized(self):
380381

381382
def test_clean_attributes(self):
382383
attributes = {'random': 'dummy', 'value': 123, 'age': '28'}
383-
self.assertEqual(self.backend.clean_attributes(attributes, ''), {'age': '28', 'is_staff': (None,), 'uid': (None,)})
384-
384+
self.assertEqual(
385+
self.backend.clean_attributes(attributes, ''),
386+
{'age': '28', 'mail': (None,), 'is_staff': (None,), 'uid': (None,)}
387+
)
388+
385389
def test_clean_user_main_attribute(self):
386-
self.assertEqual(self.backend.clean_user_main_attribute('va--l__ u -e'), 'va__l___u__e')
390+
self.assertEqual(self.backend.clean_user_main_attribute('john@example.com'), 'john')
387391

388392
def test_authenticate(self):
389393
attribute_mapping = {
@@ -454,3 +458,35 @@ def test_authenticate(self):
454458
self.user.refresh_from_db()
455459
self.assertEqual(self.user.age, '28')
456460
self.assertEqual(self.user.is_staff, True)
461+
462+
def test_user_cleaned_main_attribute(self):
463+
"""
464+
In this test the username is taken from the `mail` attribute,
465+
but cleaned to remove the @domain part. After fetching and
466+
updating the user, the username remains the same.
467+
"""
468+
attribute_mapping = {
469+
'mail': ('username',),
470+
'cn': ('first_name',),
471+
'sn': ('last_name',),
472+
'is_staff': ('is_staff', ),
473+
}
474+
attributes = {
475+
'mail': ('john@example.com',),
476+
'cn': ('John',),
477+
'sn': ('Doe',),
478+
'is_staff': (True, ),
479+
}
480+
assertion_info = {
481+
'assertion_id': 'abcdefg12345',
482+
}
483+
user = self.backend.authenticate(
484+
None,
485+
session_info={'ava': attributes, 'issuer': 'dummy_entity_id'},
486+
attribute_mapping=attribute_mapping,
487+
assertion_info=assertion_info,
488+
)
489+
self.assertEqual(user, self.user)
490+
491+
self.user.refresh_from_db()
492+
self.assertEqual(user.username, 'john')

0 commit comments

Comments
 (0)