diff options
author | Eli Collins <elic@assurancetechnologies.com> | 2012-04-17 21:55:38 -0400 |
---|---|---|
committer | Eli Collins <elic@assurancetechnologies.com> | 2012-04-17 21:55:38 -0400 |
commit | ceb7a00ddae502624d609bc63a9048f0de9f1b23 (patch) | |
tree | 69a8f42f57c6f39da914a9952cb7e8cf25dff34f | |
parent | 8583409d34d9491553f6c8e545653842518f311c (diff) | |
download | passlib-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.rst | 2 | ||||
-rw-r--r-- | passlib/handlers/bcrypt.py | 5 | ||||
-rw-r--r-- | passlib/handlers/pbkdf2.py | 2 | ||||
-rw-r--r-- | passlib/tests/test_apache.py | 4 | ||||
-rw-r--r-- | passlib/tests/test_context.py | 38 | ||||
-rw-r--r-- | passlib/tests/test_context_deprecated.py | 8 | ||||
-rw-r--r-- | passlib/tests/test_handlers.py | 5 | ||||
-rw-r--r-- | passlib/tests/utils.py | 8 | ||||
-rw-r--r-- | passlib/utils/handlers.py | 4 |
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 |