summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Collins <elic@assurancetechnologies.com>2012-04-17 21:55:38 -0400
committerEli Collins <elic@assurancetechnologies.com>2012-04-17 21:55:38 -0400
commitceb7a00ddae502624d609bc63a9048f0de9f1b23 (patch)
tree69a8f42f57c6f39da914a9952cb7e8cf25dff34f
parent8583409d34d9491553f6c8e545653842518f311c (diff)
downloadpasslib-ceb7a00ddae502624d609bc63a9048f0de9f1b23.tar.gz
a bunch of bugfixes found during unittesting
* bsdi_crypt apparently available on openbsd 4.9 * typo fixes * ConfigParser apparently only uses OrderedDict for >= PY27, adjusted CryptContext test accordingly * fixed test that depended on sha256_crypt.default_rounds * handle os_crypt backend w/ no fallback (bcrypt) * let _norm_rounds accept longs
-rw-r--r--docs/modular_crypt_format.rst2
-rw-r--r--passlib/handlers/bcrypt.py5
-rw-r--r--passlib/handlers/pbkdf2.py2
-rw-r--r--passlib/tests/test_apache.py4
-rw-r--r--passlib/tests/test_context.py38
-rw-r--r--passlib/tests/test_context_deprecated.py8
-rw-r--r--passlib/tests/test_handlers.py5
-rw-r--r--passlib/tests/utils.py8
-rw-r--r--passlib/utils/handlers.py4
9 files changed, 56 insertions, 20 deletions
diff --git a/docs/modular_crypt_format.rst b/docs/modular_crypt_format.rst
index 10cd225..d80bae4 100644
--- a/docs/modular_crypt_format.rst
+++ b/docs/modular_crypt_format.rst
@@ -131,7 +131,7 @@ and indicates which operating systems [#gae]_ offer native support.
Scheme Prefix Linux FreeBSD NetBSD OpenBSD Solaris
==================================== ==================== =========== =========== =========== =========== =======
:class:`~passlib.hash.des_crypt` n/a y y y y y
-:class:`~passlib.hash.bsdi_crypt` ``_`` y y
+:class:`~passlib.hash.bsdi_crypt` ``_`` y y y
:class:`~passlib.hash.md5_crypt` ``$1$`` y y y y y
:class:`~passlib.hash.sun_md5_crypt` ``$md5$``, ``$md5,`` y
:class:`~passlib.hash.bcrypt` ``$2$``, ``$2a$`` y y y y
diff --git a/passlib/handlers/bcrypt.py b/passlib/handlers/bcrypt.py
index 89680a2..665a5c9 100644
--- a/passlib/handlers/bcrypt.py
+++ b/passlib/handlers/bcrypt.py
@@ -249,8 +249,9 @@ class bcrypt(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.HasManyBackends, uh.
assert hash.startswith(config) and len(hash) == len(config)+31
return hash[-31:]
else:
- #NOTE: not checking other backends since this is lowest priority one,
- # so they probably aren't available either.
+ # NOTE: not checking other backends since this is lowest priority one,
+ # so they probably aren't available either.
+ # XXX: though could conceivably use builtin 8|
raise uh.exc.MissingBackendError(
"encoded password can't be handled by os_crypt, "
"recommend installing py-bcrypt.",
diff --git a/passlib/handlers/pbkdf2.py b/passlib/handlers/pbkdf2.py
index 20824b2..9980518 100644
--- a/passlib/handlers/pbkdf2.py
+++ b/passlib/handlers/pbkdf2.py
@@ -116,7 +116,7 @@ def create_pbkdf2_hash(hash_name, digest_size, rounds=6400, ident=None):
:param rounds:
Optional number of rounds to use.
Defaults to %(dr)d, but must be within ``range(1,1<<32)``.
- """ % dict(prf=prf.upper(), dsc=base.default_salt_size, dr=base.default_rounds)
+ """ % dict(prf=prf.upper(), dsc=base.default_salt_size, dr=rounds)
))
#---------------------------------------------------------
diff --git a/passlib/tests/test_apache.py b/passlib/tests/test_apache.py
index 506ad67..f05c05b 100644
--- a/passlib/tests/test_apache.py
+++ b/passlib/tests/test_apache.py
@@ -99,7 +99,7 @@ class HtpasswdFileTest(TestCase):
ht = apache.HtpasswdFile(path, autosave=True)
ht.delete("user1")
- self.assertEqual(get_file(path), "user2:pass2\n")
+ self.assertEqual(get_file(path), b("user2:pass2\n"))
def test_02_set_password(self):
"test set_password()"
@@ -125,7 +125,7 @@ class HtpasswdFileTest(TestCase):
ht = apache.HtpasswdFile(path, default_scheme="plaintext", autosave=True)
ht.set_password("user1", "pass2")
- self.assertEqual(get_file(path), "user1:pass2\n")
+ self.assertEqual(get_file(path), b("user1:pass2\n"))
def test_03_users(self):
"test users()"
diff --git a/passlib/tests/test_context.py b/passlib/tests/test_context.py
index b8a8654..b1c7828 100644
--- a/passlib/tests/test_context.py
+++ b/passlib/tests/test_context.py
@@ -78,6 +78,19 @@ class CryptContextTest(TestCase):
sample_1_resolved_dict = merge_dicts(sample_1_dict,
schemes = sample_1_handlers)
+ sample_1_unnormalized = u("""\
+[passlib]
+schemes = des_crypt, md5_crypt, bsdi_crypt, sha512_crypt
+default = md5_crypt
+; this is using %...
+all__vary_rounds = 10%%
+; this is using 'rounds' instead of 'default_rounds'
+bsdi_crypt__rounds = 25000
+bsdi_crypt__max_rounds = 30000
+sha512_crypt__max_rounds = 50000
+sha512_crypt__min_rounds = 40000
+""")
+
sample_1_unicode = u("""\
[passlib]
schemes = des_crypt, md5_crypt, bsdi_crypt, sha512_crypt
@@ -195,6 +208,10 @@ sha512_crypt__min_rounds = 45000
ctx = CryptContext.from_string(self.sample_1_unicode)
self.assertEqual(ctx.to_dict(), self.sample_1_dict)
+ # test sample 1 with unnormalized inputs
+ ctx = CryptContext.from_string(self.sample_1_unnormalized)
+ self.assertEqual(ctx.to_dict(), self.sample_1_dict)
+
# test sample 1 utf-8
ctx = CryptContext.from_string(self.sample_1_unicode.encode("utf-8"))
self.assertEqual(ctx.to_dict(), self.sample_1_dict)
@@ -708,8 +725,21 @@ sha512_crypt__min_rounds = 45000
def test_35_to_string(self):
"test to_string() method"
+ # create ctx and serialize
ctx = CryptContext(**self.sample_1_dict)
- self.assertEqual(ctx.to_string(), self.sample_1_unicode)
+ dump = ctx.to_string()
+
+ # check ctx->string returns canonical format.
+ # NOTE: ConfigParser for PY26 and earlier didn't use OrderedDict,
+ # so to_string() won't get order correct.
+ # so we skip this test.
+ import sys
+ if sys.version_info >= (2,7):
+ self.assertEqual(dump, self.sample_1_unicode)
+
+ # check ctx->string->ctx->dict returns original
+ ctx2 = CryptContext.from_string(dump)
+ self.assertEqual(ctx2.to_dict(), self.sample_1_dict)
# TODO: test other features, like the unmanaged handler warning.
# TODO: test compact mode, section
@@ -1063,8 +1093,10 @@ sha512_crypt__min_rounds = 45000
self.assertEqual(cc.genconfig(salt="nacl"), '$5$rounds=2500$nacl$')
# fallback default rounds - use handler's
- c2 = cc.copy(all__default_rounds=None, all__max_rounds=50000)
- self.assertEqual(c2.genconfig(salt="nacl"), '$5$rounds=40000$nacl$')
+ df = hash.sha256_crypt.default_rounds
+ c2 = cc.copy(all__default_rounds=None, all__max_rounds=df<<1)
+ self.assertEqual(c2.genconfig(salt="nacl"),
+ '$5$rounds=%d$nacl$' % df)
# fallback default rounds - use handler's, but clipped to max rounds
c2 = cc.copy(all__default_rounds=None, all__max_rounds=3000)
diff --git a/passlib/tests/test_context_deprecated.py b/passlib/tests/test_context_deprecated.py
index df0c5bd..e6aaffa 100644
--- a/passlib/tests/test_context_deprecated.py
+++ b/passlib/tests/test_context_deprecated.py
@@ -725,9 +725,11 @@ class CryptContextTest(TestCase):
# explicit default rounds
self.assertEqual(cc.genconfig(salt="nacl"), '$5$rounds=2500$nacl$')
- # fallback default rounds - use handler's
- c2 = cc.replace(all__default_rounds=None, all__max_rounds=50000)
- self.assertEqual(c2.genconfig(salt="nacl"), '$5$rounds=40000$nacl$')
+ # fallback default rounds - use handler's default
+ df = hash.sha256_crypt.default_rounds
+ c2 = cc.copy(all__default_rounds=None, all__max_rounds=df<<1)
+ self.assertEqual(c2.genconfig(salt="nacl"),
+ '$5$rounds=%d$nacl$' % df)
# fallback default rounds - use handler's, but clipped to max rounds
c2 = cc.replace(all__default_rounds=None, all__max_rounds=3000)
diff --git a/passlib/tests/test_handlers.py b/passlib/tests/test_handlers.py
index a5dd3ae..d045e94 100644
--- a/passlib/tests/test_handlers.py
+++ b/passlib/tests/test_handlers.py
@@ -59,6 +59,7 @@ class _bcrypt_test(HandlerCase):
"base for BCrypt test cases"
handler = hash.bcrypt
secret_size = 72
+ os_crypt_has_fallback = False
known_correct_hashes = [
#
@@ -421,7 +422,7 @@ class _bsdi_crypt_test(HandlerCase):
platform_crypt_support = dict(
freebsd=True,
- openbsd=False,
+ openbsd=True,
netbsd=True,
linux=False,
solaris=False,
@@ -851,7 +852,7 @@ class fshp_test(HandlerCase):
def test_90_variant(self):
"test variant keyword"
handler = self.handler
- kwds = dict(salt='a', rounds=1)
+ kwds = dict(salt=b('a'), rounds=1)
# accepts ints
handler(variant=1, **kwds)
diff --git a/passlib/tests/utils.py b/passlib/tests/utils.py
index a75f428..eb8f3a7 100644
--- a/passlib/tests/utils.py
+++ b/passlib/tests/utils.py
@@ -1764,8 +1764,8 @@ class OsCryptMixin(HandlerCase):
# encodeds as os.platform prefixes.
platform_crypt_support = dict()
- # TODO: test that os_crypt support is detected correct on the expected
- # platofrms.
+ # hack for bcrypt, indicating os_crypt backend has no fallback
+ os_crypt_has_fallback = True
#=========================================================
# instance attrs
@@ -1845,7 +1845,7 @@ class OsCryptMixin(HandlerCase):
# set safe_crypt to return None
setter = self._use_mock_crypt()
setter(None)
- if _find_alternate_backend(self.handler, "os_crypt"):
+ if self.os_crypt_has_fallback and _find_alternate_backend(self.handler, "os_crypt"):
# handler should have a fallback to use
h1 = self.do_encrypt("stub")
h2 = self.do_genhash("stub", h1)
@@ -1860,7 +1860,7 @@ class OsCryptMixin(HandlerCase):
self.assertRaises(MissingBackendError, self.do_verify, 'stub', hash)
def test_82_crypt_support(self):
- "test crypt support detection"
+ "test platform-specific crypt() support detection"
platform = sys.platform
for name, flag in self.platform_crypt_support.items():
if not platform.startswith(name):
diff --git a/passlib/utils/handlers.py b/passlib/utils/handlers.py
index 47e83b0..eb2b7d3 100644
--- a/passlib/utils/handlers.py
+++ b/passlib/utils/handlers.py
@@ -23,7 +23,7 @@ from passlib.utils import classproperty, consteq, getrandstr, getrandbytes,\
MAX_PASSWORD_SIZE
from passlib.utils.compat import b, join_byte_values, bytes, irange, u, \
uascii_to_str, join_unicode, unicode, str_to_uascii, \
- join_unicode, base_string_types, PY2
+ join_unicode, base_string_types, PY2, int_types
# local
__all__ = [
# helpers for implementing MCF handlers
@@ -1138,7 +1138,7 @@ class HasRounds(GenericHandler):
% (self.name,))
# check type
- if not isinstance(rounds, int):
+ if not isinstance(rounds, int_types):
raise exc.ExpectedTypeError(rounds, "integer", "rounds")
# check bounds