#13464 closed enhancement (fixed)
Allow bcrypt authentication
| Reported by: | Laman | Owned by: | Jun Omae |
|---|---|---|---|
| Priority: | normal | Milestone: | 1.5.4 |
| Component: | web frontend | Version: | |
| Severity: | normal | Keywords: | patch |
| Cc: | Branch: | ||
| Release Notes: |
|
||
| API Changes: | |||
| Internal Changes: | |||
Description
.htpasswd file format used for Trac authentication allows for bcrypt password digest but the current Trac implementation doesn't reflect this (the user is not authenticated). I propose to add this functionality.
Attachments (3)
Change History (12)
by , 4 years ago
| Attachment: | trac.auth.diff added |
|---|
comment:1 by , 4 years ago
comment:2 by , 4 years ago
- I guess. Curiosly both my
htpasswdand the online htpasswd generator linked from Trac docs output$2y$. And either version got verified by both mycryptand the passlib.
- Ah, I see. I fixed the passlib version.
But the crypt compatibility function in passlib is deprecated and it proved difficult to replace it, so I instead unified the interface to the passlib verify function.
Tests passed on passlib 1.6.5 and 1.7.4
by , 4 years ago
| Attachment: | trac.auth.2.diff added |
|---|
comment:3 by , 4 years ago
Thanks for the revised patch. I tried trac.auth.2.diff with Python 3.6 - 3.10 on Windows, and got the following failures. I consider verify_hash() should catch exceptions of passlib and return False.
======================================================================
ERROR: test_bcrypt (trac.web.tests.auth.BasicAuthenticationTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\usr\src\trac\trac.git\trac\web\tests\auth.py", line 210, in test_bcrypt
self.assertTrue(auth.test('bcrypt', 'bcrypt'))
File "C:\usr\src\trac\trac.git\trac\web\auth.py", line 363, in test
return self.verify(password, the_hash)
File "C:\usr\src\trac\trac.git\trac\util\compat.py", line 33, in verify_hash
return ctx.verify(secret, the_hash)
File "C:\usr\src\trac\venv\py310\lib\site-packages\passlib\context.py", line 2347, in verify
return record.verify(secret, hash, **kwds)
File "C:\usr\src\trac\venv\py310\lib\site-packages\passlib\utils\handlers.py", line 792, in verify
return consteq(self._calc_checksum(secret), chk)
File "C:\usr\src\trac\venv\py310\lib\site-packages\passlib\handlers\bcrypt.py", line 591, in _calc_checksum
self._stub_requires_backend()
File "C:\usr\src\trac\venv\py310\lib\site-packages\passlib\utils\handlers.py", line 2254, in _stub_requires_backend
cls.set_backend()
File "C:\usr\src\trac\venv\py310\lib\site-packages\passlib\utils\handlers.py", line 2156, in set_backend
return owner.set_backend(name, dryrun=dryrun)
File "C:\usr\src\trac\venv\py310\lib\site-packages\passlib\utils\handlers.py", line 2176, in set_backend
raise default_error
passlib.exc.MissingBackendError: bcrypt: no backends available -- recommend you install one (e.g. 'pip install bcrypt')
======================================================================
ERROR: test_extra_entries_ignored (trac.web.tests.auth.BasicAuthenticationTestCase)
Extra entries and comments are ignored.
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\usr\src\trac\trac.git\trac\web\tests\auth.py", line 228, in test_extra_entries_ignored
self.assertTrue(auth.test('bcrypt', 'bcrypt'))
File "C:\usr\src\trac\trac.git\trac\web\auth.py", line 363, in test
return self.verify(password, the_hash)
File "C:\usr\src\trac\trac.git\trac\util\compat.py", line 33, in verify_hash
return ctx.verify(secret, the_hash)
File "C:\usr\src\trac\venv\py310\lib\site-packages\passlib\context.py", line 2347, in verify
return record.verify(secret, hash, **kwds)
File "C:\usr\src\trac\venv\py310\lib\site-packages\passlib\utils\handlers.py", line 792, in verify
return consteq(self._calc_checksum(secret), chk)
File "C:\usr\src\trac\venv\py310\lib\site-packages\passlib\handlers\bcrypt.py", line 591, in _calc_checksum
self._stub_requires_backend()
File "C:\usr\src\trac\venv\py310\lib\site-packages\passlib\utils\handlers.py", line 2254, in _stub_requires_backend
cls.set_backend()
File "C:\usr\src\trac\venv\py310\lib\site-packages\passlib\utils\handlers.py", line 2156, in set_backend
return owner.set_backend(name, dryrun=dryrun)
File "C:\usr\src\trac\venv\py310\lib\site-packages\passlib\utils\handlers.py", line 2176, in set_backend
raise default_error
passlib.exc.MissingBackendError: bcrypt: no backends available -- recommend you install one (e.g. 'pip install bcrypt')
follow-up: 5 comment:4 by , 4 years ago
Sorry, I don't have an easy access to a Windows machine to test properly.
But the missing bcrypt backend bothers me. If the user sets up bcrypt digest while lacking the support, it is a miscofiguration on his part - and by returning False we just cover the error without guiding him to the cause.
There is a backup pure python backend:
The pure-python backend (5) is disabled by default!
That backend is currently too slow to be usable given the number of rounds required for security. That said, if you have no other alternative and need to use it, set the environmental variable PASSLIB_BUILTIN_BCRYPT="enabled" before importing Passlib.
I consider it better to go this way and provide a working, even if suboptimal solution. For other potential crashes, I am again hesitant to just catch and hide them. Are you sure it is the best course?
by , 4 years ago
| Attachment: | trac.auth.3.diff added |
|---|
comment:5 by , 4 years ago
| Milestone: | → 1.5.4 |
|---|---|
| Owner: | set to |
| Status: | new → assigned |
Replying to Laman:
Sorry, I don't have an easy access to a Windows machine to test properly.
Modifying trac/util/compat.py temporarily like the following, it will be able to test on Linux.
# Windows doesn't have a crypt module by default. try: - from crypt import crypt + raise ImportError # from crypt import crypt except ImportError:
But the missing bcrypt backend bothers me. If the user sets up bcrypt digest while lacking the support, it is a miscofiguration on his part - and by returning
Falsewe just cover the error without guiding him to the cause.
That makes sense.
In proposed changes, log:jomae.git@trunk:t13464, the following warning is printed when the password hash is using bcrypt and bcrypt library is not installed.
Warning: cannot verify password for user "username" (MissingBackendError: no bcrypt backends available -- recommend you install one (e.g. 'pip install bcrypt'))
The changes include:
- allowing sha-256/512 password hash
- contrib/htpasswd.py: add
-t methodoption for hash method of passwords
comment:6 by , 3 years ago
| Release Notes: | modified (diff) |
|---|---|
| Resolution: | → fixed |
| Status: | assigned → closed |
Fixed in [17619].
comment:7 by , 3 years ago
| Resolution: | fixed |
|---|---|
| Status: | closed → reopened |
Python on macOS supports only crypt. Unit tests failing.
$ python3 Python 3.9.10 (main, Jan 15 2022, 11:48:15) [Clang 12.0.0 (clang-1200.0.32.29)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import crypt >>> crypt.methods [<crypt.METHOD_CRYPT>]
======================================================================
FAIL: test_bcrypt (trac.web.tests.auth.BasicAuthenticationTestCase.test_bcrypt)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/runner/work/trac/trac/trac/web/tests/auth.py", line 243, in test_bcrypt
self.assertTrue(auth.test('bcrypt', 'bcrypt'))
AssertionError: False is not true
======================================================================
FAIL: test_extra_entries_ignored (trac.web.tests.auth.BasicAuthenticationTestCase.test_extra_entries_ignored)
Extra entries and comments are ignored.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/runner/work/trac/trac/trac/web/tests/auth.py", line 281, in test_extra_entries_ignored
self.assertTrue(auth.test('bcrypt', 'bcrypt'))
AssertionError: False is not true
======================================================================
FAIL: test_sha256 (trac.web.tests.auth.BasicAuthenticationTestCase.test_sha256)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/runner/work/trac/trac/trac/web/tests/auth.py", line 249, in test_sha256
self.assertTrue(auth.test('sha256', 'sha256'))
AssertionError: False is not true
======================================================================
FAIL: test_sha512 (trac.web.tests.auth.BasicAuthenticationTestCase.test_sha512)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/runner/work/trac/trac/trac/web/tests/auth.py", line 255, in test_sha512
self.assertTrue(auth.test('sha512', 'sha512'))
AssertionError: False is not true
comment:9 by , 3 years ago
| Resolution: | → fixed |
|---|---|
| Status: | reopened → closed |



Thanks.
$2b$rather than$2y$as a prefix.See also: https://en.wikipedia.org/wiki/Bcrypt#Versioning_history