Skip to content

Commit 18d765d

Browse files
committed
Merge branch 'dev'
2 parents 3be1bbf + 3dd1927 commit 18d765d

File tree

3 files changed

+57
-14
lines changed

3 files changed

+57
-14
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)

djangosaml2/views.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -250,14 +250,14 @@ def get(self, request, *args, **kwargs):
250250

251251
# SSO options
252252
sign_requests = getattr(conf, '_sp_authn_requests_signed', False)
253-
254253
if sign_requests:
255-
csc = settings.SAML_CONFIG['service']['sp']
256-
sso_kwargs["sigalg"] = csc.get('signing_algorithm',
257-
saml2.xmldsig.SIG_RSA_SHA256)
258-
sso_kwargs["digest_alg"] = csc.get('digest_algorithm',
259-
saml2.xmldsig.DIGEST_SHA256)
260-
254+
sso_kwargs["sigalg"] = getattr(conf, '_sp_signing_algorithm',
255+
saml2.xmldsig.SIG_RSA_SHA256
256+
)
257+
sso_kwargs["digest_alg"] = getattr(conf,
258+
'_sp_digest_algorithm',
259+
saml2.xmldsig.DIGEST_SHA256
260+
)
261261
# pysaml needs a string otherwise: "cannot serialize True (type bool)"
262262
if getattr(conf, '_sp_force_authn', False):
263263
sso_kwargs['force_authn'] = "true"

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('[email protected]'), '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': ('[email protected]',),
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)