diff options
author | Eli Collins <elic@assurancetechnologies.com> | 2020-05-12 11:16:10 -0400 |
---|---|---|
committer | Eli Collins <elic@assurancetechnologies.com> | 2020-05-12 11:16:10 -0400 |
commit | f5fdab0d18757b9952799eb1956a970773adddaa (patch) | |
tree | 2d53e23f6cfd812cb6dfddf7615801efb1c07fb8 | |
parent | 6bba63a8d801f413154f523cc2c3e899af243cc8 (diff) | |
download | passlib-f5fdab0d18757b9952799eb1956a970773adddaa.tar.gz |
bugfix: bcrypt os_crypt backend wasn't being detected properly under py3;
due to a few interlocking issues.
passlib.utils: test_crypt() shouldn't accept hash=<bytes>,
because equality comparison with str will always fail under py3.
* test_crypt() now enforces hash=<unicode_or_str> as input.
it previously allowed hash=bytes, but equality comparison
with unicode (output by safe_crypt) would always return False
under python 3.
* bcrypt's TEST_HASH_2A constant was stored bytes, which was causing os_crypt
detection to fail due to test_crypt() bug above. changed to use native str.
sidewnote: this would have been caught by UTs, except for bug in
test_82_crypt_support() that was fixed in rev 43bae3f786b7.
-rw-r--r-- | docs/history/1.7.rst | 5 | ||||
-rw-r--r-- | passlib/handlers/bcrypt.py | 6 | ||||
-rw-r--r-- | passlib/utils/__init__.py | 10 |
3 files changed, 16 insertions, 5 deletions
diff --git a/docs/history/1.7.rst b/docs/history/1.7.rst index 49b452a..5d8ff44 100644 --- a/docs/history/1.7.rst +++ b/docs/history/1.7.rst @@ -36,6 +36,11 @@ Bugfixes plain SHA256. This should strengthen the hash against brute-force attempts which bypass the intermediary hash by using known-sha256-digest lookup tables (:issue:`114`). +* .. py:currentmodule:: passlib.hash + + :class:`bcrypt`: OS native backend wasn't being detected under Python 3 on BSD platforms. + This was due to an internal issue in feature-detection code, which has been fixed. + * :func:`passlib.utils.safe_crypt`: Support :func:`crypt.crypt` unexpectedly returning bytes under Python 3 (:issue:`113`). diff --git a/passlib/handlers/bcrypt.py b/passlib/handlers/bcrypt.py index 73fbc21..e54a085 100644 --- a/passlib/handlers/bcrypt.py +++ b/passlib/handlers/bcrypt.py @@ -49,7 +49,7 @@ IDENT_2B = u("$2b$") _BNULL = b'\x00' # reference hash of "test", used in various self-checks -TEST_HASH_2A = b"$2a$04$5BJqKfqMQvV7nS.yUguNcueVirQqDBGaLXSqj.rs.pZPlNR0UX/HK" +TEST_HASH_2A = "$2a$04$5BJqKfqMQvV7nS.yUguNcueVirQqDBGaLXSqj.rs.pZPlNR0UX/HK" def _detect_pybcrypt(): """ @@ -408,7 +408,7 @@ class _BcryptCommon(uh.SubclassBackendMixin, uh.TruncateMixin, uh.HasManyIdents, #---------------------------------------------------------------- # check for 2y support #---------------------------------------------------------------- - test_hash_2y = TEST_HASH_2A.replace(b"2a", b"2y") + test_hash_2y = TEST_HASH_2A.replace("2a", "2y") result = safe_verify("test", test_hash_2y) if not result: raise RuntimeError("%s incorrectly rejected $2y$ hash" % backend) @@ -428,7 +428,7 @@ class _BcryptCommon(uh.SubclassBackendMixin, uh.TruncateMixin, uh.HasManyIdents, #---------------------------------------------------------------- # check for 2b support #---------------------------------------------------------------- - test_hash_2b = TEST_HASH_2A.replace(b"2a", b"2b") + test_hash_2b = TEST_HASH_2A.replace("2a", "2b") result = safe_verify("test", test_hash_2b) if not result: raise RuntimeError("%s incorrectly rejected $2b$ hash" % backend) diff --git a/passlib/utils/__init__.py b/passlib/utils/__init__.py index ba54b2f..b9fad4d 100644 --- a/passlib/utils/__init__.py +++ b/passlib/utils/__init__.py @@ -59,7 +59,7 @@ from passlib.exc import ExpectedStringError from passlib.utils.compat import (add_doc, join_bytes, join_byte_values, join_byte_elems, irange, imap, PY3, u, join_unicode, unicode, byte_elem_value, nextgetter, - unicode_or_bytes_types, + unicode_or_str, unicode_or_bytes_types, get_method_function, suppress_cause) # local __all__ = [ @@ -860,7 +860,13 @@ def test_crypt(secret, hash): :arg hash: known hash of password to use as reference :returns: True or False """ - assert secret and hash + # safe_crypt() always returns unicode, which means that for py3, + # 'hash' can't be bytes, or "== hash" will never be True. + # under py2 unicode & str(bytes) will compare fine; + # so just enforcing "unicode_or_str" limitation + assert isinstance(hash, unicode_or_str), \ + "hash must be unicode_or_str, got %s" % type(hash) + assert hash, "hash must be non-empty" return safe_crypt(secret, hash) == hash timer = timeit.default_timer |