# Copyright (C) 2018-2024 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later import hashlib from collections import OrderedDict from django.conf import settings from django.contrib.auth.hashers import PBKDF2PasswordHasher, mask_hash from django.utils.crypto import constant_time_compare from django.utils.translation import gettext_lazy as _ from note_kfet.middlewares import get_current_request class CustomNK15Hasher(PBKDF2PasswordHasher): """ Permet d'importer les mots de passe depuis la Note KFet 2015. Si un hash de mot de passe est de la forme : `custom_nk15$$` où est un entier quelconque (symbolisant normalement un nombre d'itérations) et le hash du mot de passe dans la Note Kfet 2015, alors ce hasher va vérifier le mot de passe. N'ayant pas la priorité (cf note_kfet/settings/base.py), le mot de passe sera converti automatiquement avec l'algorithme PBKDF2. """ algorithm = "custom_nk15" def must_update(self, encoded): if settings.DEBUG: # Small hack to let superusers to impersonate people. # Don't change their password. request = get_current_request() current_user = request.user if current_user is not None and current_user.is_superuser: return False return True def verify(self, password, encoded): if settings.DEBUG: # Small hack to let superusers to impersonate people. # If a superuser is already connected, let him/her log in as another person. request = get_current_request() current_user = request.user if current_user is not None and current_user.is_superuser\ and request.session.get("permission_mask", -1) >= 42: return True if '|' in encoded: salt, db_hashed_pass = encoded.split('$')[2].split('|') return constant_time_compare(hashlib.sha256((salt + password).encode("utf-8")).hexdigest(), db_hashed_pass) return super().verify(password, encoded) def safe_summary(self, encoded): # Displayed information in Django Admin. if '|' in encoded: salt, db_hashed_pass = encoded.split('$')[2].split('|') return OrderedDict([ (_('algorithm'), 'custom_nk15'), (_('iterations'), '1'), (_('salt'), mask_hash(salt)), (_('hash'), mask_hash(db_hashed_pass)), ]) return super().safe_summary(encoded) class DebugSuperuserBackdoor(PBKDF2PasswordHasher): """ In debug mode and during the beta, superusers can login into other accounts for tests. """ def must_update(self, encoded): return False def verify(self, password, encoded): if settings.DEBUG: # Small hack to let superusers to impersonate people. # If a superuser is already connected, let him/her log in as another person. request = get_current_request() current_user = request.user if current_user is not None and current_user.is_superuser\ and request.session.get("permission_mask", -1) >= 42: return True return super().verify(password, encoded)