Skip to content

Commit 0b44f67

Browse files
committed
fix: Correction de la logique de changement de mot de passe et mise à jour des messages d'erreur
refactor: Amélioration de la clarté du code et gestion des erreurs. Séparation des responsabilités méthodologiques (routes et login/chag_pwd des utilisateurs). Création d'un service dédié pour le changement de mot de passe et le login utilisateur. fix: Correction de la logique de changement de mot de passe et mise à jour des messages d'erreur
1 parent 06595c6 commit 0b44f67

3 files changed

Lines changed: 110 additions & 55 deletions

File tree

app_acfc/application.py

Lines changed: 17 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -392,9 +392,9 @@ def login() -> Any:
392392
try:
393393
if not user_to_authenticate.authenticate():
394394
return render_template(LOGIN['page'], title=LOGIN['title'], context=LOGIN['context'], message=INVALID)
395-
elif user_to_authenticate.user_data.is_chg_mdp:
395+
elif user_to_authenticate.is_chg_mdp:
396396
return render_template(LOGIN['page'], title=LOGIN['title'], context='change_password',
397-
message="Veuillez changer votre mot de passe.", username=user_to_authenticate.user_data.pseudo)
397+
message="Veuillez changer votre mot de passe.", username=user_to_authenticate.user_pseudo)
398398
else:
399399
return redirect(url_for('dashboard'))
400400
except Exception as e:
@@ -639,46 +639,24 @@ def chg_pwd() -> Any:
639639
"""
640640
Changement de mot de passe utilisateur.
641641
"""
642+
def _get_key_message(param: Dict[str, bool]) -> str:
643+
for key, value in param.items():
644+
if value is False:
645+
return key
646+
return ''
647+
648+
# === Gestion de la méthode POST ===
642649
if request.method == 'POST':
643650
# Récupération des données du formulaire
644-
username = request.form.get('username', '')
645-
old_password = request.form.get('old_password', '')
646-
new_password = request.form.get('new_password', '')
647-
confirm_password = request.form.get('confirm_password', '')
648-
649-
# Validation des données
650-
if not all([username, old_password, new_password, confirm_password]):
651-
return render_template(CHG_PWD['page'], title=CHG_PWD['title'], context=CHG_PWD['context'],
652-
message='Merci de remplir tous les champs.', username=username)
653-
654-
if new_password != confirm_password:
655-
return render_template(CHG_PWD['page'], title=CHG_PWD['title'], context=CHG_PWD['context'],
656-
message="Les mots de passe ne correspondent pas.", username=username)
657-
658-
if new_password == old_password:
659-
return render_template(CHG_PWD['page'], title=CHG_PWD['title'], context=CHG_PWD['context'],
660-
message="Le nouveau mot de passe ne peut pas être identique à l'ancien.", username=username)
661-
662-
# Vérification de l'ancien mot de passe
663-
db_session = SessionBdD()
664-
user = db_session.query(User).filter_by(pseudo=username).first()
665-
if not user or not ph_acfc.verify_password(old_password, user.sha_mdp):
651+
user_to_chg_pwd = AuthenticationService(request)
652+
chg_pwd_is_ok = user_to_chg_pwd.chg_pwd()
653+
if not chg_pwd_is_ok:
654+
key_message = _get_key_message(user_to_chg_pwd.pwd_param)
666655
return render_template(CHG_PWD['page'], title=CHG_PWD['title'], context=CHG_PWD['context'],
667-
message='Ancien mot de passe incorrect.', username=username)
668-
669-
# Hashage du nouveau mot de passe
670-
user.sha_mdp = ph_acfc.hash_password(new_password)
671-
672-
# retrait de la nécessité de changer le mot de passe
673-
user.is_chg_mdp = False
674-
try:
675-
db_session.commit()
676-
except Exception as e:
677-
db_session.rollback()
678-
return render_template(CHG_PWD['page'], title=CHG_PWD['title'], context='500', message=str(e))
679-
680-
return redirect(url_for('login'))
681-
656+
message=user_to_chg_pwd.pwd_param_messages[key_message], username=user_to_chg_pwd.user)
657+
else:
658+
return redirect(url_for('login'))
659+
# === Gestion de toutes les autres méthodes ===
682660
return render_template(ERROR400['page'], title=ERROR400['title'], context=ERROR400['context'], message=INVALID)
683661

684662
# ====================================================================

app_acfc/services.py

Lines changed: 92 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@
1919
from argon2 import PasswordHasher
2020
from argon2.exceptions import VerifyMismatchError
2121
from flask import Flask, session
22+
from sqlalchemy.orm import Session as SessionBdDType
2223
from os import getenv
2324
from flask import Request
24-
from typing import Any, Dict, Optional
25+
from typing import Any, Dict, Tuple
2526
from logs.logger import acfc_log, INFO
2627

2728
LOG_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}.\nErreur: {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}.\nErreur: {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+

mariadb/init_db.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ CREATE TABLE IF NOT EXISTS `99_users` (
2222
INSERT INTO `99_users` (
2323
`prenom`, `nom`, `pseudo`, `sha_mdp`, `is_chg_mdp`, `email`, `telephone`, `is_active`, `permission`, `debut`, `nb_errors`, `is_locked`
2424
) VALUES (
25-
'Admin', 'istrateur', 'admin', '$argon2id$v=19$m=65536,t=4,p=3$5MRAo5AnOW3LV9gR/jRNFg$uWgIeoC6ZpyBowO/aNLTA2nndXfeGkEnsY+nsfCEzTc', TRUE, 'admin@example.com', '0000000000', TRUE, '1234567', CURRENT_DATE, 0, FALSE
25+
'Admin', 'istrateur', 'admin', '$argon2id$v=19$m=65536,t=4,p=3$5MRAo5AnOW3LV9gR/jRNFg$uWgIeoC6ZpyBowO/aNLTA2nndXfeGkEnsY+nsfCEzTc', 1, 'admin@example.com', '0000000000', 1, '1234567', CURRENT_DATE, 0, 0
2626
)
2727
ON DUPLICATE KEY UPDATE
2828
`sha_mdp` = VALUES(`sha_mdp`),

0 commit comments

Comments
 (0)