Description
We use passlib
in warehouse as part of our user account management service:
warehouse/warehouse/accounts/services.py
Lines 79 to 93 in 26a3446
The TL;DR of what this does is allows user password hash algorithms to evolve over time, and as users log in with their passwords they are confirmed and replaced with the newer (presumably more secure) hash algorithms, preventing the user from needing to reset a password only to get the latest and greatest algorithm.
passlib hasher docs can be found here: https://passlib.readthedocs.io/en/stable/lib/passlib.hash.html
The most recent release of passlib
was in 2020, and raises warnings for using crpyt
, which will turn into breakages under Python 3.13, so this is not yet a blocker, it's something we should consider long before it becomes one.
Here's an issue for maintenance status that has yet to be resolved, either by nominating new maintainers, or some other resolution.
In the interim another contender has emerged - pwdlib
(author launch blog post), which appears to have argon2
and bcrypt
support.
So in theory, we could leverage pwdlib
and continue to leverage the upgradability-behavior, however we'd still need to account for folks that have yet to log in in modern times and the lack of older algo support in pwdlib
.
pwdlib
also does not yet support disable()
or is_enabled()
which we use today, but could be replaced by using the boolean flag User.is_active
or such.
Alternately, since it's not urgent yet, we can continue to observe the evolving space around passlib
and hope that a new maintenance team arises before it becomes a severe issue.
Some SQL counting:
warehouse=> SELECT
CASE
WHEN password LIKE '$argon2%' THEN 'argon2'
WHEN password LIKE '$bcrypt-sha256%' THEN 'bcrypt_sha256'
WHEN password LIKE '$2b$%' THEN 'bcrypt'
WHEN password LIKE 'bcrypt$%' THEN 'django_bcrypt'
WHEN password LIKE 'spammer' THEN 'disabled'
WHEN password LIKE '!' THEN 'disabled'
ELSE 'other'
END AS hash_type,
COUNT(*)
FROM users
GROUP BY hash_type
ORDER BY COUNT(*) DESC;
hash_type | count
---------------+--------
argon2 | 671847
bcrypt_sha256 | 76452
disabled | 28087
django_bcrypt | 10930
(4 rows)