summaryrefslogtreecommitdiff
path: root/passlib/tests
diff options
context:
space:
mode:
authorEli Collins <elic@assurancetechnologies.com>2012-01-19 00:13:49 -0500
committerEli Collins <elic@assurancetechnologies.com>2012-01-19 00:13:49 -0500
commitbcf652e665ba2ffbf8e3f43b4e1108e7aa29dbb0 (patch)
tree3a2aff7abc0d80d9c560846622f89439634f25ce /passlib/tests
parent6f816a3d7f1f3a394fedcc0aa410792a95b9ece6 (diff)
downloadpasslib-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.py92
-rw-r--r--passlib/tests/test_utils_handlers.py5
-rw-r--r--passlib/tests/utils.py52
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