diff --git a/password_security/models/res_users.py b/password_security/models/res_users.py index 79c74418f2..2d90d58747 100644 --- a/password_security/models/res_users.py +++ b/password_security/models/res_users.py @@ -8,6 +8,7 @@ from odoo import _, api, fields, models from odoo.exceptions import UserError, ValidationError +from odoo.tools import groupby def delta_now(**kwargs): @@ -97,22 +98,21 @@ def _check_password(self, password): return True def _check_password_rules(self, password): - self.ensure_one() if not password: return True - company_id = self.company_id params = self.env["ir.config_parameter"].sudo() minlength = params.get_param("auth_password_policy.minlength", default=0) - password_regex = [ - "^", - "(?=.*?[a-z]){" + str(company_id.password_lower) + ",}", - "(?=.*?[A-Z]){" + str(company_id.password_upper) + ",}", - "(?=.*?\\d){" + str(company_id.password_numeric) + ",}", - r"(?=.*?[\W_]){" + str(company_id.password_special) + ",}", - ".{%d,}$" % int(minlength), - ] - if not re.search("".join(password_regex), password): - raise ValidationError(self.password_match_message()) + for company_id, users in groupby(self, lambda u: u.company_id): + password_regex = [ + "^", + "(?=.*?[a-z]){" + str(company_id.password_lower) + ",}", + "(?=.*?[A-Z]){" + str(company_id.password_upper) + ",}", + "(?=.*?\\d){" + str(company_id.password_numeric) + ",}", + r"(?=.*?[\W_]){" + str(company_id.password_special) + ",}", + ".{%d,}$" % int(minlength), + ] + if not re.search("".join(password_regex), password): + raise ValidationError(users[0].password_match_message()) return True diff --git a/password_security/tests/test_change_password.py b/password_security/tests/test_change_password.py index 3793c5d748..6c9874e0a8 100644 --- a/password_security/tests/test_change_password.py +++ b/password_security/tests/test_change_password.py @@ -1,6 +1,6 @@ # Copyright 2023 Onestein () # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). - +import re from unittest import mock from odoo import http @@ -134,3 +134,14 @@ def test_04_change_password_check_password_history(self): # Log in with new password: ensure we end up on the right page res_login2 = self.login("admin", "!asdQWE12345_4") self.assertEqual(res_login2.request.path_url, "/web") + + def test_20_write_password(self): + """Detects expected singleton errors writing passwords for more than one user""" + users = self.env["res.users"].search([], limit=2) + self.assertEqual(len(users), 2) + res = users.write({"password": "!asdQWE12345"}) + self.assertTrue(res) + + msg = re.escape(users[0].password_match_message()) + with self.assertRaisesRegex(ValidationError, msg): + users.write({"password": "12345678"})