1919from argon2 import PasswordHasher
2020from argon2 .exceptions import VerifyMismatchError
2121from flask import Flask , session
22+ from sqlalchemy .orm import Session as SessionBdDType
2223from os import getenv
2324from flask import Request
24- from typing import Any , Dict , Optional
25+ from typing import Any , Dict , Tuple
2526from logs .logger import acfc_log , INFO
2627
2728LOG_LOGIN_FILE = 'login.log'
@@ -179,13 +180,27 @@ class AuthenticationService:
179180 - logout: Déconnecte l'utilisateur
180181
181182 """
182- def __init__ (self , request_object : Request ):
183+ def __init__ (self , request_object : Request , chg_mdp : bool = False ):
183184 self .user = request_object .form .get ('username' , '' )
184185 self .pwd = request_object .form .get ('password' , '' )
186+ self .old_pwd = request_object .form .get ('old_password' , '' )
187+ self .new_pwd = request_object .form .get ('new_password' , '' )
188+ self .confirm_new_pwd = request_object .form .get ('confirm_password' , '' )
185189 self .authenticated : bool = False
186190 self .user_dict : Dict [str , Any ]
187- self .user_data : User
188191 self .existing_user : bool
192+ self .is_chg_mdp : bool = False
193+ self .user_pseudo : str = ""
194+ self .pwd_param : Dict [str , bool ] = {}
195+ self .pwd_param_messages : Dict [str , str ] = {
196+ 'all_field' : 'Merci de remplir tous les champs.' ,
197+ 'pwd_match' : "Les mots de passe ne correspondent pas." ,
198+ 'pwd_changed' : "Le nouveau mot de passe ne peut pas être identique à l'ancien." ,
199+ 'authenticated_user' : "Merci de renseigner correctement l'ancien mot de passe" ,
200+ 'db_unerror' : "Erreur lors de la mise à jour en base de données." ,
201+ 'user_found' : "Utilisateur non trouvé."
202+ }
203+
189204
190205 def _create_session (self , user : User ):
191206 """
@@ -200,7 +215,7 @@ def _create_session(self, user: User):
200215 session ['last_name' ] = user .nom
201216 session ['first_name' ] = user .prenom
202217 session ['email' ] = user .email
203- session ['tel' ] = user .tel
218+ session ['tel' ] = user .telephone
204219 session ['habilitations' ] = user .permission
205220
206221 def _log_result (self , message : str , level : int = INFO ):
@@ -216,6 +231,7 @@ def _log_result(self, message: str, level: int = INFO):
216231 specific_logger = LOG_LOGIN_FILE ,
217232 zone_log = LOG_LOGIN_FILE ,
218233 db_log = True )
234+
219235 def _bad_password (self , user : User ):
220236 """
221237 Gère un mot de passe incorrect pour un utilisateur existant.
@@ -238,12 +254,23 @@ def _good_password(self, user: User, ph_acfc: PasswordService):
238254 self .existing_user = True
239255 self .authenticated = True
240256 self .user_dict = user .to_dict ()
241- self .user_data = user
257+ # Stocker les propriétés nécessaires avant de détacher l'objet de la session
258+ self .is_chg_mdp = user .is_chg_mdp
259+ acfc_log .log_to_file (level = INFO ,
260+ message = f'Changement de mot de passe requis pour l\' utilisateur: { self .is_chg_mdp } ' ,
261+ specific_logger = LOG_LOGIN_FILE ,
262+ zone_log = LOG_LOGIN_FILE ,
263+ db_log = True )
264+ self .user_pseudo = user .pseudo
242265 user .nb_errors = 0
243266 user .is_locked = False
244- user .is_chg_mdp = False
245- if ph_acfc .needs_rehash (user .sha_mdp ): user .sha_mdp = ph_acfc .hash_password (user .mot_de_passe )
267+ if ph_acfc .needs_rehash (user .sha_mdp ): user .sha_mdp = ph_acfc .hash_password (user .sha_mdp )
246268
269+ def _get_user (self ) -> Tuple [User | None , SessionBdDType ]:
270+ from modeles import SessionBdD
271+ session_db = SessionBdD ()
272+ user = session_db .query (User ).filter_by (pseudo = self .user ).first ()
273+ return user , session_db
247274
248275 def authenticate (self ) -> bool :
249276 """
@@ -255,16 +282,14 @@ def authenticate(self) -> bool:
255282 :Returns:
256283 None
257284 """
258- from modeles import SessionBdD
259- session_db = SessionBdD ()
260- user = session_db .query (User ).filter_by (pseudo = self .user ).first ()
285+ user , session_db = self ._get_user ()
261286 # Instance du service de gestion des mots de passe (hachage Argon2)
262287 ph_acfc = PasswordService ()
263288 try :
264- if user and ph_acfc .verify_password (self .pwd , user .mot_de_passe ) and (not user .is_locked and user .is_active ):
289+ if user and ph_acfc .verify_password (self .pwd , user .sha_mdp ) and (not user .is_locked and user .is_active ):
265290 self ._good_password (user , ph_acfc )
266291 self ._create_session (user )
267- self ._log_result (message = f'début de session pour l\' utilisateur: { self .user_data . pseudo if self .user_data else "inconnu" } ' )
292+ self ._log_result (message = f'début de session pour l\' utilisateur: { self .user_pseudo if self .user_pseudo else "inconnu" } ' )
268293 statement = True
269294 elif user and user .is_locked :
270295 self ._log_result (message = f'Utilisateur verrouillé: { self .user } ' )
@@ -280,14 +305,65 @@ def authenticate(self) -> bool:
280305 self ._log_result (message = f'Utilisateur non trouvé: { self .user } ' )
281306 statement = False
282307 session_db .commit ()
283- except Exception :
308+ # Détacher l'objet user de la session si il existe
309+ if user is not None :
310+ session_db .expunge (user )
311+ except Exception as e :
284312 session_db .rollback ()
285- self ._log_result (message = f'Erreur lors de l\' authentification de l\' utilisateur: { self .user } ' , level = 40 )
313+ self ._log_result (message = f'Erreur lors de l\' authentification de l\' utilisateur: { self .user } . \n Erreur: { e } ' , level = 40 )
286314 statement = False
287315 finally :
288316 # Fermeture de la session de base de données
289317 session_db .close ()
290318 return statement
319+
320+ def _validate_chg_pwd_form (self , user : User , pwd_hasher : PasswordService ):
321+ if not all ([self .user , self .old_pwd , self .new_pwd , self .confirm_new_pwd ]):
322+ self .pwd_param ['all_field' ] = False
323+ return False
324+ elif self .new_pwd != self .confirm_new_pwd :
325+ self .pwd_param ['pwd_match' ] = False
326+ return False
327+ elif self .new_pwd == self .old_pwd :
328+ self .pwd_param ['pwd_changed' ] = False
329+ return False
330+ elif not pwd_hasher .verify_password (self .old_pwd , user .sha_mdp ):
331+ self .pwd_param ['authenticated_user' ] = False
332+ return False
333+ else :
334+ self .pwd_param ['all_field' ] = True
335+ self .pwd_param ['pwd_match' ] = True
336+ self .pwd_param ['pwd_changed' ] = True
337+ self .pwd_param ['authenticated_user' ] = True
338+ return True
339+
340+ def chg_pwd (self ) -> bool :
341+ user , session_db = self ._get_user ()
342+ ph_acfc = PasswordService ()
343+ if not self ._validate_chg_pwd_form (user , ph_acfc ):
344+ return False
345+ elif user :
346+ try :
347+ user .sha_mdp = ph_acfc .hash_password (self .new_pwd )
348+ user .is_chg_mdp = False
349+ user .nb_errors = 0
350+ user .is_locked = False
351+ session_db .commit ()
352+ self ._log_result (message = f'Mot de passe changé pour l\' utilisateur: { self .user } .' )
353+ return True
354+
355+ except Exception as e :
356+ session_db .rollback ()
357+ self ._log_result (message = f'Erreur lors du changement de mot de passe de l\' utilisateur: { self .user } .\n Erreur: { e } ' , level = 40 )
358+ self .pwd_param ['db_unerror' ] = False
359+ return False
360+
361+ finally :
362+ session_db .close ()
363+ else :
364+ self ._log_result (message = f'Utilisateur non trouvé: { self .user } .' )
365+ self .pwd_param ['user_found' ] = False
366+ return False
291367
292368 def is_authenticated (self ) -> bool :
293369 """
@@ -296,4 +372,5 @@ def is_authenticated(self) -> bool:
296372 Returns:
297373 bool: True si l'utilisateur est authentifié, False sinon
298374 """
299- return self .authenticated
375+ return self .authenticated
376+
0 commit comments