summaryrefslogtreecommitdiff
path: root/passlib
diff options
context:
space:
mode:
authorEli Collins <elic@assurancetechnologies.com>2012-03-10 18:38:38 -0500
committerEli Collins <elic@assurancetechnologies.com>2012-03-10 18:38:38 -0500
commit2ec09c9b2efc3b5e63467151b12d24196ddf582d (patch)
tree3e12c6f2035d9f7b0fb4b0b59217b11ca1880b55 /passlib
parent945c3c4f90c0b755a0f607dcceecc9095f165e4f (diff)
downloadpasslib-2ec09c9b2efc3b5e63467151b12d24196ddf582d.tar.gz
safe_crypt() now handles "*0" and similar error returns from crypt()
Diffstat (limited to 'passlib')
-rw-r--r--passlib/tests/test_utils.py16
-rw-r--r--passlib/utils/__init__.py27
2 files changed, 31 insertions, 12 deletions
diff --git a/passlib/tests/test_utils.py b/passlib/tests/test_utils.py
index 9d641e1..734479b 100644
--- a/passlib/tests/test_utils.py
+++ b/passlib/tests/test_utils.py
@@ -139,15 +139,19 @@ class MiscTest(TestCase):
self.assertTrue(test_crypt("test", h1))
self.assertFalse(test_crypt("test", h1x))
- # test crypt.crypt() returning None is supported.
- # (Python's Modules/_cryptmodule.c notes some platforms may do this
- # when algorithm is not supported - but don't say which platforms)
+ # check crypt returning variant error indicators
+ # some platforms return None on errors, others empty string,
+ # The BSDs in some cases return ":"
import passlib.utils as mod
orig = mod._crypt
try:
- mod._crypt = lambda secret, hash: None
- self.assertEqual(safe_crypt("test", "aa"), None)
- self.assertFalse(test_crypt("test", h1))
+ fake = None
+ mod._crypt = lambda secret, hash: fake
+ for fake in [None, "", ":", ":0", "*0"]:
+ self.assertEqual(safe_crypt("test", "aa"), None)
+ self.assertFalse(test_crypt("test", h1))
+ fake = 'xxx'
+ self.assertEqual(safe_crypt("test", "aa"), "xxx")
finally:
mod._crypt = orig
diff --git a/passlib/utils/__init__.py b/passlib/utils/__init__.py
index 3edfaca..323b98f 100644
--- a/passlib/utils/__init__.py
+++ b/passlib/utils/__init__.py
@@ -1256,6 +1256,14 @@ except ImportError: #pragma: no cover
else:
has_crypt = True
_NULL = '\x00'
+
+ # some crypt() variants will return various constant strings when
+ # an invalid/unrecognized config string is passed in; instead of
+ # returning NULL / None. examples include ":", ":0", "*0", etc.
+ # safe_crypt() returns None for any string starting with one of the
+ # chars in this string...
+ _invalid_prefixes = u("*:!")
+
if PY3:
def safe_crypt(secret, hash):
if isinstance(secret, bytes):
@@ -1281,8 +1289,10 @@ else:
raise ValueError("null character in secret")
if isinstance(hash, bytes):
hash = hash.decode("ascii")
- # NOTE: may return None on some OSes, if hash not supported.
- return _crypt(secret, hash)
+ result = _crypt(secret, hash)
+ if not result or result[0] in _invalid_prefixes:
+ return None
+ return result
else:
def safe_crypt(secret, hash):
if isinstance(secret, unicode):
@@ -1291,12 +1301,13 @@ else:
raise ValueError("null character in secret")
if isinstance(hash, unicode):
hash = hash.encode("ascii")
- # NOTE: may return None on some OSes, if hash not supported.
result = _crypt(secret, hash)
- if result is None:
+ if not result:
return None
- else:
- return result.decode("ascii")
+ result = result.decode("ascii")
+ if result[0] in _invalid_prefixes:
+ return None
+ return result
_add_doc(safe_crypt, """wrapper around stdlib's crypt.
@@ -1322,6 +1333,10 @@ _add_doc(safe_crypt, """wrapper around stdlib's crypt.
* Some OSes will return ``None`` if they don't recognize
the algorithm being used (though most will simply fall
back to des-crypt).
+
+ * Some OSes will return an error string if the input config
+ is recognized but malformed; current code converts these to ``None``
+ as well.
""")
def test_crypt(secret, hash):