Skip to content

Tests: Usermod rename user, change password, lock password#1622

Open
aborah-sudo wants to merge 4 commits intoshadow-maint:masterfrom
aborah-sudo:usermode
Open

Tests: Usermod rename user, change password, lock password#1622
aborah-sudo wants to merge 4 commits intoshadow-maint:masterfrom
aborah-sudo:usermode

Conversation

@aborah-sudo
Copy link
Copy Markdown
Contributor

No description provided.

@aborah-sudo aborah-sudo changed the title Usermode Tests: Usermod rename user, change password, lock password Apr 30, 2026
Comment thread tests/system/tests/test_usermod.py Outdated
Comment thread tests/system/tests/test_usermod.py Outdated
Comment thread tests/system/tests/test_usermod.py Outdated
Comment thread tests/system/tests/test_usermod.py Outdated
Comment thread tests/system/tests/test_usermod.py Outdated
@aborah-sudo aborah-sudo force-pushed the usermode branch 7 times, most recently from 1df807b to 83bcf72 Compare April 30, 2026 10:54
@aborah-sudo aborah-sudo requested a review from ikerexxe April 30, 2026 11:03
Comment thread tests/system/tests/test_usermod.py Outdated
Comment thread tests/system/tests/test_usermod.py Outdated
Comment thread tests/system/tests/test_usermod.py
@aborah-sudo aborah-sudo force-pushed the usermode branch 6 times, most recently from d06e12d to 0611ed0 Compare May 4, 2026 09:05
Copy link
Copy Markdown
Collaborator

@ikerexxe ikerexxe left a comment

Choose a reason for hiding this comment

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

I see you've chosen passlib over my suggestion to use hashlib. Can you help me understand the technical reasoning behind this choice? I want to make sure I understand the requirements correctly.

In addition, several commit messages mention usermode, but that's a different binary that isn't provided by shadow. Do you mind updating the commit messages to usermod?

Comment thread tests/system/tests/test_usermod.py Outdated
@aborah-sudo aborah-sudo force-pushed the usermode branch 4 times, most recently from 7f9d5a6 to e761230 Compare May 6, 2026 01:44
@aborah-sudo aborah-sudo requested a review from ikerexxe May 6, 2026 01:44
@ikerexxe
Copy link
Copy Markdown
Collaborator

ikerexxe commented May 7, 2026

I see we went back to the crypt module. To clarify, we cannot use crypt because it is removed in Python 3.13, and our code will break in the next update.

I also want to avoid passlib to keep our project lightweight without external dependencies.

Please implement this using hashlib. It is built into Python, secure, and future-proof. Does that make sense?

@aborah-sudo aborah-sudo force-pushed the usermode branch 3 times, most recently from 6d48bb4 to 7b7a520 Compare May 7, 2026 07:46
@aborah-sudo
Copy link
Copy Markdown
Contributor Author

I see we went back to the crypt module. To clarify, we cannot use crypt because it is removed in Python 3.13, and our code will break in the next update.

I also want to avoid passlib to keep our project lightweight without external dependencies.

Please implement this using hashlib. It is built into Python, secure, and future-proof. Does that make sense?

Done

Copy link
Copy Markdown
Collaborator

@ikerexxe ikerexxe left a comment

Choose a reason for hiding this comment

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

There's a critical issue with the current password hash generation approach that needs to be addressed. While the code that you implemented produces a string that looks like a SHA-512 crypt hash (starting with $6$), it's not actually a valid SHA-512 crypt hash according to the crypt(3) specification. The issue is that hashlib.sha512() performs a simple single-pass hash, whereas the SHA-512 crypt algorithm requires thousands of rounds of key stretching (typically 5000+ iterations) and uses a specific base64 encoding with a custom alphabet. Real SHA-512 crypt hashes have exactly 86 base64-encoded characters after the salt, not 128 hex characters.

The practical impact is that while usermod -p will accept and store your generated hash (since it doesn't validate the format), users would never be able to authenticate with passwords set this way because the system's authentication libraries expect real crypt-format hashes.

Comment on lines +270 to +274
shadow_entry = shadow.tools.getent.shadow("tuser1")
assert shadow_entry is not None, "User should be found"
assert shadow_entry.password is not None, "Password should not be None"
assert shadow_entry.password.startswith("!"), "Password should be locked with ! prefix"
assert shadow_entry.password == f"!{password_hash}", "Password should have ! prefix when locked"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This check is missing in the steps and expectedresults. You need to move some setup to steps and also add this check

@aborah-sudo
Copy link
Copy Markdown
Contributor Author

aborah-sudo commented May 8, 2026

There's a critical issue with the current password hash generation approach that needs to be addressed. While the code that you implemented produces a string that looks like a SHA-512 crypt hash (starting with $6$), it's not actually a valid SHA-512 crypt hash according to the crypt(3) specification. The issue is that hashlib.sha512() performs a simple single-pass hash, whereas the SHA-512 crypt algorithm requires thousands of rounds of key stretching (typically 5000+ iterations) and uses a specific base64 encoding with a custom alphabet. Real SHA-512 crypt hashes have exactly 86 base64-encoded characters after the salt, not 128 hex characters.

The practical impact is that while usermod -p will accept and store your generated hash (since it doesn't validate the format), users would never be able to authenticate with passwords set this way because the system's authentication libraries expect real crypt-format hashes.

That means i have to use passlib as i used before ?

passlib is the officially recommended replacement for the crypt module. It provides cross-platform support for SHA-512 crypt hashes.

Added passlib dependency for generating valid SHA-512 crypt hashes
This is the transformation to Python of the test located in
`tests/usertools/01/10_usermod_rename_user_in_group.test`
which checks that `usermod` can rename user who is member of a group
This is the transformation to Python of the test located in
`tests/usertools/01/11_usermod_change_password.test`
which checks that `usermod` can change user password
This is the transformation to Python of the test located in
`tests/usertools/01/11_usermod_lock_password.test`
which checks that `usermod` can lock user password
@aborah-sudo aborah-sudo requested a review from ikerexxe May 8, 2026 09:11
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.

2 participants