diff options
| author | Eli Collins <elic@assurancetechnologies.com> | 2012-01-19 00:13:49 -0500 |
|---|---|---|
| committer | Eli Collins <elic@assurancetechnologies.com> | 2012-01-19 00:13:49 -0500 |
| commit | bcf652e665ba2ffbf8e3f43b4e1108e7aa29dbb0 (patch) | |
| tree | 3a2aff7abc0d80d9c560846622f89439634f25ce /passlib/tests | |
| parent | 6f816a3d7f1f3a394fedcc0aa410792a95b9ece6 (diff) | |
| download | passlib-bcf652e665ba2ffbf8e3f43b4e1108e7aa29dbb0.tar.gz | |
simplified crypt.crypt() wrappers
* safe_crypt() improved - accepts unicode/bytes for salt, checks for NULL, returns None on failure
* added test_crypt() wrapper to simplify backend checks.
* removed native=True from most to_string() implementations, unused now.
* updated UTs
Diffstat (limited to 'passlib/tests')
| -rw-r--r-- | passlib/tests/test_utils.py | 92 | ||||
| -rw-r--r-- | passlib/tests/test_utils_handlers.py | 5 | ||||
| -rw-r--r-- | passlib/tests/utils.py | 52 |
3 files changed, 78 insertions, 71 deletions
diff --git a/passlib/tests/test_utils.py b/passlib/tests/test_utils.py index d0609b7..957ceb4 100644 --- a/passlib/tests/test_utils.py +++ b/passlib/tests/test_utils.py @@ -98,54 +98,58 @@ class MiscTest(TestCase): rng.seed(genseed(rng)) - def test_safe_os_crypt(self): - "test safe_os_crypt() wrapper" - from passlib.utils import safe_os_crypt - - if not safe_os_crypt: - raise self.skipTest("stdlib crypt module not available") - - #NOTE: this is assuming EVERY crypt will support des_crypt. - # if this fails on some platform, this test will need modifying. - - #test normal case - ok, hash = safe_os_crypt(u('test'), u('aa')) - self.assertTrue(ok) - self.assertIsInstance(hash, unicode) - self.assertEqual(hash, u('aaqPiZY5xR5l.')) - - #test hash-as-bytes - self.assertRaises(TypeError, safe_os_crypt, u('test'), b('aa')) - - #test password as ascii - ret = safe_os_crypt(b('test'), u('aa')) - self.assertEqual(ret, (True, u('aaqPiZY5xR5l.'))) - - #test unicode password w/ high char - ret = safe_os_crypt(u('test\u1234'), u('aa')) - self.assertEqual(ret, (True, u('aahWwbrUsKZk.'))) - - #test utf-8 password w/ high char - ret = safe_os_crypt(b('test\xe1\x88\xb4'), u('aa')) - self.assertEqual(ret, (True, u('aahWwbrUsKZk.'))) - - #test latin-1 password - ret = safe_os_crypt(b('test\xff'), u('aa')) - if PY3: - self.assertEqual(ret, (False, None)) - else: - self.assertEqual(ret, (True, u('aaOx.5nbTU/.M'))) - - # test safe_os_crypt() handles os_crypt() returning None + def test_crypt(self): + "test crypt.crypt() wrappers" + from passlib.utils import has_crypt, safe_crypt, test_crypt + + # test everything is disabled + if not has_crypt: + self.assertEqual(safe_crypt("test", "aa"), None) + self.assertFalse(test_crypt("test", "aaqPiZY5xR5l.")) + raise self.skipTest("crypt.crypt() not available") + + # XXX: this assumes *every* crypt() implementation supports des_crypt. + # if this fails for some platform, this test will need modifying. + + # test return type + self.assertIsInstance(safe_crypt(u("test"), u("aa")), unicode) + + # test ascii password + h1 = u('aaqPiZY5xR5l.') + self.assertEqual(safe_crypt(u('test'), u('aa')), h1) + self.assertEqual(safe_crypt(b('test'), b('aa')), h1) + + # test utf-8 / unicode password + h2 = u('aahWwbrUsKZk.') + self.assertEqual(safe_crypt(u('test\u1234'), 'aa'), h2) + self.assertEqual(safe_crypt(b('test\xe1\x88\xb4'), 'aa'), h2) + + # test latin-1 password + hash = safe_crypt(b('test\xff'), 'aa') + if PY3: # py3 supports utf-8 bytes only. + self.assertEqual(hash, None) + else: # but py2 is fine. + self.assertEqual(hash, u('aaOx.5nbTU/.M')) + + # test rejects null chars in password + self.assertRaises(ValueError, safe_crypt, '\x00', 'aa') + + # check test_crypt() + h1x = h1[:-1] + 'x' + 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) + # when algorithm is not supported - but don't say which platforms) import passlib.utils as mod - orig = mod.os_crypt + orig = mod._crypt try: - mod.os_crypt = lambda secret, hash: None - self.assertEqual(safe_os_crypt(u('test'), u('aa')), (False,None)) + mod._crypt = lambda secret, hash: None + self.assertEqual(safe_crypt("test", "aa"), None) + self.assertFalse(test_crypt("test", h1)) finally: - mod.os_crypt = orig + mod._crypt = orig def test_consteq(self): "test consteq()" diff --git a/passlib/tests/test_utils_handlers.py b/passlib/tests/test_utils_handlers.py index 630e1a0..fe2667a 100644 --- a/passlib/tests/test_utils_handlers.py +++ b/passlib/tests/test_utils_handlers.py @@ -344,7 +344,10 @@ class PrefixWrapperTest(TestCase): d2 = uh.PrefixWrapper("d2", "sha256_crypt", "{XXX}") self.assertIs(d2.setting_kwds, sha256_crypt.setting_kwds) - self.assertTrue('max_rounds' in dir(d2)) + if PY_25_MAX: # lacks __dir__() support + self.assertFalse('max_rounds' in dir(d2)) + else: + self.assertTrue('max_rounds' in dir(d2)) def test_11_wrapped_methods(self): d1 = uh.PrefixWrapper("d1", "ldap_md5", "{XXX}", "{MD5}") diff --git a/passlib/tests/utils.py b/passlib/tests/utils.py index fc53edc..628c4ee 100644 --- a/passlib/tests/utils.py +++ b/passlib/tests/utils.py @@ -10,7 +10,7 @@ import re import os import sys import tempfile -from passlib.utils.compat import PY27, PY_MIN_32, PY3 +from passlib.utils.compat import PY2, PY27, PY_MIN_32, PY3 try: import unittest2 as unittest @@ -452,11 +452,6 @@ class HandlerCase(TestCase): #: if handler uses multiple backends, explicitly set this one when running tests. backend = None - #: hack used by create_backend() to signal we should monkeypatch - # safe_os_crypt() to use handler+this backend, - # only used when backend == "os_crypt" - _patch_crypt_backend = None - #========================================================= #alg interface helpers - allows subclass to overide how # default tests invoke the handler (eg for context_kwds) @@ -526,7 +521,7 @@ class HandlerCase(TestCase): #setup / cleanup #========================================================= _orig_backend = None #backup of original backend - _orig_os_crypt = None #backup of original utils.os_crypt + _orig_crypt = None #backup of original utils.os_crypt def setUp(self): h = self.handler @@ -539,12 +534,12 @@ class HandlerCase(TestCase): if (backend == "os_crypt" and not h.has_backend("os_crypt")): alt_backend = _has_other_backends(h, "os_crypt") if alt_backend: - #monkeypatch utils.safe_os_crypt to use specific handler+backend - #this allows use to test as much of the hash's code path + #monkeypatch utils.safe_crypt to use specific handler+backend + #this allows us to test as much of the hash's code path #as possible, even if current OS doesn't provide crypt() support #for the hash. import passlib.utils as mod - self._orig_os_crypt = mod.os_crypt + self._orig_crypt = mod._crypt def crypt_stub(secret, hash): tmp = h.get_backend() try: @@ -552,16 +547,15 @@ class HandlerCase(TestCase): hash = h.genhash(secret, hash) finally: h.set_backend(tmp) - if not PY3 and isinstance(hash, unicode): - hash = hash.encode("ascii") + assert isinstance(hash, str) return hash - mod.os_crypt = crypt_stub + mod._crypt = crypt_stub h.set_backend(backend) def tearDown(self): - if self._orig_os_crypt: + if self._orig_crypt: import passlib.utils as mod - mod.os_crypt = self._orig_os_crypt + mod._crypt = self._orig_crypt if self._orig_backend: self.handler.set_backend(self._orig_backend) @@ -1003,16 +997,16 @@ class HandlerCase(TestCase): else: helpers = [] - # provide default "os_crypt" helper - if hasattr(handler, "has_backend") and \ - 'os_crypt' in handler.backends and \ - not hasattr(handler, "orig_prefix"): + # use crypt.crypt() to check handlers that have an 'os_crypt' backend. + if _has_possible_crypt_support(handler): possible = True - if handler.has_backend("os_crypt"): + # NOTE: disabling when self._orig_crypt set, means has_backend + # will return a false positive. + if not self._orig_crypt and handler.has_backend("os_crypt"): def check_crypt(secret, hash): - from passlib.utils import os_crypt - self.assertEqual(os_crypt(secret, hash), hash, - "os_crypt(%r,%r):" % (secret, hash)) + from crypt import crypt + self.assertEqual(crypt(secret, hash), hash, + "crypt.crypt(%r,%r):" % (secret, hash)) helpers.append(check_crypt) if not helpers: @@ -1022,7 +1016,7 @@ class HandlerCase(TestCase): raise self.skipTest("not applicable") # generate a single hash, and verify it using all helpers. - secret = 't\xc3\xa1\xd0\x91\xe2\x84\x93\xc9\x99' + secret = b('t\xc3\xa1\xd0\x91\xe2\x84\x93\xc9\x99').decode("utf-8") hash = self.do_encrypt(secret) for helper in helpers: helper(secret, hash) @@ -1081,8 +1075,8 @@ def _enable_backend_case(handler, backend): if enable_option("all-backends") or _is_default_backend(handler, backend): if handler.has_backend(backend): return True, None - from passlib.utils import has_os_crypt - if backend == "os_crypt" and has_os_crypt: + from passlib.utils import has_crypt + if backend == "os_crypt" and has_crypt: if enable_option("cover") and _has_other_backends(handler, "os_crypt"): #in this case, HandlerCase will monkeypatch os_crypt #to use another backend, just so we can test os_crypt fully. @@ -1112,6 +1106,12 @@ def _has_other_backends(handler, ignore): return name return None +def _has_possible_crypt_support(handler): + "check if crypt() supports this natively on some platforms" + return hasattr(handler, "backends") and \ + 'os_crypt' in handler.backends and \ + not hasattr(handler, "orig_prefix") # ignore wrapper classes + def create_backend_case(base, name, module="passlib.tests.test_handlers"): "create a test case for specific backend of a multi-backend handler" #get handler, figure out if backend should be tested |
