summaryrefslogtreecommitdiff
path: root/passlib
diff options
context:
space:
mode:
authorEli Collins <elic@assurancetechnologies.com>2012-04-11 19:31:37 -0400
committerEli Collins <elic@assurancetechnologies.com>2012-04-11 19:31:37 -0400
commit046cfe8a3489ccf87e06a5a9982b283eb71945b0 (patch)
tree1d9fd914de2826d339b3893ff5b8457efa2ac714 /passlib
parent2183916ae35ca69fcf3c7d1550d096488e51a9a8 (diff)
downloadpasslib-046cfe8a3489ccf87e06a5a9982b283eb71945b0.tar.gz
ran full UTs, found and fixed a few bugs introduced in last few commits.
Diffstat (limited to 'passlib')
-rw-r--r--passlib/context.py3
-rw-r--r--passlib/exc.py2
-rw-r--r--passlib/ext/django/models.py2
-rw-r--r--passlib/ext/django/utils.py2
-rw-r--r--passlib/handlers/bcrypt.py17
-rw-r--r--passlib/handlers/cisco.py8
-rw-r--r--passlib/handlers/des_crypt.py4
-rw-r--r--passlib/handlers/django.py2
-rw-r--r--passlib/tests/test_ext_django.py6
-rw-r--r--passlib/tests/test_handlers.py4
-rw-r--r--passlib/tests/test_utils.py5
-rw-r--r--passlib/tests/test_utils_handlers.py17
-rw-r--r--passlib/tests/test_win32.py2
-rw-r--r--passlib/tests/utils.py6
-rw-r--r--passlib/utils/__init__.py2
15 files changed, 48 insertions, 34 deletions
diff --git a/passlib/context.py b/passlib/context.py
index e5bc2c7..2eb1a4f 100644
--- a/passlib/context.py
+++ b/passlib/context.py
@@ -1576,7 +1576,8 @@ class LazyCryptContext(CryptContext):
kwds = self._lazy_kwds
if 'create_policy' in kwds:
create_policy = kwds.pop("create_policy")
- kwds = dict(policy=create_policy(**kwds))
+ policy = create_policy(**kwds)
+ kwds = dict(policy=CryptPolicy.from_source(policy))
super(LazyCryptContext, self).__init__(**kwds)
del self._lazy_kwds
self.__class__ = CryptContext
diff --git a/passlib/exc.py b/passlib/exc.py
index 7c2bd30..1e78123 100644
--- a/passlib/exc.py
+++ b/passlib/exc.py
@@ -106,7 +106,7 @@ def ExpectedStringError(value, param):
"error message when param was supposed to be unicode or bytes"
# NOTE: value is never displayed, since it may sometimes be a password.
cls = value.__class__
- if cls.__module__ and cls.__module__ != "__builtin__":
+ if cls.__module__ and cls.__module__ not in ["__builtin__", "builtins"]:
name = "%s.%s" % (cls.__module__, cls.__name__)
elif value is None:
name = 'None'
diff --git a/passlib/ext/django/models.py b/passlib/ext/django/models.py
index edc334a..d76cc9c 100644
--- a/passlib/ext/django/models.py
+++ b/passlib/ext/django/models.py
@@ -28,7 +28,7 @@ def patch():
catfunc = getattr(settings, "PASSLIB_GET_CATEGORY", get_category)
#parse & validate input value
- if ctx == "disabled":
+ if ctx == "disabled" or ctx is None:
# remove any patching that was already set, just in case.
set_django_password_context(None)
return
diff --git a/passlib/ext/django/utils.py b/passlib/ext/django/utils.py
index 32aa96c..bb95a71 100644
--- a/passlib/ext/django/utils.py
+++ b/passlib/ext/django/utils.py
@@ -47,7 +47,7 @@ def _import_django():
import django.contrib.auth.models as _dam
from django import VERSION
_has_django0 = VERSION < (1,0)
- _has_django14 = VERISON >= (1,4)
+ _has_django14 = VERSION >= (1,4)
if _has_django14:
# django 1.4 had a large rewrite that adds new stronger schemes,
# but changes how things work. our monkeypatching may not jive.
diff --git a/passlib/handlers/bcrypt.py b/passlib/handlers/bcrypt.py
index 6d03c98..f07a194 100644
--- a/passlib/handlers/bcrypt.py
+++ b/passlib/handlers/bcrypt.py
@@ -27,7 +27,7 @@ except ImportError: #pragma: no cover
bcryptor_engine = None
#libs
from passlib.exc import PasslibHashWarning, PasslibSecurityWarning
-from passlib.utils import bcrypt64, safe_crypt, \
+from passlib.utils import bcrypt64, safe_crypt, repeat_string, \
classproperty, rng, getrandstr, test_crypt
from passlib.utils.compat import bytes, u, uascii_to_str, unicode, str_to_uascii
import passlib.utils.handlers as uh
@@ -250,10 +250,12 @@ 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 backends since this is lowest priority,
- # so they probably aren't available either
- raise ValueError("encoded password can't be handled by os_crypt, "
- "recommend installing py-bcrypt or bcryptor.")
+ #NOTE: not checking other backends since this is lowest priority one,
+ # so they probably aren't available either.
+ raise uh.exc.MissingBackendError(
+ "encoded password can't be handled by os_crypt, "
+ "recommend installing py-bcrypt.",
+ )
def _calc_checksum_pybcrypt(self, secret):
#py-bcrypt behavior:
@@ -278,9 +280,8 @@ class bcrypt(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.HasManyBackends, uh.
# bcryptor doesn't support $2$ hashes; but we can fake $2$ behavior
# using the $2a$ algorithm, by repeating the password until
# it's at least 72 chars in length.
- ss = len(secret)
- if 0 < ss < 72:
- secret = secret * (1 + 72//ss)
+ if secret:
+ secret = repeat_string(secret, 72)
config = self._get_config(IDENT_2A)
else:
config = self._get_config()
diff --git a/passlib/handlers/cisco.py b/passlib/handlers/cisco.py
index b4519a9..184134e 100644
--- a/passlib/handlers/cisco.py
+++ b/passlib/handlers/cisco.py
@@ -120,6 +120,14 @@ class cisco_type7(uh.GenericHandler):
return None
@classmethod
+ def genhash(cls, secret, config):
+ # special case to handle ``config=None`` in same style as StaticHandler
+ if config is None:
+ return cls.encrypt(secret)
+ else:
+ return super(cisco_type7, cls).genhash(secret, config)
+
+ @classmethod
def from_string(cls, hash):
hash = to_unicode(hash, "ascii", "hash")
if len(hash) < 2:
diff --git a/passlib/handlers/des_crypt.py b/passlib/handlers/des_crypt.py
index 9517899..56102c0 100644
--- a/passlib/handlers/des_crypt.py
+++ b/passlib/handlers/des_crypt.py
@@ -216,8 +216,8 @@ class des_crypt(uh.HasManyBackends, uh.HasSalt, uh.GenericHandler):
# no official policy since des-crypt predates unicode
hash = safe_crypt(secret, self.salt)
if hash:
- assert hash.startswith(self.salt) and len(hash) == 4
- return hash[-2:]
+ assert hash.startswith(self.salt) and len(hash) == 13
+ return hash[2:]
else:
return self._calc_checksum_builtin(secret)
diff --git a/passlib/handlers/django.py b/passlib/handlers/django.py
index d0c7e11..c79a00d 100644
--- a/passlib/handlers/django.py
+++ b/passlib/handlers/django.py
@@ -157,7 +157,7 @@ class django_des_crypt(DjangoSaltedHash):
chk = self.checksum
if salt and chk:
if salt[:2] != chk[:2]:
- raise uh.exc.MalformedHashError(cls,
+ raise uh.exc.MalformedHashError(self,
"first two digits of salt and checksum must match")
# repeat stub checksum detection since salt isn't set
# when _norm_checksum() is called.
diff --git a/passlib/tests/test_ext_django.py b/passlib/tests/test_ext_django.py
index 96de69e..890c87b 100644
--- a/passlib/tests/test_ext_django.py
+++ b/passlib/tests/test_ext_django.py
@@ -533,7 +533,7 @@ class PluginTest(TestCase):
def test_06_categories(self):
"test PASSLIB_GET_CATEGORY unset"
update_settings(
- PASSLIB_CONTEXT=category_context.policy,
+ PASSLIB_CONTEXT=category_context.policy.to_string(),
)
import passlib.ext.django.models
@@ -546,7 +546,7 @@ class PluginTest(TestCase):
def get_category(user):
return user.first_name or None
update_settings(
- PASSLIB_CONTEXT = category_context.policy,
+ PASSLIB_CONTEXT = category_context.policy.to_string(),
PASSLIB_GET_CATEGORY = get_category,
)
import passlib.ext.django.models
@@ -559,7 +559,7 @@ class PluginTest(TestCase):
def test_08_categories_disabled(self):
"test PASSLIB_GET_CATEGORY = None"
update_settings(
- PASSLIB_CONTEXT = category_context.policy,
+ PASSLIB_CONTEXT = category_context.policy.to_string(),
PASSLIB_GET_CATEGORY = None,
)
import passlib.ext.django.models
diff --git a/passlib/tests/test_handlers.py b/passlib/tests/test_handlers.py
index aaa114b..f00e1cf 100644
--- a/passlib/tests/test_handlers.py
+++ b/passlib/tests/test_handlers.py
@@ -178,7 +178,7 @@ class _bcrypt_test(HandlerCase):
# override some methods
#===============================================================
def setUp(self):
- HandlerCase.setUp(self)
+ super(_bcrypt_test, self).setUp()
if self.backend == "builtin":
warnings.filterwarnings("ignore",
"SECURITY WARNING: .*pure-python bcrypt.*")
@@ -2325,7 +2325,7 @@ class sun_md5_crypt_test(HandlerCase):
def do_verify(self, secret, hash):
# override to fake error for "$..." hash strings listed in known_config.
# these have to be hash strings, in order to test bare salt issue.
- if hash and hash.endswith("$......................"):
+ if isinstance(hash, str) and hash.endswith("$......................"):
raise ValueError("pretending '$.' hash is config string")
return self.handler.verify(secret, hash)
diff --git a/passlib/tests/test_utils.py b/passlib/tests/test_utils.py
index 2d9d147..4c3a6d2 100644
--- a/passlib/tests/test_utils.py
+++ b/passlib/tests/test_utils.py
@@ -348,7 +348,6 @@ class CodecTest(TestCase):
#check unicode w/ encodings
self.assertEqual(to_bytes(u('\x00\xff'), 'latin-1'), b('\x00\xff'))
self.assertRaises(ValueError, to_bytes, u('\x00\xff'), 'ascii')
- self.assertRaises(TypeError, to_bytes, u('abc'), None)
#check bytes inputs
self.assertEqual(to_bytes(b('abc')), b('abc'))
@@ -364,6 +363,7 @@ class CodecTest(TestCase):
b('\x00\xff'))
#check other
+ self.assertRaises(AssertionError, to_bytes, 'abc', None)
self.assertRaises(TypeError, to_bytes, None)
def test_to_unicode(self):
@@ -375,7 +375,6 @@ class CodecTest(TestCase):
self.assertEqual(to_unicode(u('\x00\xff')), u('\x00\xff'))
#check unicode input ignores encoding
- self.assertEqual(to_unicode(u('\x00\xff'), None), u('\x00\xff'))
self.assertEqual(to_unicode(u('\x00\xff'), "ascii"), u('\x00\xff'))
#check bytes input
@@ -384,9 +383,9 @@ class CodecTest(TestCase):
self.assertEqual(to_unicode(b('\x00\xff'), 'latin-1'),
u('\x00\xff'))
self.assertRaises(ValueError, to_unicode, b('\x00\xff'))
- self.assertRaises(TypeError, to_unicode, b('\x00\xff'), None)
#check other
+ self.assertRaises(AssertionError, to_unicode, 'abc', None)
self.assertRaises(TypeError, to_unicode, None)
def test_to_native_str(self):
diff --git a/passlib/tests/test_utils_handlers.py b/passlib/tests/test_utils_handlers.py
index 5044d1e..827fc1b 100644
--- a/passlib/tests/test_utils_handlers.py
+++ b/passlib/tests/test_utils_handlers.py
@@ -74,7 +74,8 @@ class SkeletonTest(TestCase):
self.assertFalse(d1.identify(u('a')))
self.assertFalse(d1.identify(u('b')))
self.assertFalse(d1.identify(u('c')))
- self.assertFalse(d1.identify(None))
+ self.assertRaises(TypeError, d1.identify, None)
+ self.assertRaises(TypeError, d1.identify, 1)
# check default genconfig method
self.assertIs(d1.genconfig(), None)
@@ -109,23 +110,24 @@ class SkeletonTest(TestCase):
raise ValueError
# check fallback
- self.assertFalse(d1.identify(None))
+ self.assertRaises(TypeError, d1.identify, None)
+ self.assertRaises(TypeError, d1.identify, 1)
self.assertFalse(d1.identify(''))
self.assertTrue(d1.identify('a'))
self.assertFalse(d1.identify('b'))
# check regexp
d1._hash_regex = re.compile(u('@.'))
- self.assertFalse(d1.identify(None))
- self.assertFalse(d1.identify(''))
+ self.assertRaises(TypeError, d1.identify, None)
+ self.assertRaises(TypeError, d1.identify, 1)
self.assertTrue(d1.identify('@a'))
self.assertFalse(d1.identify('a'))
del d1._hash_regex
# check ident-based
d1.ident = u('!')
- self.assertFalse(d1.identify(None))
- self.assertFalse(d1.identify(''))
+ self.assertRaises(TypeError, d1.identify, None)
+ self.assertRaises(TypeError, d1.identify, 1)
self.assertTrue(d1.identify('!a'))
self.assertFalse(d1.identify('a'))
del d1.ident
@@ -372,7 +374,8 @@ class SkeletonTest(TestCase):
self.assertFalse(d1.identify(u("!Cxxx")))
self.assertFalse(d1.identify(u("A")))
self.assertFalse(d1.identify(u("")))
- self.assertFalse(d1.identify(None))
+ self.assertRaises(TypeError, d1.identify, None)
+ self.assertRaises(TypeError, d1.identify, 1)
# check default_ident missing is detected.
d1.default_ident = None
diff --git a/passlib/tests/test_win32.py b/passlib/tests/test_win32.py
index 09f5023..7fd475a 100644
--- a/passlib/tests/test_win32.py
+++ b/passlib/tests/test_win32.py
@@ -21,7 +21,7 @@ class UtilTest(TestCase):
## among other places
def setUp(self):
- TestCase.setUp(self)
+ super(UtilTest, self).setUp()
warnings.filterwarnings("ignore",
"the 'passlib.win32' module is deprecated")
diff --git a/passlib/tests/utils.py b/passlib/tests/utils.py
index 17a60ba..713824e 100644
--- a/passlib/tests/utils.py
+++ b/passlib/tests/utils.py
@@ -197,7 +197,7 @@ class TestCase(unittest.TestCase):
resetWarningState = True
def setUp(self):
- unittest.TestCase.setUp(self)
+ super(TestCase, self).setUp()
if self.resetWarningState:
ctx = reset_warnings()
ctx.__enter__()
@@ -1535,7 +1535,7 @@ class HandlerCase(TestCase):
from passlib.utils import tick
handler = self.handler
disabled = self.is_disabled_handler
- max_time = int(os.environ.get("PASSLIB_TESTS_FUZZ_TIME") or 1)
+ max_time = float(os.environ.get("PASSLIB_TESTS_FUZZ_TIME") or 1)
verifiers = self.get_fuzz_verifiers()
def vname(v):
return (v.__doc__ or v.__name__).splitlines()[0]
@@ -1721,7 +1721,7 @@ class OsCryptMixin(HandlerCase):
if not self.handler.has_backend("os_crypt"):
self.handler.get_backend() # hack to prevent recursion issue
self._patch_safe_crypt()
- HandlerCase.setUp(self)
+ super(OsCryptMixin, self).setUp()
def _patch_safe_crypt(self):
"""if crypt() doesn't support current hash alg, this patches
diff --git a/passlib/utils/__init__.py b/passlib/utils/__init__.py
index b9ee776..e0b9e75 100644
--- a/passlib/utils/__init__.py
+++ b/passlib/utils/__init__.py
@@ -548,6 +548,7 @@ def to_bytes(source, encoding="utf-8", errname="value", source_encoding=None):
* if *source_encoding* is specified, byte strings will be transcoded
to *encoding*.
"""
+ assert encoding
if isinstance(source, bytes):
if source_encoding and not is_same_codec(source_encoding, encoding):
return source.decode(source_encoding).encode(encoding)
@@ -579,6 +580,7 @@ def to_unicode(source, source_encoding="utf-8", errname="value"):
if isinstance(source, unicode):
return source
elif isinstance(source, bytes):
+ assert source_encoding
return source.decode(source_encoding)
else:
raise ExpectedStringError(source, errname)