Skip to content

Commit 73b6a45

Browse files
authored
Merge pull request #35 from maykinmedia/split-up-users
Allow a easy override of the user lookup functionality.
2 parents e91047e + e0be49e commit 73b6a45

File tree

2 files changed

+81
-56
lines changed

2 files changed

+81
-56
lines changed

djangosaml2/backends.py

Lines changed: 75 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323

2424
from djangosaml2.signals import pre_user_save
2525

26+
from . import settings as saml_settings
27+
2628
try:
2729
from django.contrib.auth.models import SiteProfileNotAvailable
2830
except ImportError:
@@ -83,10 +85,8 @@ def authenticate(self, session_info=None, attribute_mapping=None,
8385
use_name_id_as_username = getattr(
8486
settings, 'SAML_USE_NAME_ID_AS_USERNAME', False)
8587

86-
django_user_main_attribute = getattr(
87-
settings, 'SAML_DJANGO_USER_MAIN_ATTRIBUTE', 'username')
88-
django_user_main_attribute_lookup = getattr(
89-
settings, 'SAML_DJANGO_USER_MAIN_ATTRIBUTE_LOOKUP', '')
88+
django_user_main_attribute = saml_settings.SAML_DJANGO_USER_MAIN_ATTRIBUTE
89+
django_user_main_attribute_lookup = saml_settings.SAML_DJANGO_USER_MAIN_ATTRIBUTE_LOOKUP
9090

9191
logger.debug('attributes: %s', attributes)
9292
saml_user = None
@@ -97,11 +97,7 @@ def authenticate(self, session_info=None, attribute_mapping=None,
9797
else:
9898
logger.error('The nameid is not available. Cannot find user without a nameid.')
9999
else:
100-
logger.debug('attribute_mapping: %s', attribute_mapping)
101-
for saml_attr, django_fields in attribute_mapping.items():
102-
if (django_user_main_attribute in django_fields
103-
and saml_attr in attributes):
104-
saml_user = attributes[saml_attr][0]
100+
saml_user = self.get_attribute_value(django_user_main_attribute, attributes, attribute_mapping)
105101

106102
if saml_user is None:
107103
logger.error('Could not find saml_user value')
@@ -110,50 +106,21 @@ def authenticate(self, session_info=None, attribute_mapping=None,
110106
if not self.is_authorized(attributes, attribute_mapping):
111107
return None
112108

113-
user = None
114-
115109
main_attribute = self.clean_user_main_attribute(saml_user)
116110

117-
user_query_args = {
118-
django_user_main_attribute+django_user_main_attribute_lookup:
119-
main_attribute}
120-
user_create_defaults = {django_user_main_attribute: main_attribute}
121-
122111
# Note that this could be accomplished in one try-except clause, but
123112
# instead we use get_or_create when creating unknown users since it has
124113
# built-in safeguards for multiple threads.
125-
User = get_saml_user_model()
126-
if create_unknown_user:
127-
logger.debug('Check if the user "%s" exists or create otherwise',
128-
main_attribute)
129-
try:
130-
user, created = User.objects.get_or_create(
131-
defaults=user_create_defaults, **user_query_args)
132-
except MultipleObjectsReturned:
133-
logger.error("There are more than one user with %s = %s",
134-
django_user_main_attribute, main_attribute)
135-
return None
136-
137-
if created:
138-
logger.debug('New user created')
139-
user = self.configure_user(user, attributes, attribute_mapping)
140-
else:
141-
logger.debug('User updated')
142-
user = self.update_user(user, attributes, attribute_mapping)
143-
else:
144-
logger.debug('Retrieving existing user "%s"', main_attribute)
145-
try:
146-
user = User.objects.get(**user_query_args)
147-
user = self.update_user(user, attributes, attribute_mapping)
148-
except User.DoesNotExist:
149-
logger.error('The user "%s" does not exist', main_attribute)
150-
return None
151-
except MultipleObjectsReturned:
152-
logger.error("There are more than one user with %s = %s",
153-
django_user_main_attribute, main_attribute)
154-
return None
114+
return self.get_saml2_user(
115+
create_unknown_user, main_attribute, attributes, attribute_mapping)
155116

156-
return user
117+
def get_attribute_value(self, django_field, attributes, attribute_mapping):
118+
saml_user = None
119+
logger.debug('attribute_mapping: %s', attribute_mapping)
120+
for saml_attr, django_fields in attribute_mapping.items():
121+
if django_field in django_fields and saml_attr in attributes:
122+
saml_user = attributes[saml_attr][0]
123+
return saml_user
157124

158125
def is_authorized(self, attributes, attribute_mapping):
159126
"""Hook to allow custom authorization policies based on
@@ -170,6 +137,65 @@ def clean_user_main_attribute(self, main_attribute):
170137
"""
171138
return main_attribute
172139

140+
def get_user_query_args(self, main_attribute):
141+
django_user_main_attribute = getattr(
142+
settings, 'SAML_DJANGO_USER_MAIN_ATTRIBUTE', 'username')
143+
django_user_main_attribute_lookup = getattr(
144+
settings, 'SAML_DJANGO_USER_MAIN_ATTRIBUTE_LOOKUP', '')
145+
146+
return {
147+
django_user_main_attribute + django_user_main_attribute_lookup: main_attribute
148+
}
149+
150+
def get_saml2_user(self, create, main_attribute, attributes, attribute_mapping):
151+
if create:
152+
return self._get_or_create_saml2_user(main_attribute, attributes, attribute_mapping)
153+
154+
return self._get_saml2_user(main_attribute, attributes, attribute_mapping)
155+
156+
def _get_or_create_saml2_user(self, main_attribute, attributes, attribute_mapping):
157+
logger.debug('Check if the user "%s" exists or create otherwise',
158+
main_attribute)
159+
django_user_main_attribute = saml_settings.SAML_DJANGO_USER_MAIN_ATTRIBUTE
160+
django_user_main_attribute_lookup = saml_settings.SAML_DJANGO_USER_MAIN_ATTRIBUTE_LOOKUP
161+
user_query_args = self.get_user_query_args(main_attribute)
162+
user_create_defaults = {django_user_main_attribute: main_attribute}
163+
164+
User = get_saml_user_model()
165+
try:
166+
user, created = User.objects.get_or_create(
167+
defaults=user_create_defaults, **user_query_args)
168+
except MultipleObjectsReturned:
169+
logger.error("There are more than one user with %s = %s",
170+
django_user_main_attribute, main_attribute)
171+
return None
172+
173+
if created:
174+
logger.debug('New user created')
175+
user = self.configure_user(user, attributes, attribute_mapping)
176+
else:
177+
logger.debug('User updated')
178+
user = self.update_user(user, attributes, attribute_mapping)
179+
return user
180+
181+
def _get_saml2_user(self, main_attribute, attributes, attribute_mapping):
182+
User = get_saml_user_model()
183+
django_user_main_attribute = saml_settings.SAML_DJANGO_USER_MAIN_ATTRIBUTE
184+
user_query_args = self.get_user_query_args(main_attribute)
185+
186+
logger.debug('Retrieving existing user "%s"', main_attribute)
187+
try:
188+
user = User.objects.get(**user_query_args)
189+
user = self.update_user(user, attributes, attribute_mapping)
190+
except User.DoesNotExist:
191+
logger.error('The user "%s" does not exist', main_attribute)
192+
return None
193+
except MultipleObjectsReturned:
194+
logger.error("There are more than one user with %s = %s",
195+
django_user_main_attribute, main_attribute)
196+
return None
197+
return user
198+
173199
def configure_user(self, user, attributes, attribute_mapping):
174200
"""Configures a user after creation and returns the updated user.
175201
@@ -207,15 +233,8 @@ def update_user(self, user, attributes, attribute_mapping,
207233
try:
208234
for attr in django_attrs:
209235
if hasattr(user, attr):
210-
211-
user_attr = getattr(user, attr)
212-
if callable(user_attr):
213-
modified = user_attr(
214-
attributes[saml_attr])
215-
else:
216-
modified = self._set_attribute(
217-
user, attr, attributes[saml_attr][0])
218-
236+
modified = self._set_attribute(
237+
user, attr, attributes[saml_attr][0])
219238
user_modified = user_modified or modified
220239

221240
elif profile is not None and hasattr(profile, attr):

djangosaml2/settings.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from django.conf import settings
2+
3+
SAML_DJANGO_USER_MAIN_ATTRIBUTE = getattr(
4+
settings, 'SAML_DJANGO_USER_MAIN_ATTRIBUTE', 'username')
5+
SAML_DJANGO_USER_MAIN_ATTRIBUTE_LOOKUP = getattr(
6+
settings, 'SAML_DJANGO_USER_MAIN_ATTRIBUTE_LOOKUP', '')

0 commit comments

Comments
 (0)