Skip to content

Comments

[19.0][MIG] password_security: Migration to 19.0#855

Open
bizzappdev wants to merge 81 commits intoOCA:19.0from
BizzAppDev-Systems:19.0-mig-password_security-BAD
Open

[19.0][MIG] password_security: Migration to 19.0#855
bizzappdev wants to merge 81 commits intoOCA:19.0from
BizzAppDev-Systems:19.0-mig-password_security-BAD

Conversation

@bizzappdev
Copy link
Contributor

No description provided.

lasley and others added 30 commits October 27, 2025 15:39
* [ADD] res_users_password_security: New module
* Create new module to lock down user passwords

* [REF] res_users_password_security: PR Review fixes
* Also add beta pass history rule

* [ADD] res_users_password_security: Pass history and min time
* Add pass history memory and threshold
* Add minimum time for pass resets through web reset

* Begin controller tests

* Fix copyright, wrong year for new file

* Add tests for password_security_home
* Left to do web_auth_reset_password

* Fix minimum reset threshold and finish tests

* Bug fixes per review

* [REF] password_security: PR review improvements
* Change tech name to password_security
* Use new except format
* Limit 1 & new api
* Cascade deletion for pass history

* [REF] password_security: Fix travis + style
* Fix travis errors
* self to cls
* Better variable names in tests

* [FIX] password_security: Fix travis errors
* Bump versions
* Installable to True
* Add Usage section to ReadMe w/ Runbot link
* `_crypt_context` now directly exposes the `CryptContext`
* Change all instances of openerp to odoo
* Add current time as password_write_date for admin user in demo, disabling the reset prompt - fixes OCA#652
* Switch security to be on correct model to fix OCA#674
…ord invalid (OCA#859)

* [FIX] password_security: Fix password stored

* [REF] password_security: use a unified check_password private method to validate rules and history password
* Add logic to overloaded web_login action to log out users with expired
passwords, preventing the password reset from being ignored
* Add unit test for new logic
This translates to Spanish all missing translations, 31 in total.
Since some implementation details are changed, I had to change some tests that were actually testing the implementation instead of the desired result of the method.
In a normal Odoo deployment, somebody in group *Administration / Access Rights* should be able to create users; but if this addon is installed, it gets this error:

    The requested operation cannot be completed due to security restrictions. Please contact your system administrator.

    (Document type: Res Users Password History, Operation: create)

This is now tested and fixed.
[The `website` addon returns an aditional redirection][1] that makes these tests fail if ran after installing `website`.

The tests were checking the returned value in a funky way anyways.

Now, instead of checking the final returned value, we check directly the parameters sent to the redirection method.

[1]: https://github.com/odoo/odoo/blob/3b85900fafc9469dca6e7c01fca6dac4f55d20f5/addons/website/controllers/main.py#L85-L89
Avoided requiring the module twice in JS.
Currently translated at 57.9% (22 of 38 strings)

Translation: server-auth-12.0/server-auth-12.0-password_security
Translate-URL: https://translation.odoo-community.org/projects/server-auth-12-0/server-auth-12-0-password_security/hr/
astirpe and others added 27 commits October 27, 2025 15:39
Co-authored-by: Dawn Hwang <hwangh95@gmail.com>
Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Translation: server-auth-16.0/server-auth-16.0-password_security
Translate-URL: https://translation.odoo-community.org/projects/server-auth-16-0/server-auth-16-0-password_security/
Currently translated at 24.0% (12 of 50 strings)

Translation: server-auth-16.0/server-auth-16.0-password_security
Translate-URL: https://translation.odoo-community.org/projects/server-auth-16-0/server-auth-16-0-password_security/it/
Currently translated at 24.0% (12 of 50 strings)

Translation: server-auth-16.0/server-auth-16.0-password_security
Translate-URL: https://translation.odoo-community.org/projects/server-auth-16-0/server-auth-16-0-password_security/it/
Currently translated at 100.0% (50 of 50 strings)

Translation: server-auth-16.0/server-auth-16.0-password_security
Translate-URL: https://translation.odoo-community.org/projects/server-auth-16-0/server-auth-16-0-password_security/es/
Currently translated at 100.0% (50 of 50 strings)

Translation: server-auth-16.0/server-auth-16.0-password_security
Translate-URL: https://translation.odoo-community.org/projects/server-auth-16-0/server-auth-16-0-password_security/it/
Replace fields on res.company by ir.config_parameter
Remove dead test for v16 migration script
@bizzappdev bizzappdev marked this pull request as ready for review December 11, 2025 05:39
"security/res_users_pass_history.xml",
],
"demo": [
"demo/res_users.xml",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Odoo 19, all files are declared under the data section and are differentiated by their respective suffixes.

Image

https://www.odoo.com/documentation/19.0/contributing/development/coding_guidelines.html#directories

</setting>
<setting>
<span>
Minimum number of special characters

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you properly define the field name, there is no need to add additional span.

if not (request.session.uid and request.env.user._password_has_expired()):
return response
# My password is expired, kick me out
request.env["res.users"].invalidate_model()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In which scenarios would you need to use invalidate_model?

pwd_params = self._get_all_password_params()
password_history = self.env["res.users.pass.history"].sudo()
for user in self:
password_history_ids = password_history.search([("user_id", "=", user.id)])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why aren’t you using the password_history_ids field?

self.username = "jackoneill"
self.passwd = "!asdQWE12345_3"
@classmethod
def setUpClass(cls):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please document this change in the commit message for better traceability and context?

"""Log in with provided credentials."""
self.session = http.root.session_store.new()
self.opener = Opener(self.env.cr)
self.opener = Opener(self)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additionally, please include the links to the specific commit where the changes were made to ensure full traceability.

@classmethod
def setUpClass(cls):
super().setUpClass()
cls.demo_user = new_test_user(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please clarify the reason for changing the user?

You are creating the demo user multiple times; please consolidate it into a single definition to avoid redundancy and potential conflicts.

demo = self.env.ref("base.user_demo")
demo.groups_id |= self.env.ref("base.group_erp_manager")
demo = self.demo_user
demo.group_ids |= self.env.ref("base.group_erp_manager")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are mutating the shared user since demo was created in setUpClass, mutating it will permanently alter its state for any subsequent tests in that class.


class PasswordSecurityHome(AuthSignupHome):
def do_signup(self, qcontext):
def do_signup(self, qcontext, do_login=True):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need to retain this inheritance? I believe the validation is already triggered from the _set_password method.

# My password is expired, kick me out
request.env.user.action_expire_password()
request.session.logout(keep_db=True)
redirect = request.env.user.partner_id._get_signup_url()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are generating the URL after the session has been closed, which means the link will be created under the public user context.

@imanie383
Copy link

  1. Could you please update the branch, It is currently outdated and needs to be synchronized with the latest changes.

  2. Please improve the migration and document all relevant changes clearly in the commit message,

@bizzappdev

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.