2424from django .core .exceptions import (ImproperlyConfigured ,
2525 MultipleObjectsReturned )
2626
27+ from .signals import authenticate , pre_user_save , post_user_save
28+
2729
2830logger = logging .getLogger ('djangosaml2' )
2931
@@ -123,6 +125,13 @@ def authenticate(self, request, session_info=None, attribute_mapping=None, creat
123125
124126 if not self .is_authorized (attributes , attribute_mapping , idp_entityid , assertion_info ):
125127 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 )
126135 return None
127136
128137 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
141150 user = self ._update_user (
142151 user , attributes , attribute_mapping , force_save = created )
143152
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 :
145162 return user
146163
147164 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
156173 if not attribute_mapping :
157174 # Always save a brand new user instance
158175 if user .pk is None :
176+ pre_user_save .send (sender = self , user = user , attributes = attributes )
159177 user = self .save_user (user )
178+ post_user_save .send (sender = self , user = user , attributes = attributes )
160179 return user
161180
162181 # 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 :
164196 has_updated_fields = False
165197 for saml_attr , django_attrs in attribute_mapping .items ():
166198 attr_value_list = attributes .get (saml_attr )
167199 if not attr_value_list :
168200 logger .debug (
169201 f'Could not find value for "{ saml_attr } ", not updating fields "{ django_attrs } "' )
170- continue
171-
202+ return has_updated_fields
172203 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 = has_updated_fields or self .lookup_and_set_attribute (
205+ user , attr , attr_value_list
206+ )
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
199224
200225 def clean_attributes (self , attributes : dict , idp_entityid : str , ** kwargs ) -> dict :
201226 """ Hook to clean or filter attributes from the SAML response. No-op by default. """
0 commit comments