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 }  "' )
170202 continue 
171- 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  =  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 
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