diff --git a/password_security/README.rst b/password_security/README.rst index eff705daec..7bcb717beb 100644 --- a/password_security/README.rst +++ b/password_security/README.rst @@ -7,7 +7,7 @@ Password Security !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:dc29155c73a519d3732e2806f60bd11ebb31cd8c181ebd5918e4bc68080d37aa + !! source digest: sha256:5f0bed48b7eca2655dceb715c14f64fd6a2703a6447e4f8f0401072dc03c3933 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png @@ -59,18 +59,19 @@ any user in that company. These are defined at the company level: -===================== ======= =================================================== - Name Default Description -===================== ======= =================================================== - password_expiration 60 Days until passwords expire - password_length 12 Minimum number of characters in password - password_lower 0 Minimum number of lowercase letter in password - password_upper 0 Minimum number of uppercase letters in password - password_numeric 0 Minimum number of number in password - password_special 0 Minimum number of unique special character in password - password_history 30 Disallow reuse of this many previous passwords - password_minimum 24 Amount of hours that must pass until another reset -===================== ======= =================================================== +========================= ======= =================================================== + Name Default Description +========================= ======= =================================================== + password_policy_enabled False Enables password security requirements + password_expiration 60 Days until passwords expire + password_length 12 Minimum number of characters in password + password_lower 0 Minimum number of lowercase letter in password + password_upper 0 Minimum number of uppercase letters in password + password_numeric 0 Minimum number of number in password + password_special 0 Minimum number of unique special character in password + password_history 30 Disallow reuse of this many previous passwords + password_minimum 24 Amount of hours that must pass until another reset +========================= ======= =================================================== Usage ===== @@ -120,6 +121,9 @@ Contributors * `Onestein `_: * Andrea Stirpe +* `twio.tech `_: + * Dawn Hwang + Maintainers ~~~~~~~~~~~ diff --git a/password_security/__manifest__.py b/password_security/__manifest__.py index 6b1391d6cd..208de91f20 100644 --- a/password_security/__manifest__.py +++ b/password_security/__manifest__.py @@ -5,7 +5,7 @@ { "name": "Password Security", "summary": "Allow admin to set password security requirements.", - "version": "16.0.1.0.0", + "version": "16.0.1.1.0", "author": "LasLabs, " "Onestein, " "Kaushal Prajapati, " diff --git a/password_security/migrations/16.0.1.1.0/post-migration.py b/password_security/migrations/16.0.1.1.0/post-migration.py new file mode 100644 index 0000000000..fc29c233fe --- /dev/null +++ b/password_security/migrations/16.0.1.1.0/post-migration.py @@ -0,0 +1,17 @@ +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl) + +import logging + +from odoo import SUPERUSER_ID, api + +_logger = logging.getLogger(__name__) + + +def migrate(cr, version): + if not version: + return + env = api.Environment(cr, SUPERUSER_ID, {}) + companies = env["res.company"].with_context(active_test=False).search([]) + _logger.info("Enable the password policy on %s companies", len(companies)) + _logger.info(companies.mapped("name")) + companies.write({"password_policy_enabled": True}) diff --git a/password_security/models/res_company.py b/password_security/models/res_company.py index 031563efdc..263ad72306 100644 --- a/password_security/models/res_company.py +++ b/password_security/models/res_company.py @@ -8,6 +8,11 @@ class ResCompany(models.Model): _inherit = "res.company" + password_policy_enabled = fields.Boolean( + "Password Policy", + default=False, + help="Enable password security requirements", + ) password_expiration = fields.Integer( "Days", default=60, diff --git a/password_security/models/res_config_settings.py b/password_security/models/res_config_settings.py index 3bc6c93052..a2ea315801 100644 --- a/password_security/models/res_config_settings.py +++ b/password_security/models/res_config_settings.py @@ -6,6 +6,9 @@ class ResConfigSettings(models.TransientModel): _inherit = "res.config.settings" + password_policy_enabled = fields.Boolean( + related="company_id.password_policy_enabled", readonly=False + ) password_expiration = fields.Integer( related="company_id.password_expiration", readonly=False ) diff --git a/password_security/models/res_users.py b/password_security/models/res_users.py index 8a5213e4b6..cc608c51ed 100644 --- a/password_security/models/res_users.py +++ b/password_security/models/res_users.py @@ -36,6 +36,10 @@ def write(self, vals): def get_password_policy(self): data = super(ResUsers, self).get_password_policy() company_id = self.env.user.company_id + + if not company_id.password_policy_enabled: + return data + data.update( { "password_lower": company_id.password_lower, @@ -49,10 +53,10 @@ def get_password_policy(self): def _check_password_policy(self, passwords): result = super(ResUsers, self)._check_password_policy(passwords) - for password in passwords: + for user, password in zip(self, passwords): if not password: continue - self._check_password(password) + user._check_password(password) return result @@ -92,6 +96,8 @@ def password_match_message(self): return "\r".join(message) def _check_password(self, password): + if not self.company_id.password_policy_enabled: + return True self._check_password_rules(password) self._check_password_history(password) return True @@ -118,6 +124,9 @@ def _check_password_rules(self, password): def _password_has_expired(self): self.ensure_one() + if not self.company_id.password_policy_enabled: + return False + if not self.password_write_date: return True @@ -140,6 +149,9 @@ def _validate_pass_reset(self): :return: True on allowed reset """ for user in self: + if not user.company_id.password_policy_enabled: + continue + pass_min = user.company_id.password_minimum if pass_min <= 0: continue @@ -180,6 +192,9 @@ def _set_encrypted_password(self, uid, pw): """It saves password crypt history for history rules""" res = super(ResUsers, self)._set_encrypted_password(uid, pw) + if not self.browse(uid).company_id.password_policy_enabled: + return res + self.env["res.users.pass.history"].create( { "user_id": uid, diff --git a/password_security/readme/CONFIGURE.rst b/password_security/readme/CONFIGURE.rst index a9464d271a..be8c0989af 100644 --- a/password_security/readme/CONFIGURE.rst +++ b/password_security/readme/CONFIGURE.rst @@ -9,15 +9,16 @@ any user in that company. These are defined at the company level: -===================== ======= =================================================== - Name Default Description -===================== ======= =================================================== - password_expiration 60 Days until passwords expire - password_length 12 Minimum number of characters in password - password_lower 0 Minimum number of lowercase letter in password - password_upper 0 Minimum number of uppercase letters in password - password_numeric 0 Minimum number of number in password - password_special 0 Minimum number of unique special character in password - password_history 30 Disallow reuse of this many previous passwords - password_minimum 24 Amount of hours that must pass until another reset -===================== ======= =================================================== +========================= ======= =================================================== + Name Default Description +========================= ======= =================================================== + password_policy_enabled False Enables password security requirements + password_expiration 60 Days until passwords expire + password_length 12 Minimum number of characters in password + password_lower 0 Minimum number of lowercase letter in password + password_upper 0 Minimum number of uppercase letters in password + password_numeric 0 Minimum number of number in password + password_special 0 Minimum number of unique special character in password + password_history 30 Disallow reuse of this many previous passwords + password_minimum 24 Amount of hours that must pass until another reset +========================= ======= =================================================== diff --git a/password_security/readme/CONTRIBUTORS.rst b/password_security/readme/CONTRIBUTORS.rst index 76ad7c31e1..d86dfec9c9 100644 --- a/password_security/readme/CONTRIBUTORS.rst +++ b/password_security/readme/CONTRIBUTORS.rst @@ -13,3 +13,6 @@ * `Onestein `_: * Andrea Stirpe + +* `twio.tech `_: + * Dawn Hwang diff --git a/password_security/static/description/index.html b/password_security/static/description/index.html index 9b69a7b9f2..50ef50ae9c 100644 --- a/password_security/static/description/index.html +++ b/password_security/static/description/index.html @@ -367,7 +367,7 @@

Password Security

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:dc29155c73a519d3732e2806f60bd11ebb31cd8c181ebd5918e4bc68080d37aa +!! source digest: sha256:5f0bed48b7eca2655dceb715c14f64fd6a2703a6447e4f8f0401072dc03c3933 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: LGPL-3 OCA/server-auth Translate me on Weblate Try me on Runboat

This module allows admin to set company-level password security requirements @@ -406,9 +406,9 @@

Configuration

These are defined at the company level:

---+++ @@ -417,6 +417,10 @@

Configuration

+ + + + @@ -511,6 +515,14 @@

Contributors

+
  • +
    twio.tech:
    +
    +
    +
    +
  • diff --git a/password_security/tests/test_change_password.py b/password_security/tests/test_change_password.py index 3793c5d748..fef9e967ed 100644 --- a/password_security/tests/test_change_password.py +++ b/password_security/tests/test_change_password.py @@ -10,6 +10,10 @@ @tagged("-at_install", "post_install") class TestPasswordSecurityChange(HttpCase): + def setUp(self): + super().setUp() + self.env.company.password_policy_enabled = True + def login(self, username, password): """Log in with provided credentials.""" self.session = http.root.session_store.new() diff --git a/password_security/tests/test_login.py b/password_security/tests/test_login.py index 1059592b58..35a6e4bec2 100644 --- a/password_security/tests/test_login.py +++ b/password_security/tests/test_login.py @@ -15,6 +15,7 @@ def setUp(self): super().setUp() self.username = "jackoneill" self.passwd = "!asdQWE12345_3" + self.env.company.password_policy_enabled = True # Create user with strong password: no error raised new_test_user(self.env, self.username, password=self.passwd) diff --git a/password_security/tests/test_password_history.py b/password_security/tests/test_password_history.py index be8fe30563..6c42b7a3ee 100644 --- a/password_security/tests/test_password_history.py +++ b/password_security/tests/test_password_history.py @@ -12,6 +12,7 @@ def test_check_password_history(self): user = self.env.ref("base.user_admin") user.company_id.update( { + "password_policy_enabled": True, "password_lower": 0, "password_history": 1, "password_numeric": 0, diff --git a/password_security/tests/test_res_users.py b/password_security/tests/test_res_users.py index b4cdc55e6e..e79ffe22e1 100644 --- a/password_security/tests/test_res_users.py +++ b/password_security/tests/test_res_users.py @@ -18,6 +18,7 @@ def setUp(self): } self.password = "asdQWE123$%^" self.main_comp = self.env.ref("base.main_company") + self.main_comp.password_policy_enabled = True self.vals = { "name": "User", "login": self.login, diff --git a/password_security/tests/test_reset_password.py b/password_security/tests/test_reset_password.py index 62da5ed788..92ac3a9af5 100644 --- a/password_security/tests/test_reset_password.py +++ b/password_security/tests/test_reset_password.py @@ -12,6 +12,7 @@ class TestPasswordSecurityReset(HttpCase): def setUp(self): super().setUp() + self.env.company.password_policy_enabled = True # Create user with strong password: no error raised new_test_user(self.env, "jackoneill", password="!asdQWE12345_3") diff --git a/password_security/tests/test_signup.py b/password_security/tests/test_signup.py index b600f4cd12..b3d9f2429c 100644 --- a/password_security/tests/test_signup.py +++ b/password_security/tests/test_signup.py @@ -19,6 +19,10 @@ class EndTestException(Exception): @tagged("-at_install", "post_install") class TestPasswordSecuritySignup(HttpCase): + def setUp(self): + super().setUp() + self.env.company.password_policy_enabled = True + def signup(self, username, password): """Signup user""" self.session = http.root.session_store.new() diff --git a/password_security/views/res_config_settings_views.xml b/password_security/views/res_config_settings_views.xml index 4fb6816d2c..e567418ed4 100644 --- a/password_security/views/res_config_settings_views.xml +++ b/password_security/views/res_config_settings_views.xml @@ -31,12 +31,24 @@ + + + -
    Name
    password_policy_enabledFalseEnables password security requirements
    password_expiration 60 Days until passwords expire