From 2a57cd6629a75203de63f318f32882587779c137 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Fri, 20 Feb 2026 09:59:13 +0100 Subject: [PATCH] Use django authentication function to check password. see 3928 --- modoboa/admin/api/v1/tests.py | 14 +++++++++++--- modoboa/admin/tests/test_import_.py | 4 +++- modoboa/core/api/v1/serializers.py | 10 +++++----- modoboa/core/api/v2/serializers.py | 4 ++-- modoboa/imap_migration/auth_backends.py | 3 ++- 5 files changed, 23 insertions(+), 12 deletions(-) diff --git a/modoboa/admin/api/v1/tests.py b/modoboa/admin/api/v1/tests.py index fcb838b15..2a364e62e 100644 --- a/modoboa/admin/api/v1/tests.py +++ b/modoboa/admin/api/v1/tests.py @@ -10,6 +10,8 @@ from django.core.cache import cache from django.test import override_settings from django.urls import reverse +from django.contrib.auth import authenticate + from rest_framework.authtoken.models import Token from reversion.models import Version @@ -461,13 +463,17 @@ class AccountAPITestCase(ModoAPITestCase): account.refresh_from_db() account.mailbox.refresh_from_db() self.assertEqual(account.email, account.mailbox.full_address) - self.assertTrue(account.check_password("Toto1234")) + self.assertIsNot( + authenticate(username=account.username, password="Toto1234"), None + ) del data["password"] response = self.client.put(url, data, format="json") self.assertEqual(response.status_code, 200) account.refresh_from_db() - self.assertTrue(account.check_password("Toto1234")) + self.assertIsNot( + authenticate(username=account.username, password="Toto1234"), None + ) def test_update_account_with_no_mailbox(self): """Try to disable an account.""" @@ -577,7 +583,9 @@ class AccountAPITestCase(ModoAPITestCase): ) self.assertEqual(response.status_code, 200) account.refresh_from_db() - self.assertTrue(account.check_password("Toto1234")) + self.assertIsNot( + authenticate(username=account.username, password="Toto1234"), None + ) @mock.patch("ovh.Client.get") @mock.patch("ovh.Client.post") diff --git a/modoboa/admin/tests/test_import_.py b/modoboa/admin/tests/test_import_.py index 1041021cf..061153fbd 100644 --- a/modoboa/admin/tests/test_import_.py +++ b/modoboa/admin/tests/test_import_.py @@ -8,6 +8,8 @@ from django.core.management import call_command from django.core.management.base import CommandError from django.urls import reverse +from django.contrib.auth import authenticate + from modoboa.core import factories as core_factories from modoboa.core.models import User from modoboa.lib.tests import ModoAPITestCase @@ -335,4 +337,4 @@ alias; alias1@test.com; True; user1@test.com ) call_command("modo", "import", "--crypt-passwords", test_file) user = User.objects.get(username="user1@test.com") - self.assertTrue(user.check_password("toto")) + self.assertIsNot(authenticate(username=user.username, password="toto"), None) diff --git a/modoboa/core/api/v1/serializers.py b/modoboa/core/api/v1/serializers.py index 2dccd111f..6aaeb529e 100644 --- a/modoboa/core/api/v1/serializers.py +++ b/modoboa/core/api/v1/serializers.py @@ -2,7 +2,7 @@ import logging -from django.contrib.auth import password_validation +from django.contrib.auth import authenticate, password_validation from django.core.exceptions import ValidationError from django.utils.html import escape from django.utils.translation import gettext as _ @@ -31,7 +31,7 @@ class AccountPasswordSerializer(serializers.ModelSerializer): """Check password.""" authentication_type = param_tools.get_global_parameter("authentication_type") if authentication_type != "ldap": - check = self.instance.check_password(value) + check = authenticate(username=self.instance.username, password=value) else: from django_auth_ldap.backend import LDAPBackend @@ -80,9 +80,9 @@ class CheckPasswordTFASerializer(serializers.Serializer): password = serializers.CharField() - def validate_password(self, value): - user = self.context["user"] - if not user.check_password(value): + def validate_password(self, value: str) -> str: + user: models.User = self.context["user"] + if not authenticate(username=user.username, password=value): msg = _( "Failed TFA settings editing attempt from '%(addr)s' as user '%(user)s'" ) % { diff --git a/modoboa/core/api/v2/serializers.py b/modoboa/core/api/v2/serializers.py index c37134a0e..480f4bad7 100644 --- a/modoboa/core/api/v2/serializers.py +++ b/modoboa/core/api/v2/serializers.py @@ -6,7 +6,7 @@ import oath from django.conf import settings from django.db.models import Q -from django.contrib.auth import password_validation +from django.contrib.auth import authenticate, password_validation from django.contrib.sites.shortcuts import get_current_site from django.contrib.auth.tokens import default_token_generator from django.core.mail import send_mail @@ -434,7 +434,7 @@ class CheckPasswordSerializer(serializers.Serializer): def validate_password(self, value): user = self.context["user"] - if not user.check_password(value): + if not authenticate(username=user.username, password=value): raise serializers.ValidationError(_("Invalid password")) return value diff --git a/modoboa/imap_migration/auth_backends.py b/modoboa/imap_migration/auth_backends.py index fd84b4969..8005b1368 100644 --- a/modoboa/imap_migration/auth_backends.py +++ b/modoboa/imap_migration/auth_backends.py @@ -3,6 +3,7 @@ import imaplib import ssl +from django.contrib.auth import authenticate from django.utils.encoding import smart_bytes, smart_str from django.utils.translation import gettext as _ @@ -94,7 +95,7 @@ class IMAPBackend: # No migration => either someone else account, or # migration is done return None - if not user.check_password(password): + if not authenticate(username=user.username, password=password): # User may have changed its password on modoboa # Remote password and local now differs # We block the connection in that case