summaryrefslogtreecommitdiff
path: root/passlib/tests/test_utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'passlib/tests/test_utils.py')
-rw-r--r--passlib/tests/test_utils.py514
1 files changed, 85 insertions, 429 deletions
diff --git a/passlib/tests/test_utils.py b/passlib/tests/test_utils.py
index 678ae06..d317629 100644
--- a/passlib/tests/test_utils.py
+++ b/passlib/tests/test_utils.py
@@ -26,6 +26,60 @@ class MiscTest(TestCase):
#NOTE: could test xor_bytes(), but it's exercised well enough by pbkdf2 test
+ def test_classproperty(self):
+ from passlib.utils import classproperty
+
+ class test(object):
+ xvar = 1
+ @classproperty
+ def xprop(cls):
+ return cls.xvar
+
+ self.assertEqual(test.xprop, 1)
+ prop = test.__dict__['xprop']
+ self.assertIs(prop.im_func, prop.__func__)
+
+ def test_deprecated_function(self):
+ from passlib.utils import deprecated_function
+ # NOTE: not comprehensive, just tests the basic behavior
+
+ @deprecated_function(deprecated="1.6", removed="1.8")
+ def test_func(*args):
+ "test docstring"
+ return args
+
+ self.assertTrue(".. deprecated::" in test_func.__doc__)
+
+ with catch_warnings(record=True) as wlog:
+ self.assertEqual(test_func(1,2), (1,2))
+ self.consumeWarningList(wlog,[
+ dict(category=DeprecationWarning,
+ message="the function passlib.tests.test_utils.test_func() "
+ "is deprecated as of Passlib 1.6, and will be "
+ "removed in Passlib 1.8."
+ ),
+ ])
+
+ def test_memoized_property(self):
+ from passlib.utils import memoized_property
+
+ class dummy(object):
+ counter = 0
+
+ @memoized_property
+ def value(self):
+ value = self.counter
+ self.counter = value+1
+ return value
+
+ d = dummy()
+ self.assertEqual(d.value, 0)
+ self.assertEqual(d.value, 0)
+ self.assertEqual(d.counter, 1)
+
+ prop = dummy.value
+ self.assertIs(prop.im_func, prop.__func__)
+
def test_getrandbytes(self):
"test getrandbytes()"
from passlib.utils import getrandbytes, rng
@@ -241,13 +295,11 @@ class MiscTest(TestCase):
def test_saslprep(self):
"test saslprep() unicode normalizer"
- from passlib.utils import saslprep as sp, _ipy_missing_stringprep
-
+ self.require_stringprep()
+ from passlib.utils.compat import IRONPYTHON
if IRONPYTHON:
- self.assertTrue(_ipy_missing_stringprep,
- "alert passlib author that IPY has stringprep support!")
- self.assertRaises(NotImplementedError, sp, u('abc'))
- raise self.skipTest("stringprep missing under IPY")
+ warn("IronPython now has stringprep support!")
+ from passlib.utils import saslprep as sp
# invalid types
self.assertRaises(TypeError, sp, None)
@@ -290,6 +342,8 @@ class MiscTest(TestCase):
# unassigned code points (as of unicode 3.2)
self.assertRaises(ValueError, sp, u("\u0900"))
self.assertRaises(ValueError, sp, u("\uFFF8"))
+ # tagging characters
+ self.assertRaises(ValueError, sp, u("\U000e0001"))
# verify bidi behavior
# if starts with R/AL -- must end with R/AL
@@ -450,86 +504,32 @@ class CodecTest(TestCase):
self.assertFalse(is_same_codec("ascii", "utf-8"))
#=========================================================
-#test des module
+# base64engine
#=========================================================
-import passlib.utils.des as des
-
-class DesTest(TestCase):
-
- #test vectors taken from http://www.skepticfiles.org/faq/testdes.htm
-
- #data is list of (key, plaintext, ciphertext), all as 64 bit hex string
- test_des_vectors = [
- (line[4:20], line[21:37], line[38:54])
- for line in
-b(""" 0000000000000000 0000000000000000 8CA64DE9C1B123A7
- FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF 7359B2163E4EDC58
- 3000000000000000 1000000000000001 958E6E627A05557B
- 1111111111111111 1111111111111111 F40379AB9E0EC533
- 0123456789ABCDEF 1111111111111111 17668DFC7292532D
- 1111111111111111 0123456789ABCDEF 8A5AE1F81AB8F2DD
- 0000000000000000 0000000000000000 8CA64DE9C1B123A7
- FEDCBA9876543210 0123456789ABCDEF ED39D950FA74BCC4
- 7CA110454A1A6E57 01A1D6D039776742 690F5B0D9A26939B
- 0131D9619DC1376E 5CD54CA83DEF57DA 7A389D10354BD271
- 07A1133E4A0B2686 0248D43806F67172 868EBB51CAB4599A
- 3849674C2602319E 51454B582DDF440A 7178876E01F19B2A
- 04B915BA43FEB5B6 42FD443059577FA2 AF37FB421F8C4095
- 0113B970FD34F2CE 059B5E0851CF143A 86A560F10EC6D85B
- 0170F175468FB5E6 0756D8E0774761D2 0CD3DA020021DC09
- 43297FAD38E373FE 762514B829BF486A EA676B2CB7DB2B7A
- 07A7137045DA2A16 3BDD119049372802 DFD64A815CAF1A0F
- 04689104C2FD3B2F 26955F6835AF609A 5C513C9C4886C088
- 37D06BB516CB7546 164D5E404F275232 0A2AEEAE3FF4AB77
- 1F08260D1AC2465E 6B056E18759F5CCA EF1BF03E5DFA575A
- 584023641ABA6176 004BD6EF09176062 88BF0DB6D70DEE56
- 025816164629B007 480D39006EE762F2 A1F9915541020B56
- 49793EBC79B3258F 437540C8698F3CFA 6FBF1CAFCFFD0556
- 4FB05E1515AB73A7 072D43A077075292 2F22E49BAB7CA1AC
- 49E95D6D4CA229BF 02FE55778117F12A 5A6B612CC26CCE4A
- 018310DC409B26D6 1D9D5C5018F728C2 5F4C038ED12B2E41
- 1C587F1C13924FEF 305532286D6F295A 63FAC0D034D9F793
- 0101010101010101 0123456789ABCDEF 617B3A0CE8F07100
- 1F1F1F1F0E0E0E0E 0123456789ABCDEF DB958605F8C8C606
- E0FEE0FEF1FEF1FE 0123456789ABCDEF EDBFD1C66C29CCC7
- 0000000000000000 FFFFFFFFFFFFFFFF 355550B2150E2451
- FFFFFFFFFFFFFFFF 0000000000000000 CAAAAF4DEAF1DBAE
- 0123456789ABCDEF 0000000000000000 D5D44FF720683D0D
- FEDCBA9876543210 FFFFFFFFFFFFFFFF 2A2BB008DF97C2F2
- """).split(b("\n")) if line.strip()
- ]
+class Base64EngineTest(TestCase):
+ "test standalone parts of Base64Engine"
+ # NOTE: most Base64Engine testing done via _Base64Test subclasses below.
- def test_des_encrypt_block(self):
- for k,p,c in self.test_des_vectors:
- k = unhexlify(k)
- p = unhexlify(p)
- c = unhexlify(c)
- result = des.des_encrypt_block(k,p)
- self.assertEqual(result, c, "key=%r p=%r:" % (k,p))
-
- #test 7 byte key
- #FIXME: use a better key
- k,p,c = b('00000000000000'), b('FFFFFFFFFFFFFFFF'), b('355550B2150E2451')
- k = unhexlify(k)
- p = unhexlify(p)
- c = unhexlify(c)
- result = des.des_encrypt_block(k,p)
- self.assertEqual(result, c, "key=%r p=%r:" % (k,p))
-
- def test_mdes_encrypt_int_block(self):
- for k,p,c in self.test_des_vectors:
- k = int(k,16)
- p = int(p,16)
- c = int(c,16)
- result = des.mdes_encrypt_int_block(k,p, salt=0, rounds=1)
- self.assertEqual(result, c, "key=%r p=%r:" % (k,p))
-
- #TODO: test other des methods (eg: mdes_encrypt_int_block w/ salt & rounds)
- # though des-crypt builtin backend test should thump it well enough
+ def test_constructor(self):
+ from passlib.utils import Base64Engine, AB64_CHARS
+
+ # bad charmap type
+ self.assertRaises(TypeError, Base64Engine, 1)
+
+ # bad charmap size
+ self.assertRaises(ValueError, Base64Engine, AB64_CHARS[:-1])
+
+ # dup charmap letter
+ self.assertRaises(ValueError, Base64Engine, AB64_CHARS[:-1] + "A")
+
+ def test_ab64(self):
+ from passlib.utils import ab64_decode
+ # TODO: make ab64_decode (and a b64 variant) *much* stricter about
+ # padding chars, etc.
+
+ # 1 mod 4 not valid
+ self.assertRaises(ValueError, ab64_decode, "abcde")
-#=========================================================
-# base64engine
-#=========================================================
class _Base64Test(TestCase):
"common tests for all Base64Engine instances"
#=========================================================
@@ -730,6 +730,8 @@ class _Base64Test(TestCase):
out = engine.decode_bytes(tmp)
self.assertEqual(out, result)
+ self.assertRaises(TypeError, engine.encode_transposed_bytes, u("a"), [])
+
def test_decode_transposed_bytes(self):
"test decode_transposed_bytes()"
engine = self.engine
@@ -895,351 +897,5 @@ class H64Big_Test(_Base64Test):
]
#=========================================================
-#test md4
-#=========================================================
-class _MD4_Test(TestCase):
- #test vectors from http://www.faqs.org/rfcs/rfc1320.html - A.5
-
- hash = None
-
- vectors = [
- # input -> hex digest
- (b(""), "31d6cfe0d16ae931b73c59d7e0c089c0"),
- (b("a"), "bde52cb31de33e46245e05fbdbd6fb24"),
- (b("abc"), "a448017aaf21d8525fc10ae87aa6729d"),
- (b("message digest"), "d9130a8164549fe818874806e1c7014b"),
- (b("abcdefghijklmnopqrstuvwxyz"), "d79e1c308aa5bbcdeea8ed63df412da9"),
- (b("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"), "043f8582f241db351ce627e153e7f0e4"),
- (b("12345678901234567890123456789012345678901234567890123456789012345678901234567890"), "e33b4ddc9c38f2199c3e7b164fcc0536"),
- ]
-
- def test_md4_update(self):
- "test md4 update"
- md4 = self.hash
- h = md4(b(''))
- self.assertEqual(h.hexdigest(), "31d6cfe0d16ae931b73c59d7e0c089c0")
-
- #NOTE: under py2, hashlib methods try to encode to ascii,
- # though shouldn't rely on that.
- if PY3:
- self.assertRaises(TypeError, h.update, u('x'))
-
- h.update(b('a'))
- self.assertEqual(h.hexdigest(), "bde52cb31de33e46245e05fbdbd6fb24")
-
- h.update(b('bcdefghijklmnopqrstuvwxyz'))
- self.assertEqual(h.hexdigest(), "d79e1c308aa5bbcdeea8ed63df412da9")
-
- def test_md4_hexdigest(self):
- "test md4 hexdigest()"
- md4 = self.hash
- for input, hex in self.vectors:
- out = md4(input).hexdigest()
- self.assertEqual(out, hex)
-
- def test_md4_digest(self):
- "test md4 digest()"
- md4 = self.hash
- for input, hex in self.vectors:
- out = bascii_to_str(hexlify(md4(input).digest()))
- self.assertEqual(out, hex)
-
- def test_md4_copy(self):
- "test md4 copy()"
- md4 = self.hash
- h = md4(b('abc'))
-
- h2 = h.copy()
- h2.update(b('def'))
- self.assertEqual(h2.hexdigest(), '804e7f1c2586e50b49ac65db5b645131')
-
- h.update(b('ghi'))
- self.assertEqual(h.hexdigest(), 'c5225580bfe176f6deeee33dee98732c')
-
-#
-#now do a bunch of things to test multiple possible backends.
-#
-import passlib.utils.md4 as md4_mod
-
-has_ssl_md4 = (md4_mod.md4 is not md4_mod._builtin_md4)
-
-if has_ssl_md4:
- class MD4_SSL_Test(_MD4_Test):
- descriptionPrefix = "MD4 (SSL version)"
- hash = staticmethod(md4_mod.md4)
-
-if not has_ssl_md4 or enable_option("cover"):
- class MD4_Builtin_Test(_MD4_Test):
- descriptionPrefix = "MD4 (builtin version)"
- hash = md4_mod._builtin_md4
-
-#=========================================================
-#test passlib.utils.pbkdf2
-#=========================================================
-import hashlib
-import hmac
-from passlib.utils import pbkdf2
-
-#TODO: should we bother testing hmac_sha1() function? it's verified via sha1_crypt testing.
-class CryptoTest(TestCase):
- "test various crypto functions"
-
- ndn_formats = ["hashlib", "iana"]
- ndn_values = [
- # (iana name, hashlib name, ... other unnormalized names)
- ("md5", "md5", "SCRAM-MD5-PLUS", "MD-5"),
- ("sha1", "sha-1", "SCRAM-SHA-1", "SHA1"),
- ("sha256", "sha-256", "SHA_256", "sha2-256"),
- ("ripemd", "ripemd", "SCRAM-RIPEMD", "RIPEMD"),
- ("ripemd160", "ripemd-160",
- "SCRAM-RIPEMD-160", "RIPEmd160"),
- ("test128", "test-128", "TEST128"),
- ("test2", "test2", "TEST-2"),
- ("test3128", "test3-128", "TEST-3-128"),
- ]
-
- def test_norm_hash_name(self):
- "test norm_hash_name()"
- from itertools import chain
- from passlib.utils.pbkdf2 import norm_hash_name, _nhn_hash_names
-
- # test formats
- for format in self.ndn_formats:
- norm_hash_name("md4", format)
- self.assertRaises(ValueError, norm_hash_name, "md4", None)
- self.assertRaises(ValueError, norm_hash_name, "md4", "fake")
-
- # test types
- self.assertEqual(norm_hash_name(u("MD4")), "md4")
- self.assertEqual(norm_hash_name(b("MD4")), "md4")
- self.assertRaises(TypeError, norm_hash_name, None)
-
- # test selected results
- with catch_warnings():
- warnings.filterwarnings("ignore", '.*unknown hash')
- for row in chain(_nhn_hash_names, self.ndn_values):
- for idx, format in enumerate(self.ndn_formats):
- correct = row[idx]
- for value in row:
- result = norm_hash_name(value, format)
- self.assertEqual(result, correct,
- "name=%r, format=%r:" % (value,
- format))
-
-class KdfTest(TestCase):
- "test kdf helpers"
-
- def test_pbkdf1(self):
- "test pbkdf1"
- for secret, salt, rounds, klen, hash, correct in [
- #http://www.di-mgt.com.au/cryptoKDFs.html
- (b('password'), hb('78578E5A5D63CB06'), 1000, 16, 'sha1',
- hb('dc19847e05c64d2faf10ebfb4a3d2a20')),
- ]:
- result = pbkdf2.pbkdf1(secret, salt, rounds, klen, hash)
- self.assertEqual(result, correct)
-
- #test rounds < 1
- #test klen < 0
- #test klen > block size
- #test invalid hash
-
-#NOTE: this is not run directly, but via two subclasses (below)
-class _Pbkdf2BackendTest(TestCase):
- "test builtin unix crypt backend"
- enable_m2crypto = False
-
- def setUp(self):
- #disable m2crypto support so we'll always use software backend
- if not self.enable_m2crypto:
- self._orig_EVP = pbkdf2._EVP
- pbkdf2._EVP = None
- else:
- #set flag so tests can check for m2crypto presence quickly
- self.enable_m2crypto = bool(pbkdf2._EVP)
- pbkdf2._clear_prf_cache()
-
- def tearDown(self):
- if not self.enable_m2crypto:
- pbkdf2._EVP = self._orig_EVP
- pbkdf2._clear_prf_cache()
-
- #TODO: test get_prf() behavior in various situations - though overall behavior tested via pbkdf2
-
- def test_rfc3962(self):
- "rfc3962 test vectors"
- self.assertFunctionResults(pbkdf2.pbkdf2, [
- # result, secret, salt, rounds, keylen, digest="sha1"
-
- #test case 1 / 128 bit
- (
- hb("cdedb5281bb2f801565a1122b2563515"),
- b("password"), b("ATHENA.MIT.EDUraeburn"), 1, 16
- ),
-
- #test case 2 / 128 bit
- (
- hb("01dbee7f4a9e243e988b62c73cda935d"),
- b("password"), b("ATHENA.MIT.EDUraeburn"), 2, 16
- ),
-
- #test case 2 / 256 bit
- (
- hb("01dbee7f4a9e243e988b62c73cda935da05378b93244ec8f48a99e61ad799d86"),
- b("password"), b("ATHENA.MIT.EDUraeburn"), 2, 32
- ),
-
- #test case 3 / 256 bit
- (
- hb("5c08eb61fdf71e4e4ec3cf6ba1f5512ba7e52ddbc5e5142f708a31e2e62b1e13"),
- b("password"), b("ATHENA.MIT.EDUraeburn"), 1200, 32
- ),
-
- #test case 4 / 256 bit
- (
- hb("d1daa78615f287e6a1c8b120d7062a493f98d203e6be49a6adf4fa574b6e64ee"),
- b("password"), b('\x12\x34\x56\x78\x78\x56\x34\x12'), 5, 32
- ),
-
- #test case 5 / 256 bit
- (
- hb("139c30c0966bc32ba55fdbf212530ac9c5ec59f1a452f5cc9ad940fea0598ed1"),
- b("X"*64), b("pass phrase equals block size"), 1200, 32
- ),
-
- #test case 6 / 256 bit
- (
- hb("9ccad6d468770cd51b10e6a68721be611a8b4d282601db3b36be9246915ec82a"),
- b("X"*65), b("pass phrase exceeds block size"), 1200, 32
- ),
- ])
-
- def test_rfc6070(self):
- "rfc6070 test vectors"
- self.assertFunctionResults(pbkdf2.pbkdf2, [
-
- (
- hb("0c60c80f961f0e71f3a9b524af6012062fe037a6"),
- b("password"), b("salt"), 1, 20,
- ),
-
- (
- hb("ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957"),
- b("password"), b("salt"), 2, 20,
- ),
-
- (
- hb("4b007901b765489abead49d926f721d065a429c1"),
- b("password"), b("salt"), 4096, 20,
- ),
-
- #just runs too long - could enable if ALL option is set
- ##(
- ##
- ## unhexlify("eefe3d61cd4da4e4e9945b3d6ba2158c2634e984"),
- ## "password", "salt", 16777216, 20,
- ##),
-
- (
- hb("3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038"),
- b("passwordPASSWORDpassword"),
- b("saltSALTsaltSALTsaltSALTsaltSALTsalt"),
- 4096, 25,
- ),
-
- (
- hb("56fa6aa75548099dcc37d7f03425e0c3"),
- b("pass\00word"), b("sa\00lt"), 4096, 16,
- ),
- ])
-
- def test_invalid_values(self):
-
- #invalid rounds
- self.assertRaises(ValueError, pbkdf2.pbkdf2, b('password'), b('salt'), -1, 16)
- self.assertRaises(ValueError, pbkdf2.pbkdf2, b('password'), b('salt'), 0, 16)
- self.assertRaises(TypeError, pbkdf2.pbkdf2, b('password'), b('salt'), 'x', 16)
-
- #invalid keylen
- self.assertRaises(ValueError, pbkdf2.pbkdf2, b('password'), b('salt'),
- 1, 20*(2**32-1)+1)
-
- #invalid salt type
- self.assertRaises(TypeError, pbkdf2.pbkdf2, b('password'), 5, 1, 10)
-
- #invalid secret type
- self.assertRaises(TypeError, pbkdf2.pbkdf2, 5, b('salt'), 1, 10)
-
- #invalid hash
- self.assertRaises(ValueError, pbkdf2.pbkdf2, b('password'), b('salt'), 1, 16, 'hmac-foo')
- self.assertRaises(ValueError, pbkdf2.pbkdf2, b('password'), b('salt'), 1, 16, 'foo')
- self.assertRaises(TypeError, pbkdf2.pbkdf2, b('password'), b('salt'), 1, 16, 5)
-
- def test_default_keylen(self):
- "test keylen==-1"
- self.assertEqual(len(pbkdf2.pbkdf2(b('password'), b('salt'), 1, -1,
- prf='hmac-sha1')), 20)
-
- self.assertEqual(len(pbkdf2.pbkdf2(b('password'), b('salt'), 1, -1,
- prf='hmac-sha256')), 32)
-
- def test_hmac_sha1(self):
- "test independant hmac_sha1() method"
- self.assertEqual(
- pbkdf2.hmac_sha1(b("secret"), b("salt")),
- b('\xfc\xd4\x0c;]\r\x97\xc6\xf1S\x8d\x93\xb9\xeb\xc6\x00\x04.\x8b\xfe')
- )
-
- def test_sha1_string(self):
- "test various prf values"
- self.assertEqual(
- pbkdf2.pbkdf2(b("secret"), b("salt"), 10, 16, "hmac-sha1"),
- b('\xe2H\xfbk\x136QF\xf8\xacc\x07\xcc"(\x12')
- )
-
- def test_sha512_string(self):
- "test alternate digest string (sha512)"
- self.assertFunctionResults(pbkdf2.pbkdf2, [
- # result, secret, salt, rounds, keylen, digest="sha1"
-
- #case taken from example in http://grub.enbug.org/Authentication
- (
- hb("887CFF169EA8335235D8004242AA7D6187A41E3187DF0CE14E256D85ED97A97357AAA8FF0A3871AB9EEFF458392F462F495487387F685B7472FC6C29E293F0A0"),
- b("hello"),
- hb("9290F727ED06C38BA4549EF7DE25CF5642659211B7FC076F2D28FEFD71784BB8D8F6FB244A8CC5C06240631B97008565A120764C0EE9C2CB0073994D79080136"),
- 10000, 64, "hmac-sha512"
- ),
- ])
-
- def test_sha512_function(self):
- "test custom digest function"
- def prf(key, msg):
- return hmac.new(key, msg, hashlib.sha512).digest()
-
- self.assertFunctionResults(pbkdf2.pbkdf2, [
- # result, secret, salt, rounds, keylen, digest="sha1"
-
- #case taken from example in http://grub.enbug.org/Authentication
- (
- hb("887CFF169EA8335235D8004242AA7D6187A41E3187DF0CE14E256D85ED97A97357AAA8FF0A3871AB9EEFF458392F462F495487387F685B7472FC6C29E293F0A0"),
- b("hello"),
- hb("9290F727ED06C38BA4549EF7DE25CF5642659211B7FC076F2D28FEFD71784BB8D8F6FB244A8CC5C06240631B97008565A120764C0EE9C2CB0073994D79080136"),
- 10000, 64, prf,
- ),
- ])
-
-has_m2crypto = (pbkdf2._EVP is not None)
-
-if has_m2crypto:
- class Pbkdf2_M2Crypto_Test(_Pbkdf2BackendTest):
- descriptionPrefix = "pbkdf2 (m2crypto backend)"
- enable_m2crypto = True
-
-if not has_m2crypto or enable_option("cover"):
- class Pbkdf2_Builtin_Test(_Pbkdf2BackendTest):
- descriptionPrefix = "pbkdf2 (builtin backend)"
- enable_m2crypto = False
-
-#=========================================================
#EOF
#=========================================================