diff --git a/apps/users/models/user.py b/apps/users/models/user.py index 715f02b9d..97a9e3d6d 100644 --- a/apps/users/models/user.py +++ b/apps/users/models/user.py @@ -7,8 +7,6 @@ import string import random import datetime -from functools import partial - from django.conf import settings from django.contrib.auth.models import AbstractUser from django.contrib.auth.hashers import check_password, make_password @@ -30,7 +28,7 @@ from users.exceptions import MFANotEnabled from ..signals import post_user_change_password -__all__ = ['User'] +__all__ = ['User', 'UserPasswordHistory'] logger = get_logger(__file__) @@ -83,12 +81,6 @@ class AuthMixin: else: return False - def save_history_password(self, password): - UserPasswordHistory.objects.create( - user=self, password=make_password(password), - date_created=self.date_password_last_updated - ) - def is_public_key_valid(self): """ Check if the user's ssh public key is valid. @@ -771,3 +763,9 @@ class UserPasswordHistory(models.Model): user = models.ForeignKey("users.User", related_name='history_passwords', on_delete=models.CASCADE, verbose_name=_('User')) date_created = models.DateTimeField(auto_now_add=True, verbose_name=_("Date created")) + + def __str__(self): + return f'{self.user} set at {self.date_created}' + + def __repr__(self): + return self.__str__() diff --git a/apps/users/serializers/profile.py b/apps/users/serializers/profile.py index 261dd6f01..c1caf1f99 100644 --- a/apps/users/serializers/profile.py +++ b/apps/users/serializers/profile.py @@ -39,8 +39,6 @@ class UserUpdatePasswordSerializer(serializers.ModelSerializer): limit_count = settings.OLD_PASSWORD_HISTORY_LIMIT_COUNT msg = _('The new password cannot be the last {} passwords').format(limit_count) raise serializers.ValidationError(msg) - else: - self.instance.save_history_password(value) return value def validate_new_password_again(self, value): diff --git a/apps/users/signals_handler.py b/apps/users/signals_handler.py index 887531f45..9831367fc 100644 --- a/apps/users/signals_handler.py +++ b/apps/users/signals_handler.py @@ -6,17 +6,33 @@ from django_auth_ldap.backend import populate_user from django.conf import settings from django.core.exceptions import PermissionDenied from django_cas_ng.signals import cas_user_authenticated +from django.db.models.signals import post_save from jms_oidc_rp.signals import openid_create_or_update_user from common.utils import get_logger from .signals import post_user_create -from .models import User +from .models import User, UserPasswordHistory logger = get_logger(__file__) +@receiver(post_save, sender=User) +def save_passwd_change(sender, instance: User, **kwargs): + passwds = UserPasswordHistory.objects.filter(user=instance).order_by('-date_created')\ + .values_list('password', flat=True)[:int(settings.OLD_PASSWORD_HISTORY_LIMIT_COUNT)] + + for p in passwds: + if instance.password == p: + break + else: + UserPasswordHistory.objects.create( + user=instance, password=instance.password, + date_created=instance.date_password_last_updated + ) + + @receiver(post_user_create) def on_user_create(sender, user=None, **kwargs): logger.debug("Receive user `{}` create signal".format(user.name)) diff --git a/apps/users/views/profile/reset.py b/apps/users/views/profile/reset.py index 356694020..ba9cfd9b7 100644 --- a/apps/users/views/profile/reset.py +++ b/apps/users/views/profile/reset.py @@ -111,8 +111,6 @@ class UserResetPasswordView(FormView): error = _('* The new password cannot be the last {} passwords').format(limit_count) form.add_error('new_password', error) return self.form_invalid(form) - else: - user.save_history_password(password) user.reset_password(password) User.expired_reset_password_token(token)