| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743 |
- """tests for passlib.context
- this file is a clone of the 1.5 test_context.py,
- containing the tests using the legacy CryptPolicy api.
- it's being preserved here to ensure the old api doesn't break
- (until Passlib 1.8, when this and the legacy api will be removed).
- """
- #=============================================================================
- # imports
- #=============================================================================
- from __future__ import with_statement
- # core
- from logging import getLogger
- import os
- import warnings
- # site
- try:
- from pkg_resources import resource_filename
- except ImportError:
- resource_filename = None
- # pkg
- from passlib import hash
- from passlib.context import CryptContext, CryptPolicy, LazyCryptContext
- from passlib.utils import to_bytes, to_unicode
- import passlib.utils.handlers as uh
- from passlib.tests.utils import TestCase, set_file
- from passlib.registry import (register_crypt_handler_path,
- _has_crypt_handler as has_crypt_handler,
- _unload_handler_name as unload_handler_name,
- )
- # module
- log = getLogger(__name__)
- #=============================================================================
- #
- #=============================================================================
- class CryptPolicyTest(TestCase):
- """test CryptPolicy object"""
- # TODO: need to test user categories w/in all this
- descriptionPrefix = "CryptPolicy"
- #===================================================================
- # sample crypt policies used for testing
- #===================================================================
- #---------------------------------------------------------------
- # sample 1 - average config file
- #---------------------------------------------------------------
- # NOTE: copy of this is stored in file passlib/tests/sample_config_1s.cfg
- sample_config_1s = """\
- [passlib]
- schemes = des_crypt, md5_crypt, bsdi_crypt, sha512_crypt
- default = md5_crypt
- all.vary_rounds = 10%%
- bsdi_crypt.max_rounds = 30000
- bsdi_crypt.default_rounds = 25000
- sha512_crypt.max_rounds = 50000
- sha512_crypt.min_rounds = 40000
- """
- sample_config_1s_path = os.path.abspath(os.path.join(
- os.path.dirname(__file__), "sample_config_1s.cfg"))
- if not os.path.exists(sample_config_1s_path) and resource_filename:
- # in case we're zipped up in an egg.
- sample_config_1s_path = resource_filename("passlib.tests",
- "sample_config_1s.cfg")
- # make sure sample_config_1s uses \n linesep - tests rely on this
- assert sample_config_1s.startswith("[passlib]\nschemes")
- sample_config_1pd = dict(
- schemes = [ "des_crypt", "md5_crypt", "bsdi_crypt", "sha512_crypt"],
- default = "md5_crypt",
- # NOTE: not maintaining backwards compat for rendering to "10%"
- all__vary_rounds = 0.1,
- bsdi_crypt__max_rounds = 30000,
- bsdi_crypt__default_rounds = 25000,
- sha512_crypt__max_rounds = 50000,
- sha512_crypt__min_rounds = 40000,
- )
- sample_config_1pid = {
- "schemes": "des_crypt, md5_crypt, bsdi_crypt, sha512_crypt",
- "default": "md5_crypt",
- # NOTE: not maintaining backwards compat for rendering to "10%"
- "all.vary_rounds": 0.1,
- "bsdi_crypt.max_rounds": 30000,
- "bsdi_crypt.default_rounds": 25000,
- "sha512_crypt.max_rounds": 50000,
- "sha512_crypt.min_rounds": 40000,
- }
- sample_config_1prd = dict(
- schemes = [ hash.des_crypt, hash.md5_crypt, hash.bsdi_crypt, hash.sha512_crypt],
- default = "md5_crypt", # NOTE: passlib <= 1.5 was handler obj.
- # NOTE: not maintaining backwards compat for rendering to "10%"
- all__vary_rounds = 0.1,
- bsdi_crypt__max_rounds = 30000,
- bsdi_crypt__default_rounds = 25000,
- sha512_crypt__max_rounds = 50000,
- sha512_crypt__min_rounds = 40000,
- )
- #---------------------------------------------------------------
- # sample 2 - partial policy & result of overlay on sample 1
- #---------------------------------------------------------------
- sample_config_2s = """\
- [passlib]
- bsdi_crypt.min_rounds = 29000
- bsdi_crypt.max_rounds = 35000
- bsdi_crypt.default_rounds = 31000
- sha512_crypt.min_rounds = 45000
- """
- sample_config_2pd = dict(
- # using this to test full replacement of existing options
- bsdi_crypt__min_rounds = 29000,
- bsdi_crypt__max_rounds = 35000,
- bsdi_crypt__default_rounds = 31000,
- # using this to test partial replacement of existing options
- sha512_crypt__min_rounds=45000,
- )
- sample_config_12pd = dict(
- schemes = [ "des_crypt", "md5_crypt", "bsdi_crypt", "sha512_crypt"],
- default = "md5_crypt",
- # NOTE: not maintaining backwards compat for rendering to "10%"
- all__vary_rounds = 0.1,
- bsdi_crypt__min_rounds = 29000,
- bsdi_crypt__max_rounds = 35000,
- bsdi_crypt__default_rounds = 31000,
- sha512_crypt__max_rounds = 50000,
- sha512_crypt__min_rounds=45000,
- )
- #---------------------------------------------------------------
- # sample 3 - just changing default
- #---------------------------------------------------------------
- sample_config_3pd = dict(
- default="sha512_crypt",
- )
- sample_config_123pd = dict(
- schemes = [ "des_crypt", "md5_crypt", "bsdi_crypt", "sha512_crypt"],
- default = "sha512_crypt",
- # NOTE: not maintaining backwards compat for rendering to "10%"
- all__vary_rounds = 0.1,
- bsdi_crypt__min_rounds = 29000,
- bsdi_crypt__max_rounds = 35000,
- bsdi_crypt__default_rounds = 31000,
- sha512_crypt__max_rounds = 50000,
- sha512_crypt__min_rounds=45000,
- )
- #---------------------------------------------------------------
- # sample 4 - category specific
- #---------------------------------------------------------------
- sample_config_4s = """
- [passlib]
- schemes = sha512_crypt
- all.vary_rounds = 10%%
- default.sha512_crypt.max_rounds = 20000
- admin.all.vary_rounds = 5%%
- admin.sha512_crypt.max_rounds = 40000
- """
- sample_config_4pd = dict(
- schemes = [ "sha512_crypt" ],
- # NOTE: not maintaining backwards compat for rendering to "10%"
- all__vary_rounds = 0.1,
- sha512_crypt__max_rounds = 20000,
- # NOTE: not maintaining backwards compat for rendering to "5%"
- admin__all__vary_rounds = 0.05,
- admin__sha512_crypt__max_rounds = 40000,
- )
- #---------------------------------------------------------------
- # sample 5 - to_string & deprecation testing
- #---------------------------------------------------------------
- sample_config_5s = sample_config_1s + """\
- deprecated = des_crypt
- admin__context__deprecated = des_crypt, bsdi_crypt
- """
- sample_config_5pd = sample_config_1pd.copy()
- sample_config_5pd.update(
- deprecated = [ "des_crypt" ],
- admin__context__deprecated = [ "des_crypt", "bsdi_crypt" ],
- )
- sample_config_5pid = sample_config_1pid.copy()
- sample_config_5pid.update({
- "deprecated": "des_crypt",
- "admin.context.deprecated": "des_crypt, bsdi_crypt",
- })
- sample_config_5prd = sample_config_1prd.copy()
- sample_config_5prd.update({
- # XXX: should deprecated return the actual handlers in this case?
- # would have to modify how policy stores info, for one.
- "deprecated": ["des_crypt"],
- "admin__context__deprecated": ["des_crypt", "bsdi_crypt"],
- })
- #===================================================================
- # constructors
- #===================================================================
- def setUp(self):
- TestCase.setUp(self)
- warnings.filterwarnings("ignore",
- r"The CryptPolicy class has been deprecated")
- warnings.filterwarnings("ignore",
- r"the method.*hash_needs_update.*is deprecated")
- warnings.filterwarnings("ignore", "The 'all' scheme is deprecated.*")
- warnings.filterwarnings("ignore", "bsdi_crypt rounds should be odd")
- def test_00_constructor(self):
- """test CryptPolicy() constructor"""
- policy = CryptPolicy(**self.sample_config_1pd)
- self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- policy = CryptPolicy(self.sample_config_1pd)
- self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- self.assertRaises(TypeError, CryptPolicy, {}, {})
- self.assertRaises(TypeError, CryptPolicy, {}, dummy=1)
- # check key with too many separators is rejected
- self.assertRaises(TypeError, CryptPolicy,
- schemes = [ "des_crypt", "md5_crypt", "bsdi_crypt", "sha512_crypt"],
- bad__key__bsdi_crypt__max_rounds = 30000,
- )
- # check nameless handler rejected
- class nameless(uh.StaticHandler):
- name = None
- self.assertRaises(ValueError, CryptPolicy, schemes=[nameless])
- # check scheme must be name or crypt handler
- self.assertRaises(TypeError, CryptPolicy, schemes=[uh.StaticHandler])
- # check name conflicts are rejected
- class dummy_1(uh.StaticHandler):
- name = 'dummy_1'
- self.assertRaises(KeyError, CryptPolicy, schemes=[dummy_1, dummy_1])
- # with unknown deprecated value
- self.assertRaises(KeyError, CryptPolicy,
- schemes=['des_crypt'],
- deprecated=['md5_crypt'])
- # with unknown default value
- self.assertRaises(KeyError, CryptPolicy,
- schemes=['des_crypt'],
- default='md5_crypt')
- def test_01_from_path_simple(self):
- """test CryptPolicy.from_path() constructor"""
- # NOTE: this is separate so it can also run under GAE
- # test preset stored in existing file
- path = self.sample_config_1s_path
- policy = CryptPolicy.from_path(path)
- self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- # test if path missing
- self.assertRaises(EnvironmentError, CryptPolicy.from_path, path + 'xxx')
- def test_01_from_path(self):
- """test CryptPolicy.from_path() constructor with encodings"""
- path = self.mktemp()
- # test "\n" linesep
- set_file(path, self.sample_config_1s)
- policy = CryptPolicy.from_path(path)
- self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- # test "\r\n" linesep
- set_file(path, self.sample_config_1s.replace("\n","\r\n"))
- policy = CryptPolicy.from_path(path)
- self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- # test with custom encoding
- uc2 = to_bytes(self.sample_config_1s, "utf-16", source_encoding="utf-8")
- set_file(path, uc2)
- policy = CryptPolicy.from_path(path, encoding="utf-16")
- self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- def test_02_from_string(self):
- """test CryptPolicy.from_string() constructor"""
- # test "\n" linesep
- policy = CryptPolicy.from_string(self.sample_config_1s)
- self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- # test "\r\n" linesep
- policy = CryptPolicy.from_string(
- self.sample_config_1s.replace("\n","\r\n"))
- self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- # test with unicode
- data = to_unicode(self.sample_config_1s)
- policy = CryptPolicy.from_string(data)
- self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- # test with non-ascii-compatible encoding
- uc2 = to_bytes(self.sample_config_1s, "utf-16", source_encoding="utf-8")
- policy = CryptPolicy.from_string(uc2, encoding="utf-16")
- self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- # test category specific options
- policy = CryptPolicy.from_string(self.sample_config_4s)
- self.assertEqual(policy.to_dict(), self.sample_config_4pd)
- def test_03_from_source(self):
- """test CryptPolicy.from_source() constructor"""
- # pass it a path
- policy = CryptPolicy.from_source(self.sample_config_1s_path)
- self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- # pass it a string
- policy = CryptPolicy.from_source(self.sample_config_1s)
- self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- # pass it a dict (NOTE: make a copy to detect in-place modifications)
- policy = CryptPolicy.from_source(self.sample_config_1pd.copy())
- self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- # pass it existing policy
- p2 = CryptPolicy.from_source(policy)
- self.assertIs(policy, p2)
- # pass it something wrong
- self.assertRaises(TypeError, CryptPolicy.from_source, 1)
- self.assertRaises(TypeError, CryptPolicy.from_source, [])
- def test_04_from_sources(self):
- """test CryptPolicy.from_sources() constructor"""
- # pass it empty list
- self.assertRaises(ValueError, CryptPolicy.from_sources, [])
- # pass it one-element list
- policy = CryptPolicy.from_sources([self.sample_config_1s])
- self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- # pass multiple sources
- policy = CryptPolicy.from_sources(
- [
- self.sample_config_1s_path,
- self.sample_config_2s,
- self.sample_config_3pd,
- ])
- self.assertEqual(policy.to_dict(), self.sample_config_123pd)
- def test_05_replace(self):
- """test CryptPolicy.replace() constructor"""
- p1 = CryptPolicy(**self.sample_config_1pd)
- # check overlaying sample 2
- p2 = p1.replace(**self.sample_config_2pd)
- self.assertEqual(p2.to_dict(), self.sample_config_12pd)
- # check repeating overlay makes no change
- p2b = p2.replace(**self.sample_config_2pd)
- self.assertEqual(p2b.to_dict(), self.sample_config_12pd)
- # check overlaying sample 3
- p3 = p2.replace(self.sample_config_3pd)
- self.assertEqual(p3.to_dict(), self.sample_config_123pd)
- def test_06_forbidden(self):
- """test CryptPolicy() forbidden kwds"""
- # salt not allowed to be set
- self.assertRaises(KeyError, CryptPolicy,
- schemes=["des_crypt"],
- des_crypt__salt="xx",
- )
- self.assertRaises(KeyError, CryptPolicy,
- schemes=["des_crypt"],
- all__salt="xx",
- )
- # schemes not allowed for category
- self.assertRaises(KeyError, CryptPolicy,
- schemes=["des_crypt"],
- user__context__schemes=["md5_crypt"],
- )
- #===================================================================
- # reading
- #===================================================================
- def test_10_has_schemes(self):
- """test has_schemes() method"""
- p1 = CryptPolicy(**self.sample_config_1pd)
- self.assertTrue(p1.has_schemes())
- p3 = CryptPolicy(**self.sample_config_3pd)
- self.assertTrue(not p3.has_schemes())
- def test_11_iter_handlers(self):
- """test iter_handlers() method"""
- p1 = CryptPolicy(**self.sample_config_1pd)
- s = self.sample_config_1prd['schemes']
- self.assertEqual(list(p1.iter_handlers()), s)
- p3 = CryptPolicy(**self.sample_config_3pd)
- self.assertEqual(list(p3.iter_handlers()), [])
- def test_12_get_handler(self):
- """test get_handler() method"""
- p1 = CryptPolicy(**self.sample_config_1pd)
- # check by name
- self.assertIs(p1.get_handler("bsdi_crypt"), hash.bsdi_crypt)
- # check by missing name
- self.assertIs(p1.get_handler("sha256_crypt"), None)
- self.assertRaises(KeyError, p1.get_handler, "sha256_crypt", required=True)
- # check default
- self.assertIs(p1.get_handler(), hash.md5_crypt)
- def test_13_get_options(self):
- """test get_options() method"""
- p12 = CryptPolicy(**self.sample_config_12pd)
- self.assertEqual(p12.get_options("bsdi_crypt"),dict(
- # NOTE: not maintaining backwards compat for rendering to "10%"
- vary_rounds = 0.1,
- min_rounds = 29000,
- max_rounds = 35000,
- default_rounds = 31000,
- ))
- self.assertEqual(p12.get_options("sha512_crypt"),dict(
- # NOTE: not maintaining backwards compat for rendering to "10%"
- vary_rounds = 0.1,
- min_rounds = 45000,
- max_rounds = 50000,
- ))
- p4 = CryptPolicy.from_string(self.sample_config_4s)
- self.assertEqual(p4.get_options("sha512_crypt"), dict(
- # NOTE: not maintaining backwards compat for rendering to "10%"
- vary_rounds=0.1,
- max_rounds=20000,
- ))
- self.assertEqual(p4.get_options("sha512_crypt", "user"), dict(
- # NOTE: not maintaining backwards compat for rendering to "10%"
- vary_rounds=0.1,
- max_rounds=20000,
- ))
- self.assertEqual(p4.get_options("sha512_crypt", "admin"), dict(
- # NOTE: not maintaining backwards compat for rendering to "5%"
- vary_rounds=0.05,
- max_rounds=40000,
- ))
- def test_14_handler_is_deprecated(self):
- """test handler_is_deprecated() method"""
- pa = CryptPolicy(**self.sample_config_1pd)
- pb = CryptPolicy(**self.sample_config_5pd)
- self.assertFalse(pa.handler_is_deprecated("des_crypt"))
- self.assertFalse(pa.handler_is_deprecated(hash.bsdi_crypt))
- self.assertFalse(pa.handler_is_deprecated("sha512_crypt"))
- self.assertTrue(pb.handler_is_deprecated("des_crypt"))
- self.assertFalse(pb.handler_is_deprecated(hash.bsdi_crypt))
- self.assertFalse(pb.handler_is_deprecated("sha512_crypt"))
- # check categories as well
- self.assertTrue(pb.handler_is_deprecated("des_crypt", "user"))
- self.assertFalse(pb.handler_is_deprecated("bsdi_crypt", "user"))
- self.assertTrue(pb.handler_is_deprecated("des_crypt", "admin"))
- self.assertTrue(pb.handler_is_deprecated("bsdi_crypt", "admin"))
- # check deprecation is overridden per category
- pc = CryptPolicy(
- schemes=["md5_crypt", "des_crypt"],
- deprecated=["md5_crypt"],
- user__context__deprecated=["des_crypt"],
- )
- self.assertTrue(pc.handler_is_deprecated("md5_crypt"))
- self.assertFalse(pc.handler_is_deprecated("des_crypt"))
- self.assertFalse(pc.handler_is_deprecated("md5_crypt", "user"))
- self.assertTrue(pc.handler_is_deprecated("des_crypt", "user"))
- def test_15_min_verify_time(self):
- """test get_min_verify_time() method"""
- # silence deprecation warnings for min verify time
- warnings.filterwarnings("ignore", category=DeprecationWarning)
- pa = CryptPolicy()
- self.assertEqual(pa.get_min_verify_time(), 0)
- self.assertEqual(pa.get_min_verify_time('admin'), 0)
- pb = pa.replace(min_verify_time=.1)
- self.assertEqual(pb.get_min_verify_time(), 0)
- self.assertEqual(pb.get_min_verify_time('admin'), 0)
- #===================================================================
- # serialization
- #===================================================================
- def test_20_iter_config(self):
- """test iter_config() method"""
- p5 = CryptPolicy(**self.sample_config_5pd)
- self.assertEqual(dict(p5.iter_config()), self.sample_config_5pd)
- self.assertEqual(dict(p5.iter_config(resolve=True)), self.sample_config_5prd)
- self.assertEqual(dict(p5.iter_config(ini=True)), self.sample_config_5pid)
- def test_21_to_dict(self):
- """test to_dict() method"""
- p5 = CryptPolicy(**self.sample_config_5pd)
- self.assertEqual(p5.to_dict(), self.sample_config_5pd)
- self.assertEqual(p5.to_dict(resolve=True), self.sample_config_5prd)
- def test_22_to_string(self):
- """test to_string() method"""
- pa = CryptPolicy(**self.sample_config_5pd)
- s = pa.to_string() # NOTE: can't compare string directly, ordering etc may not match
- pb = CryptPolicy.from_string(s)
- self.assertEqual(pb.to_dict(), self.sample_config_5pd)
- s = pa.to_string(encoding="latin-1")
- self.assertIsInstance(s, bytes)
- #===================================================================
- #
- #===================================================================
- #=============================================================================
- # CryptContext
- #=============================================================================
- class CryptContextTest(TestCase):
- """test CryptContext class"""
- descriptionPrefix = "CryptContext"
- def setUp(self):
- TestCase.setUp(self)
- warnings.filterwarnings("ignore",
- r"CryptContext\(\)\.replace\(\) has been deprecated.*")
- warnings.filterwarnings("ignore",
- r"The CryptContext ``policy`` keyword has been deprecated.*")
- warnings.filterwarnings("ignore", ".*(CryptPolicy|context\.policy).*(has|have) been deprecated.*")
- warnings.filterwarnings("ignore",
- r"the method.*hash_needs_update.*is deprecated")
- #===================================================================
- # constructor
- #===================================================================
- def test_00_constructor(self):
- """test constructor"""
- # create crypt context using handlers
- cc = CryptContext([hash.md5_crypt, hash.bsdi_crypt, hash.des_crypt])
- c,b,a = cc.policy.iter_handlers()
- self.assertIs(a, hash.des_crypt)
- self.assertIs(b, hash.bsdi_crypt)
- self.assertIs(c, hash.md5_crypt)
- # create context using names
- cc = CryptContext(["md5_crypt", "bsdi_crypt", "des_crypt"])
- c,b,a = cc.policy.iter_handlers()
- self.assertIs(a, hash.des_crypt)
- self.assertIs(b, hash.bsdi_crypt)
- self.assertIs(c, hash.md5_crypt)
- # policy kwd
- policy = cc.policy
- cc = CryptContext(policy=policy)
- self.assertEqual(cc.to_dict(), policy.to_dict())
- cc = CryptContext(policy=policy, default="bsdi_crypt")
- self.assertNotEqual(cc.to_dict(), policy.to_dict())
- self.assertEqual(cc.to_dict(), dict(schemes=["md5_crypt","bsdi_crypt","des_crypt"],
- default="bsdi_crypt"))
- self.assertRaises(TypeError, setattr, cc, 'policy', None)
- self.assertRaises(TypeError, CryptContext, policy='x')
- def test_01_replace(self):
- """test replace()"""
- cc = CryptContext(["md5_crypt", "bsdi_crypt", "des_crypt"])
- self.assertIs(cc.policy.get_handler(), hash.md5_crypt)
- cc2 = cc.replace()
- self.assertIsNot(cc2, cc)
- # NOTE: was not able to maintain backward compatibility with this...
- ##self.assertIs(cc2.policy, cc.policy)
- cc3 = cc.replace(default="bsdi_crypt")
- self.assertIsNot(cc3, cc)
- # NOTE: was not able to maintain backward compatibility with this...
- ##self.assertIs(cc3.policy, cc.policy)
- self.assertIs(cc3.policy.get_handler(), hash.bsdi_crypt)
- def test_02_no_handlers(self):
- """test no handlers"""
- # check constructor...
- cc = CryptContext()
- self.assertRaises(KeyError, cc.identify, 'hash', required=True)
- self.assertRaises(KeyError, cc.hash, 'secret')
- self.assertRaises(KeyError, cc.verify, 'secret', 'hash')
- # check updating policy after the fact...
- cc = CryptContext(['md5_crypt'])
- p = CryptPolicy(schemes=[])
- cc.policy = p
- self.assertRaises(KeyError, cc.identify, 'hash', required=True)
- self.assertRaises(KeyError, cc.hash, 'secret')
- self.assertRaises(KeyError, cc.verify, 'secret', 'hash')
- #===================================================================
- # policy adaptation
- #===================================================================
- sample_policy_1 = dict(
- schemes = [ "des_crypt", "md5_crypt", "phpass", "bsdi_crypt",
- "sha256_crypt"],
- deprecated = [ "des_crypt", ],
- default = "sha256_crypt",
- bsdi_crypt__max_rounds = 30,
- bsdi_crypt__default_rounds = 25,
- bsdi_crypt__vary_rounds = 0,
- sha256_crypt__max_rounds = 3000,
- sha256_crypt__min_rounds = 2000,
- sha256_crypt__default_rounds = 3000,
- phpass__ident = "H",
- phpass__default_rounds = 7,
- )
- def test_12_hash_needs_update(self):
- """test hash_needs_update() method"""
- cc = CryptContext(**self.sample_policy_1)
- # check deprecated scheme
- self.assertTrue(cc.hash_needs_update('9XXD4trGYeGJA'))
- self.assertFalse(cc.hash_needs_update('$1$J8HC2RCr$HcmM.7NxB2weSvlw2FgzU0'))
- # check min rounds
- self.assertTrue(cc.hash_needs_update('$5$rounds=1999$jD81UCoo.zI.UETs$Y7qSTQ6mTiU9qZB4fRr43wRgQq4V.5AAf7F97Pzxey/'))
- self.assertFalse(cc.hash_needs_update('$5$rounds=2000$228SSRje04cnNCaQ$YGV4RYu.5sNiBvorQDlO0WWQjyJVGKBcJXz3OtyQ2u8'))
- # check max rounds
- self.assertFalse(cc.hash_needs_update('$5$rounds=3000$fS9iazEwTKi7QPW4$VasgBC8FqlOvD7x2HhABaMXCTh9jwHclPA9j5YQdns.'))
- self.assertTrue(cc.hash_needs_update('$5$rounds=3001$QlFHHifXvpFX4PLs$/0ekt7lSs/lOikSerQ0M/1porEHxYq7W/2hdFpxA3fA'))
- #===================================================================
- # border cases
- #===================================================================
- def test_30_nonstring_hash(self):
- """test non-string hash values cause error"""
- warnings.filterwarnings("ignore", ".*needs_update.*'scheme' keyword is deprecated.*")
- #
- # test hash=None or some other non-string causes TypeError
- # and that explicit-scheme code path behaves the same.
- #
- cc = CryptContext(["des_crypt"])
- for hash, kwds in [
- (None, {}),
- # NOTE: 'scheme' kwd is deprecated...
- (None, {"scheme": "des_crypt"}),
- (1, {}),
- ((), {}),
- ]:
- self.assertRaises(TypeError, cc.hash_needs_update, hash, **kwds)
- cc2 = CryptContext(["mysql323"])
- self.assertRaises(TypeError, cc2.hash_needs_update, None)
- #===================================================================
- # eoc
- #===================================================================
- #=============================================================================
- # LazyCryptContext
- #=============================================================================
- class dummy_2(uh.StaticHandler):
- name = "dummy_2"
- class LazyCryptContextTest(TestCase):
- descriptionPrefix = "LazyCryptContext"
- def setUp(self):
- TestCase.setUp(self)
- # make sure this isn't registered before OR after
- unload_handler_name("dummy_2")
- self.addCleanup(unload_handler_name, "dummy_2")
- # silence some warnings
- warnings.filterwarnings("ignore",
- r"CryptContext\(\)\.replace\(\) has been deprecated")
- warnings.filterwarnings("ignore", ".*(CryptPolicy|context\.policy).*(has|have) been deprecated.*")
- def test_kwd_constructor(self):
- """test plain kwds"""
- self.assertFalse(has_crypt_handler("dummy_2"))
- register_crypt_handler_path("dummy_2", "passlib.tests.test_context")
- cc = LazyCryptContext(iter(["dummy_2", "des_crypt"]), deprecated=["des_crypt"])
- self.assertFalse(has_crypt_handler("dummy_2", True))
- self.assertTrue(cc.policy.handler_is_deprecated("des_crypt"))
- self.assertEqual(cc.policy.schemes(), ["dummy_2", "des_crypt"])
- self.assertTrue(has_crypt_handler("dummy_2", True))
- def test_callable_constructor(self):
- """test create_policy() hook, returning CryptPolicy"""
- self.assertFalse(has_crypt_handler("dummy_2"))
- register_crypt_handler_path("dummy_2", "passlib.tests.test_context")
- def create_policy(flag=False):
- self.assertTrue(flag)
- return CryptPolicy(schemes=iter(["dummy_2", "des_crypt"]), deprecated=["des_crypt"])
- cc = LazyCryptContext(create_policy=create_policy, flag=True)
- self.assertFalse(has_crypt_handler("dummy_2", True))
- self.assertTrue(cc.policy.handler_is_deprecated("des_crypt"))
- self.assertEqual(cc.policy.schemes(), ["dummy_2", "des_crypt"])
- self.assertTrue(has_crypt_handler("dummy_2", True))
- #=============================================================================
- # eof
- #=============================================================================
|