24
24
from django .core .exceptions import (ImproperlyConfigured ,
25
25
MultipleObjectsReturned )
26
26
27
+ from .signals import authenticate , pre_user_save , post_user_save
28
+
27
29
28
30
logger = logging .getLogger ('djangosaml2' )
29
31
@@ -123,6 +125,13 @@ def authenticate(self, request, session_info=None, attribute_mapping=None, creat
123
125
124
126
if not self .is_authorized (attributes , attribute_mapping , idp_entityid , assertion_info ):
125
127
logger .error ('Request not authorized' )
128
+ authenticate .send (sender = self ,
129
+ request = request ,
130
+ is_authorized = False ,
131
+ can_authenticate = None ,
132
+ user = None ,
133
+ user_created = None ,
134
+ attributes = attributes )
126
135
return None
127
136
128
137
user_lookup_key , user_lookup_value = self ._extract_user_identifier_params (
@@ -141,7 +150,15 @@ def authenticate(self, request, session_info=None, attribute_mapping=None, creat
141
150
user = self ._update_user (
142
151
user , attributes , attribute_mapping , force_save = created )
143
152
144
- if self .user_can_authenticate (user ):
153
+ can_authenticate = self .user_can_authenticate (user )
154
+ authenticate .send (sender = self ,
155
+ request = request ,
156
+ is_authorized = True ,
157
+ can_authenticate = can_authenticate ,
158
+ user = user ,
159
+ user_created = created ,
160
+ attributes = attributes )
161
+ if can_authenticate :
145
162
return user
146
163
147
164
def _update_user (self , user , attributes : dict , attribute_mapping : dict , force_save : bool = False ):
@@ -156,46 +173,54 @@ def _update_user(self, user, attributes: dict, attribute_mapping: dict, force_sa
156
173
if not attribute_mapping :
157
174
# Always save a brand new user instance
158
175
if user .pk is None :
176
+ pre_user_save .send (sender = self , user = user , attributes = attributes )
159
177
user = self .save_user (user )
178
+ post_user_save .send (sender = self , user = user , attributes = attributes )
160
179
return user
161
180
162
181
# Lookup key
163
- user_lookup_key = self ._user_lookup_attribute
182
+ has_updated_fields = self .lookup_and_set_attributes (user , attributes , attribute_mapping )
183
+
184
+ if has_updated_fields or force_save :
185
+ pre_user_save .send (sender = self , user = user , attributes = attributes )
186
+ user = self .save_user (user )
187
+ post_user_save .send (sender = self , user = user , attributes = attributes )
188
+
189
+ return user
190
+
191
+ # ################################################
192
+ # Methods to override by end-users in subclasses #
193
+ # ################################################
194
+
195
+ def lookup_and_set_attributes (self , user , attributes : dict , attribute_mapping : dict ) -> bool :
164
196
has_updated_fields = False
165
197
for saml_attr , django_attrs in attribute_mapping .items ():
166
198
attr_value_list = attributes .get (saml_attr )
167
199
if not attr_value_list :
168
200
logger .debug (
169
201
f'Could not find value for "{ saml_attr } ", not updating fields "{ django_attrs } "' )
170
202
continue
171
-
172
203
for attr in django_attrs :
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 ):
179
- user_attr = getattr (user , attr )
180
- if callable (user_attr ):
181
- modified = user_attr (attr_value_list )
182
- else :
183
- modified = set_attribute (
184
- user , attr , attr_value_list [0 ])
185
-
186
- has_updated_fields = has_updated_fields or modified
187
- else :
188
- logger .debug (
189
- f'Could not find attribute "{ attr } " on user "{ user } "' )
190
-
191
- if has_updated_fields or force_save :
192
- user = self .save_user (user )
193
-
194
- return user
195
-
196
- # ############################################
197
- # Hooks to override by end-users in subclasses
198
- # ############################################
204
+ has_updated_fields = self .lookup_and_set_attribute (
205
+ user , attr , attr_value_list
206
+ ) or has_updated_fields
207
+ return has_updated_fields
208
+
209
+ def lookup_and_set_attribute (self , user , attr , attr_value_list ) -> bool :
210
+ if attr == self ._user_lookup_attribute :
211
+ # Don't update user_lookup_key (e.g. username) (issue #245)
212
+ # It was just used to find/create this user and might have
213
+ # been changed by `clean_user_main_attribute`
214
+ return False
215
+ elif hasattr (user , attr ):
216
+ user_attr = getattr (user , attr )
217
+ if callable (user_attr ):
218
+ return user_attr (attr_value_list )
219
+ else :
220
+ return set_attribute (user , attr , attr_value_list [0 ])
221
+ else :
222
+ logger .debug (f'Could not find attribute "{ attr } " on user "{ user } "' )
223
+ return False
199
224
200
225
def clean_attributes (self , attributes : dict , idp_entityid : str , ** kwargs ) -> dict :
201
226
""" Hook to clean or filter attributes from the SAML response. No-op by default. """
0 commit comments