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))
    def test_20_norm_salt(self):
        "test GenericHandler+HasSalt: .norm_salt(), .generate_salt()"
        class d1(uh.HasSalt, uh.GenericHandler):
            name = 'd1'
            setting_kwds = ('salt',)
            min_salt_size = 1
            max_salt_size = 3
            default_salt_size = 2
            salt_chars = 'a'

        #check salt=None
        self.assertEqual(d1.norm_salt(None), 'aa')
        self.assertRaises(ValueError, d1.norm_salt, None, strict=True)

        #check small & large salts
        with catch_warnings():
            warnings.filterwarnings("ignore", ".* salt string must be at (least|most) .*", UserWarning)
            self.assertEqual(d1.norm_salt('aaaa'), 'aaa')
        self.assertRaises(ValueError, d1.norm_salt, '')
        self.assertRaises(ValueError, d1.norm_salt, 'aaaa', strict=True)

        #check generate salt (indirectly)
        self.assertEqual(len(d1.norm_salt(None)), 2)
        self.assertEqual(len(d1.norm_salt(None,salt_size=1)), 1)
        self.assertEqual(len(d1.norm_salt(None,salt_size=3)), 3)
        self.assertEqual(len(d1.norm_salt(None,salt_size=5)), 3)
        self.assertRaises(ValueError, d1.norm_salt, None, salt_size=5, strict=True)
Example #3
0
    def test_get_crypt_handler(self):
        "test get_crypt_handler()"

        class dummy_1(uh.StaticHandler):
            name = "dummy_1"

        # without available handler
        self.assertRaises(KeyError, get_crypt_handler, "dummy_1")
        self.assertIs(get_crypt_handler("dummy_1", None), None)

        # already loaded handler
        register_crypt_handler(dummy_1)
        self.assertIs(get_crypt_handler("dummy_1"), dummy_1)

        with catch_warnings():
            warnings.filterwarnings("ignore", "handler names should be lower-case, and use underscores instead of hyphens:.*", UserWarning)

            # already loaded handler, using incorrect name
            self.assertIs(get_crypt_handler("DUMMY-1"), dummy_1)

            # lazy load of unloaded handler, using incorrect name
            register_crypt_handler_path('dummy_0', __name__)
            self.assertIs(get_crypt_handler("DUMMY-0"), dummy_0)

        # check system & private names aren't returned
        import passlib.hash # ensure module imported, so py3.3 sets __package__
        passlib.hash.__dict__["_fake"] = "dummy" # so behavior seen under py2x also
        for name in ["_fake", "__package__"]:
            self.assertRaises(KeyError, get_crypt_handler, name)
            self.assertIs(get_crypt_handler(name, None), None)
    def test_30_norm_rounds(self):
        "test GenericHandler+HasRounds: .norm_rounds()"

        class d1(uh.HasRounds, uh.GenericHandler):
            name = "d1"
            setting_kwds = ("rounds",)
            min_rounds = 1
            max_rounds = 3
            default_rounds = 2

        # check rounds=None
        self.assertEqual(d1.norm_rounds(None), 2)
        self.assertRaises(ValueError, d1.norm_rounds, None, strict=True)

        # check small & large rounds
        with catch_warnings():
            warnings.filterwarnings("ignore", ".* does not allow (less|more) than \d rounds: .*", UserWarning)
            self.assertEqual(d1.norm_rounds(0), 1)
            self.assertEqual(d1.norm_rounds(4), 3)
        self.assertRaises(ValueError, d1.norm_rounds, 0, strict=True)
        self.assertRaises(ValueError, d1.norm_rounds, 4, strict=True)

        # check no default rounds
        d1.default_rounds = None
        self.assertRaises(ValueError, d1.norm_rounds, None)
    def test_20_norm_salt(self):
        "test GenericHandler+HasSalt: .norm_salt(), .generate_salt()"

        class d1(uh.HasSalt, uh.GenericHandler):
            name = "d1"
            setting_kwds = ("salt",)
            min_salt_size = 1
            max_salt_size = 3
            default_salt_size = 2
            salt_chars = "a"

        # check salt=None
        self.assertEqual(d1.norm_salt(None), "aa")
        self.assertRaises(ValueError, d1.norm_salt, None, strict=True)

        # check small & large salts
        with catch_warnings():
            warnings.filterwarnings("ignore", ".* salt string must be at (least|most) .*", UserWarning)
            self.assertEqual(d1.norm_salt("aaaa"), "aaa")
        self.assertRaises(ValueError, d1.norm_salt, "")
        self.assertRaises(ValueError, d1.norm_salt, "aaaa", strict=True)

        # check generate salt (indirectly)
        self.assertEqual(len(d1.norm_salt(None)), 2)
        self.assertEqual(len(d1.norm_salt(None, salt_size=1)), 1)
        self.assertEqual(len(d1.norm_salt(None, salt_size=3)), 3)
        self.assertEqual(len(d1.norm_salt(None, salt_size=5)), 3)
        self.assertRaises(ValueError, d1.norm_salt, None, salt_size=5, strict=True)
Example #6
0
    def test_get_crypt_handler(self):
        "test get_crypt_handler()"

        class dummy_1(uh.StaticHandler):
            name = "dummy_1"

        # without available handler
        self.assertRaises(KeyError, get_crypt_handler, "dummy_1")
        self.assertIs(get_crypt_handler("dummy_1", None), None)

        # already loaded handler
        register_crypt_handler(dummy_1)
        self.assertIs(get_crypt_handler("dummy_1"), dummy_1)

        with catch_warnings():
            warnings.filterwarnings(
                "ignore",
                "handler names should be lower-case, and use underscores instead of hyphens:.*",
                UserWarning)

            # already loaded handler, using incorrect name
            self.assertIs(get_crypt_handler("DUMMY-1"), dummy_1)

            # lazy load of unloaded handler, using incorrect name
            register_crypt_handler_path('dummy_0', __name__)
            self.assertIs(get_crypt_handler("DUMMY-0"), dummy_0)

        # check system & private names aren't returned
        import passlib.hash  # ensure module imported, so py3.3 sets __package__
        passlib.hash.__dict__[
            "_fake"] = "dummy"  # so behavior seen under py2x also
        for name in ["_fake", "__package__"]:
            self.assertRaises(KeyError, get_crypt_handler, name)
            self.assertIs(get_crypt_handler(name, None), None)
    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))
    def test_get_crypt_handler(self):
        "test get_crypt_handler()"

        class dummy_1(uh.StaticHandler):
            name = "dummy_1"

        self.assertRaises(KeyError, get_crypt_handler, "dummy_1")

        register_crypt_handler(dummy_1)
        self.assertIs(get_crypt_handler("dummy_1"), dummy_1)

        with catch_warnings():
            warnings.filterwarnings("ignore", "handler names should be lower-case, and use underscores instead of hyphens:.*", UserWarning)
            self.assertIs(get_crypt_handler("DUMMY-1"), dummy_1)
Example #9
0
    def test_24_min_verify_time(self):
        "test verify() honors min_verify_time"
        #NOTE: this whole test assumes time.sleep() and time.time()
        #      have at least 1ms accuracy
        delta = .1
        min_delay = delta
        min_verify_time = min_delay + 2*delta
        max_delay = min_verify_time + 2*delta

        class TimedHash(uh.StaticHandler):
            "psuedo hash that takes specified amount of time"
            name = "timed_hash"
            delay = 0

            @classmethod
            def identify(cls, hash):
                return True

            @classmethod
            def genhash(cls, secret, hash):
                time.sleep(cls.delay)
                return hash or 'x'

        cc = CryptContext([TimedHash], min_verify_time=min_verify_time)

        def timecall(func, *args, **kwds):
            start = time.time()
            result = func(*args, **kwds)
            end = time.time()
            return end-start, result

        #verify hashing works
        TimedHash.delay = min_delay
        elapsed, _ = timecall(TimedHash.genhash, 'stub', 'stub')
        self.assertAlmostEqual(elapsed, min_delay, delta=delta)

        #ensure min verify time is honored
        elapsed, _ = timecall(cc.verify, "stub", "stub")
        self.assertAlmostEqual(elapsed, min_verify_time, delta=delta)

        #ensure taking longer emits a warning.
        TimedHash.delay = max_delay
        with catch_warnings(record=True) as wlog:
            warnings.simplefilter("always")
            elapsed, _ = timecall(cc.verify, "stub", "stub")
        self.assertAlmostEqual(elapsed, max_delay, delta=delta)
        self.assertEqual(len(wlog), 1)
        self.assertWarningMatches(wlog[0],
            message_re="CryptContext: verify exceeded min_verify_time")
Example #10
0
    def test_register_crypt_handler_path(self):
        """test register_crypt_handler_path()"""
        # NOTE: this messes w/ internals of registry, shouldn't be used publically.
        paths = registry._locations

        # check namespace is clear
        self.assertTrue('dummy_0' not in paths)
        self.assertFalse(hasattr(hash, 'dummy_0'))

        # check invalid names are rejected
        self.assertRaises(ValueError, register_crypt_handler_path, "dummy_0",
                          ".test_registry")
        self.assertRaises(ValueError, register_crypt_handler_path, "dummy_0",
                          __name__ + ":dummy_0:xxx")
        self.assertRaises(ValueError, register_crypt_handler_path, "dummy_0",
                          __name__ + ":dummy_0.xxx")

        # try lazy load
        register_crypt_handler_path('dummy_0', __name__)
        self.assertTrue('dummy_0' in list_crypt_handlers())
        self.assertTrue('dummy_0' not in list_crypt_handlers(loaded_only=True))
        self.assertIs(hash.dummy_0, dummy_0)
        self.assertTrue('dummy_0' in list_crypt_handlers(loaded_only=True))
        unload_handler_name('dummy_0')

        # try lazy load w/ alt
        register_crypt_handler_path('dummy_0', __name__ + ':alt_dummy_0')
        self.assertIs(hash.dummy_0, alt_dummy_0)
        unload_handler_name('dummy_0')

        # check lazy load w/ wrong type fails
        register_crypt_handler_path('dummy_x', __name__)
        self.assertRaises(TypeError, get_crypt_handler, 'dummy_x')

        # check lazy load w/ wrong name fails
        register_crypt_handler_path('alt_dummy_0', __name__)
        self.assertRaises(ValueError, get_crypt_handler, "alt_dummy_0")
        unload_handler_name("alt_dummy_0")

        # TODO: check lazy load which calls register_crypt_handler (warning should be issued)
        sys.modules.pop("passlib.tests._test_bad_register", None)
        register_crypt_handler_path("dummy_bad",
                                    "passlib.tests._test_bad_register")
        with catch_warnings():
            warnings.filterwarnings("ignore", "xxxxxxxxxx", DeprecationWarning)
            h = get_crypt_handler("dummy_bad")
        from passlib.tests import _test_bad_register as tbr
        self.assertIs(h, tbr.alt_dummy_bad)
Example #11
0
    def test_register_crypt_handler_path(self):
        """test register_crypt_handler_path()"""
        # NOTE: this messes w/ internals of registry, shouldn't be used publically.
        paths = registry._locations

        # check namespace is clear
        self.assertTrue('dummy_0' not in paths)
        self.assertFalse(hasattr(hash, 'dummy_0'))

        # check invalid names are rejected
        self.assertRaises(ValueError, register_crypt_handler_path,
                          "dummy_0", ".test_registry")
        self.assertRaises(ValueError, register_crypt_handler_path,
                          "dummy_0", __name__ + ":dummy_0:xxx")
        self.assertRaises(ValueError, register_crypt_handler_path,
                          "dummy_0", __name__ + ":dummy_0.xxx")

        # try lazy load
        register_crypt_handler_path('dummy_0', __name__)
        self.assertTrue('dummy_0' in list_crypt_handlers())
        self.assertTrue('dummy_0' not in list_crypt_handlers(loaded_only=True))
        self.assertIs(hash.dummy_0, dummy_0)
        self.assertTrue('dummy_0' in list_crypt_handlers(loaded_only=True))
        unload_handler_name('dummy_0')

        # try lazy load w/ alt
        register_crypt_handler_path('dummy_0', __name__ + ':alt_dummy_0')
        self.assertIs(hash.dummy_0, alt_dummy_0)
        unload_handler_name('dummy_0')

        # check lazy load w/ wrong type fails
        register_crypt_handler_path('dummy_x', __name__)
        self.assertRaises(TypeError, get_crypt_handler, 'dummy_x')

        # check lazy load w/ wrong name fails
        register_crypt_handler_path('alt_dummy_0', __name__)
        self.assertRaises(ValueError, get_crypt_handler, "alt_dummy_0")
        unload_handler_name("alt_dummy_0")

        # TODO: check lazy load which calls register_crypt_handler (warning should be issued)
        sys.modules.pop("passlib.tests._test_bad_register", None)
        register_crypt_handler_path("dummy_bad", "passlib.tests._test_bad_register")
        with catch_warnings():
            warnings.filterwarnings("ignore", "xxxxxxxxxx", DeprecationWarning)
            h = get_crypt_handler("dummy_bad")
        from passlib.tests import _test_bad_register as tbr
        self.assertIs(h, tbr.alt_dummy_bad)
    def test_30_norm_rounds(self):
        "test GenericHandler + HasRounds mixin"

        # setup helpers
        class d1(uh.HasRounds, uh.GenericHandler):
            name = 'd1'
            setting_kwds = ('rounds', )
            min_rounds = 1
            max_rounds = 3
            default_rounds = 2

        def norm_rounds(**k):
            return d1(**k).rounds

        # check rounds=None
        self.assertRaises(TypeError, norm_rounds)
        self.assertRaises(TypeError, norm_rounds, rounds=None)
        self.assertEqual(norm_rounds(use_defaults=True), 2)

        # check rounds=non int
        self.assertRaises(TypeError, norm_rounds, rounds=1.5)

        # check explicit rounds
        with catch_warnings(record=True) as wlog:
            # too small
            self.assertRaises(ValueError, norm_rounds, rounds=0)
            self.consumeWarningList(wlog)

            self.assertEqual(norm_rounds(rounds=0, relaxed=True), 1)
            self.consumeWarningList(wlog, PasslibHashWarning)

            # just right
            self.assertEqual(norm_rounds(rounds=1), 1)
            self.assertEqual(norm_rounds(rounds=2), 2)
            self.assertEqual(norm_rounds(rounds=3), 3)
            self.consumeWarningList(wlog)

            # too large
            self.assertRaises(ValueError, norm_rounds, rounds=4)
            self.consumeWarningList(wlog)

            self.assertEqual(norm_rounds(rounds=4, relaxed=True), 3)
            self.consumeWarningList(wlog, PasslibHashWarning)

        # check no default rounds
        d1.default_rounds = None
        self.assertRaises(TypeError, norm_rounds, use_defaults=True)
    def test_30_norm_rounds(self):
        "test GenericHandler + HasRounds mixin"
        # setup helpers
        class d1(uh.HasRounds, uh.GenericHandler):
            name = 'd1'
            setting_kwds = ('rounds',)
            min_rounds = 1
            max_rounds = 3
            default_rounds = 2

        def norm_rounds(**k):
            return d1(**k).rounds

        # check rounds=None
        self.assertRaises(TypeError, norm_rounds)
        self.assertRaises(TypeError, norm_rounds, rounds=None)
        self.assertEqual(norm_rounds(use_defaults=True), 2)

        # check rounds=non int
        self.assertRaises(TypeError, norm_rounds, rounds=1.5)

        # check explicit rounds
        with catch_warnings(record=True) as wlog:
            # too small
            self.assertRaises(ValueError, norm_rounds, rounds=0)
            self.consumeWarningList(wlog)

            self.assertEqual(norm_rounds(rounds=0, relaxed=True), 1)
            self.consumeWarningList(wlog, PasslibHashWarning)

            # just right
            self.assertEqual(norm_rounds(rounds=1), 1)
            self.assertEqual(norm_rounds(rounds=2), 2)
            self.assertEqual(norm_rounds(rounds=3), 3)
            self.consumeWarningList(wlog)

            # too large
            self.assertRaises(ValueError, norm_rounds, rounds=4)
            self.consumeWarningList(wlog)

            self.assertEqual(norm_rounds(rounds=4, relaxed=True), 3)
            self.consumeWarningList(wlog, PasslibHashWarning)

        # check no default rounds
        d1.default_rounds = None
        self.assertRaises(TypeError, norm_rounds, use_defaults=True)
Example #14
0
    def test_01_patch_control_detection(self):
        "test set_django_password_context detection of foreign monkeypatches"

        def dummy():
            pass

        with catch_warnings(record=True) as wlog:
            warnings.simplefilter("always")

            #patch to use stock django context
            utils.set_django_password_context(django_context)
            self.assert_patched(context=django_context)
            self.assertEquals(len(wlog), 0)

            #mess with User.set_password, make sure it's detected
            dam.User.set_password = dummy
            utils.set_django_password_context(django_context)
            self.assert_patched(context=django_context)
            self.assertEquals(len(wlog), 1)
            self.assertWarningMatches(
                wlog.pop(),
                message_re="^another library has patched.*User\.set_password$")

            #mess with user.check_password, make sure it's detected
            dam.User.check_password = dummy
            utils.set_django_password_context(django_context)
            self.assert_patched(context=django_context)
            self.assertEquals(len(wlog), 1)
            self.assertWarningMatches(
                wlog.pop(),
                message_re="^another library has patched.*User\.check_password$"
            )

            #mess with user.check_password, make sure it's detected
            dam.check_password = dummy
            utils.set_django_password_context(django_context)
            self.assert_patched(context=django_context)
            self.assertEquals(len(wlog), 1)
            self.assertWarningMatches(
                wlog.pop(),
                message_re=
                "^another library has patched.*models:check_password$")
Example #15
0
    def test_11_encrypt_settings(self):
        "test encrypt() honors policy settings"
        cc = CryptContext(**self.sample_policy_1)

        # hash specific settings
        self.assertEqual(
            cc.encrypt("password", scheme="nthash"),
            '$NT$8846f7eaee8fb117ad06bdd830b7586c',
            )
        self.assertEqual(
            cc.encrypt("password", scheme="nthash", ident="3"),
            '$3$$8846f7eaee8fb117ad06bdd830b7586c',
            )

        # min rounds
        self.assertEqual(
            cc.encrypt("password", rounds=1999, salt="nacl"),
            '$5$rounds=2000$nacl$9/lTZ5nrfPuz8vphznnmHuDGFuvjSNvOEDsGmGfsS97',
            )
        self.assertEqual(
            cc.encrypt("password", rounds=2001, salt="nacl"),
            '$5$rounds=2001$nacl$8PdeoPL4aXQnJ0woHhqgIw/efyfCKC2WHneOpnvF.31'
            )

        #TODO:
        # max rounds
        # default rounds
        #       falls back to max, then min.
        #       specified
        #       outside of min/max range
        # default+vary rounds
        # default+vary % rounds

        #make sure default > max doesn't cause error when vary is set
        cc2 = cc.replace(sha256_crypt__default_rounds=4000)
        with catch_warnings():
            warnings.filterwarnings("ignore", "vary default rounds: lower bound > upper bound.*", UserWarning)
            self.assertEqual(
                cc2.encrypt("password", salt="nacl"),
                '$5$rounds=3000$nacl$oH831OVMbkl.Lbw1SXflly4dW8L3mSxpxDz1u1CK/B0',
                )
Example #16
0
    def test_90_bcrypt_normhash(self):
        "teset verify_and_update / hash_needs_update corrects bcrypt padding"
        # see issue 25.
        bcrypt = hash.bcrypt
        
        PASS1 = "loppux"
        BAD1  = "$2a$12$oaQbBqq8JnSM1NHRPQGXORm4GCUMqp7meTnkft4zgSnrbhoKdDV0C"
        GOOD1 = "$2a$12$oaQbBqq8JnSM1NHRPQGXOOm4GCUMqp7meTnkft4zgSnrbhoKdDV0C"
        ctx = CryptContext(["bcrypt"])
        
        with catch_warnings(record=True) as wlog:
            warnings.simplefilter("always")

            self.assertTrue(ctx.hash_needs_update(BAD1))
            self.assertFalse(ctx.hash_needs_update(GOOD1))
    
            if bcrypt.has_backend():            
                self.assertEquals(ctx.verify_and_update(PASS1,GOOD1), (True,None))
                self.assertEquals(ctx.verify_and_update("x",BAD1), (False,None))
                res = ctx.verify_and_update(PASS1, BAD1)
                self.assertTrue(res[0] and res[1] and res[1] != BAD1)
    def test_get_crypt_handler(self):
        "test get_crypt_handler()"

        class dummy_1(uh.StaticHandler):
            name = "dummy_1"

        # without available handler
        self.assertRaises(KeyError, get_crypt_handler, "dummy_1")
        self.assertIs(get_crypt_handler("dummy_1", None), None)

        # already loaded handler
        register_crypt_handler(dummy_1)
        self.assertIs(get_crypt_handler("dummy_1"), dummy_1)

        with catch_warnings():
            warnings.filterwarnings("ignore", "handler names should be lower-case, and use underscores instead of hyphens:.*", UserWarning)

            # already loaded handler, using incorrect name
            self.assertIs(get_crypt_handler("DUMMY-1"), dummy_1)

            # lazy load of unloaded handler, using incorrect name
            register_crypt_handler_path('dummy_0', __name__)
            self.assertIs(get_crypt_handler("DUMMY-0"), dummy_0)
    def test_30_norm_rounds(self):
        "test GenericHandler+HasRounds: .norm_rounds()"
        class d1(uh.HasRounds, uh.GenericHandler):
            name = 'd1'
            setting_kwds = ('rounds',)
            min_rounds = 1
            max_rounds = 3
            default_rounds = 2

        #check rounds=None
        self.assertEqual(d1.norm_rounds(None), 2)
        self.assertRaises(ValueError, d1.norm_rounds, None, strict=True)

        #check small & large rounds
        with catch_warnings():
            warnings.filterwarnings("ignore", ".* does not allow (less|more) than \d rounds: .*", UserWarning)
            self.assertEqual(d1.norm_rounds(0), 1)
            self.assertEqual(d1.norm_rounds(4), 3)
        self.assertRaises(ValueError, d1.norm_rounds, 0, strict=True)
        self.assertRaises(ValueError, d1.norm_rounds, 4, strict=True)

        #check no default rounds
        d1.default_rounds = None
        self.assertRaises(ValueError, d1.norm_rounds, None)
    def test_01_patch_control_detection(self):
        "test set_django_password_context detection of foreign monkeypatches"
        def dummy():
            pass

        with catch_warnings(record=True) as wlog:
            warnings.simplefilter("always")

            #patch to use stock django context
            utils.set_django_password_context(django_context)
            self.assert_patched(context=django_context)
            self.assertEquals(len(wlog), 0)

            #mess with User.set_password, make sure it's detected
            dam.User.set_password = dummy
            utils.set_django_password_context(django_context)
            self.assert_patched(context=django_context)
            self.assertEquals(len(wlog), 1)
            self.assertWarningMatches(wlog.pop(),
                message_re="^another library has patched.*User\.set_password$")

            #mess with user.check_password, make sure it's detected
            dam.User.check_password = dummy
            utils.set_django_password_context(django_context)
            self.assert_patched(context=django_context)
            self.assertEquals(len(wlog), 1)
            self.assertWarningMatches(wlog.pop(),
                message_re="^another library has patched.*User\.check_password$")

            #mess with user.check_password, make sure it's detected
            dam.check_password = dummy
            utils.set_django_password_context(django_context)
            self.assert_patched(context=django_context)
            self.assertEquals(len(wlog), 1)
            self.assertWarningMatches(wlog.pop(),
                message_re="^another library has patched.*models:check_password$")
Example #20
0
    def test_20_norm_salt(self):
        "test GenericHandler + HasSalt mixin"
        # setup helpers
        class d1(uh.HasSalt, uh.GenericHandler):
            name = 'd1'
            setting_kwds = ('salt',)
            min_salt_size = 2
            max_salt_size = 4
            default_salt_size = 3
            salt_chars = 'ab'

        def norm_salt(**k):
            return d1(**k).salt

        def gen_salt(sz, **k):
            return d1(use_defaults=True, salt_size=sz, **k).salt

        salts2 = _makelang('ab', 2)
        salts3 = _makelang('ab', 3)
        salts4 = _makelang('ab', 4)

        # check salt=None
        self.assertRaises(TypeError, norm_salt)
        self.assertRaises(TypeError, norm_salt, salt=None)
        self.assertIn(norm_salt(use_defaults=True), salts3)

        # check explicit salts
        with catch_warnings(record=True) as wlog:

            # check too-small salts
            self.assertRaises(ValueError, norm_salt, salt='')
            self.assertRaises(ValueError, norm_salt, salt='a')
            self.consumeWarningList(wlog)

            # check correct salts
            self.assertEqual(norm_salt(salt='ab'), 'ab')
            self.assertEqual(norm_salt(salt='aba'), 'aba')
            self.assertEqual(norm_salt(salt='abba'), 'abba')
            self.consumeWarningList(wlog)

            # check too-large salts
            self.assertRaises(ValueError, norm_salt, salt='aaaabb')
            self.consumeWarningList(wlog)

            self.assertEqual(norm_salt(salt='aaaabb', relaxed=True), 'aaaa')
            self.consumeWarningList(wlog, PasslibHashWarning)

        # check generated salts
        with catch_warnings(record=True) as wlog:

            # check too-small salt size
            self.assertRaises(ValueError, gen_salt, 0)
            self.assertRaises(ValueError, gen_salt, 1)
            self.consumeWarningList(wlog)

            # check correct salt size
            self.assertIn(gen_salt(2), salts2)
            self.assertIn(gen_salt(3), salts3)
            self.assertIn(gen_salt(4), salts4)
            self.consumeWarningList(wlog)

            # check too-large salt size
            self.assertRaises(ValueError, gen_salt, 5)
            self.consumeWarningList(wlog)

            self.assertIn(gen_salt(5, relaxed=True), salts4)
            self.consumeWarningList(wlog, ["salt too large"])

        # test with max_salt_size=None
        del d1.max_salt_size
        with self.assertWarningList([]):
            self.assertEqual(len(gen_salt(None)), 3)
            self.assertEqual(len(gen_salt(5)), 5)
Example #21
0
    def test_91_bcrypt_padding(self):
        "test passlib correctly handles bcrypt padding bits"
        bcrypt = self.handler

        def check_warning(wlog):
            self.assertWarningMatches(
                wlog.pop(0),
                message_re=
                "^encountered a bcrypt hash with incorrectly set padding bits.*",
            )
            self.assertFalse(wlog)

        def check_padding(hash):
            "check bcrypt hash doesn't have salt padding bits set"
            assert hash.startswith("$2a$") and len(hash) >= 28
            self.assertTrue(hash[28] in BSLAST,
                            "padding bits set in hash: %r" % (hash, ))

        #===============================================================
        # test generated salts
        #===============================================================
        from passlib.handlers.bcrypt import BCHARS, BSLAST

        # make sure genconfig & encrypt don't return bad hashes.
        # bug had 15/16 chance of occurring every time salt generated.
        # so we call it a few different way a number of times.
        for i in xrange(6):
            check_padding(bcrypt.genconfig())
        for i in xrange(3):
            check_padding(bcrypt.encrypt("bob", rounds=bcrypt.min_rounds))

        # check passing salt to genconfig causes it to be normalized.
        with catch_warnings(record=True) as wlog:
            warnings.simplefilter("always")

            hash = bcrypt.genconfig(salt="." * 21 + "A.")
            check_warning(wlog)
            self.assertEqual(hash, "$2a$12$" + "." * 22)

            hash = bcrypt.genconfig(salt="." * 23)
            self.assertFalse(wlog)
            self.assertEqual(hash, "$2a$12$" + "." * 22)

        #===============================================================
        # test handling existing hashes
        #===============================================================

        # 2 bits of salt padding set
        PASS1 = "loppux"
        BAD1 = "$2a$12$oaQbBqq8JnSM1NHRPQGXORm4GCUMqp7meTnkft4zgSnrbhoKdDV0C"
        GOOD1 = "$2a$12$oaQbBqq8JnSM1NHRPQGXOOm4GCUMqp7meTnkft4zgSnrbhoKdDV0C"

        # all 4 bits of salt padding set
        PASS2 = "Passlib11"
        BAD2 = "$2a$12$M8mKpW9a2vZ7PYhq/8eJVcUtKxpo6j0zAezu0G/HAMYgMkhPu4fLK"
        GOOD2 = "$2a$12$M8mKpW9a2vZ7PYhq/8eJVOUtKxpo6j0zAezu0G/HAMYgMkhPu4fLK"

        # bad checksum padding
        PASS3 = "test"
        BAD3 = "$2a$04$yjDgE74RJkeqC0/1NheSSOrvKeu9IbKDpcQf/Ox3qsrRS/Kw42qIV"
        GOOD3 = "$2a$04$yjDgE74RJkeqC0/1NheSSOrvKeu9IbKDpcQf/Ox3qsrRS/Kw42qIS"

        # make sure genhash() corrects input
        with catch_warnings(record=True) as wlog:
            warnings.simplefilter("always")

            self.assertEqual(bcrypt.genhash(PASS1, BAD1), GOOD1)
            check_warning(wlog)

            self.assertEqual(bcrypt.genhash(PASS2, BAD2), GOOD2)
            check_warning(wlog)

            self.assertEqual(bcrypt.genhash(PASS2, GOOD2), GOOD2)
            self.assertFalse(wlog)

            self.assertEqual(bcrypt.genhash(PASS3, BAD3), GOOD3)
            check_warning(wlog)
            self.assertFalse(wlog)

        # make sure verify works on both bad and good hashes
        with catch_warnings(record=True) as wlog:
            warnings.simplefilter("always")

            self.assertTrue(bcrypt.verify(PASS1, BAD1))
            check_warning(wlog)

            self.assertTrue(bcrypt.verify(PASS1, GOOD1))
            self.assertFalse(wlog)

        #===============================================================
        # test normhash cleans things up correctly
        #===============================================================
        with catch_warnings(record=True) as wlog:
            warnings.simplefilter("always")
            self.assertEqual(bcrypt.normhash(BAD1), GOOD1)
            self.assertEqual(bcrypt.normhash(BAD2), GOOD2)
            self.assertEqual(bcrypt.normhash(GOOD1), GOOD1)
            self.assertEqual(bcrypt.normhash(GOOD2), GOOD2)
            self.assertEqual(bcrypt.normhash("$md5$abc"), "$md5$abc")
    def test_91_bcrypt_padding(self):
        "test passlib correctly handles bcrypt padding bits"
        bcrypt = self.handler

        def check_warning(wlog):
            self.assertWarningMatches(wlog.pop(0),
                message_re="^encountered a bcrypt hash with incorrectly set padding bits.*",
            )
            self.assertFalse(wlog)

        def check_padding(hash):
            "check bcrypt hash doesn't have salt padding bits set"
            assert hash.startswith("$2a$") and len(hash) >= 28
            self.assertTrue(hash[28] in BSLAST,
                            "padding bits set in hash: %r" % (hash,))

        #===============================================================
        # test generated salts
        #===============================================================
        from passlib.handlers.bcrypt import BCHARS, BSLAST

        # make sure genconfig & encrypt don't return bad hashes.
        # bug had 15/16 chance of occurring every time salt generated.
        # so we call it a few different way a number of times.
        for i in xrange(6):
            check_padding(bcrypt.genconfig())
        for i in xrange(3):
            check_padding(bcrypt.encrypt("bob", rounds=bcrypt.min_rounds))

        # check passing salt to genconfig causes it to be normalized.
        with catch_warnings(record=True) as wlog:
            warnings.simplefilter("always")

            hash = bcrypt.genconfig(salt="."*21 + "A.")
            check_warning(wlog)
            self.assertEqual(hash, "$2a$12$" + "." * 22)

            hash = bcrypt.genconfig(salt="."*23)
            self.assertFalse(wlog)
            self.assertEqual(hash, "$2a$12$" + "." * 22)

        #===============================================================
        # test handling existing hashes
        #===============================================================

        # 2 bits of salt padding set
        PASS1 = "loppux"
        BAD1  = "$2a$12$oaQbBqq8JnSM1NHRPQGXORm4GCUMqp7meTnkft4zgSnrbhoKdDV0C"
        GOOD1 = "$2a$12$oaQbBqq8JnSM1NHRPQGXOOm4GCUMqp7meTnkft4zgSnrbhoKdDV0C"

        # all 4 bits of salt padding set
        PASS2 = "Passlib11"
        BAD2  = "$2a$12$M8mKpW9a2vZ7PYhq/8eJVcUtKxpo6j0zAezu0G/HAMYgMkhPu4fLK"
        GOOD2 = "$2a$12$M8mKpW9a2vZ7PYhq/8eJVOUtKxpo6j0zAezu0G/HAMYgMkhPu4fLK"

        # bad checksum padding
        PASS3 = "test"
        BAD3  = "$2a$04$yjDgE74RJkeqC0/1NheSSOrvKeu9IbKDpcQf/Ox3qsrRS/Kw42qIV"
        GOOD3 = "$2a$04$yjDgE74RJkeqC0/1NheSSOrvKeu9IbKDpcQf/Ox3qsrRS/Kw42qIS"

        # make sure genhash() corrects input
        with catch_warnings(record=True) as wlog:
            warnings.simplefilter("always")

            self.assertEqual(bcrypt.genhash(PASS1, BAD1), GOOD1)
            check_warning(wlog)

            self.assertEqual(bcrypt.genhash(PASS2, BAD2), GOOD2)
            check_warning(wlog)

            self.assertEqual(bcrypt.genhash(PASS2, GOOD2), GOOD2)
            self.assertFalse(wlog)
            
            self.assertEqual(bcrypt.genhash(PASS3, BAD3), GOOD3)
            check_warning(wlog)
            self.assertFalse(wlog)
            
        # make sure verify works on both bad and good hashes
        with catch_warnings(record=True) as wlog:
            warnings.simplefilter("always")

            self.assertTrue(bcrypt.verify(PASS1, BAD1))
            check_warning(wlog)

            self.assertTrue(bcrypt.verify(PASS1, GOOD1))
            self.assertFalse(wlog)

        #===============================================================
        # test normhash cleans things up correctly
        #===============================================================
        with catch_warnings(record=True) as wlog:
            warnings.simplefilter("always")
            self.assertEqual(bcrypt.normhash(BAD1), GOOD1)
            self.assertEqual(bcrypt.normhash(BAD2), GOOD2)
            self.assertEqual(bcrypt.normhash(GOOD1), GOOD1)
            self.assertEqual(bcrypt.normhash(GOOD2), GOOD2)
            self.assertEqual(bcrypt.normhash("$md5$abc"), "$md5$abc")
    def test_20_norm_salt(self):
        "test GenericHandler + HasSalt mixin"
        # setup helpers
        class d1(uh.HasSalt, uh.GenericHandler):
            name = 'd1'
            setting_kwds = ('salt',)
            min_salt_size = 2
            max_salt_size = 4
            default_salt_size = 3
            salt_chars = 'ab'

        def norm_salt(**k):
            return d1(**k).salt

        def gen_salt(sz, **k):
            return d1(use_defaults=True, salt_size=sz, **k).salt

        salts2 = _makelang('ab', 2)
        salts3 = _makelang('ab', 3)
        salts4 = _makelang('ab', 4)

        # check salt=None
        self.assertRaises(TypeError, norm_salt)
        self.assertRaises(TypeError, norm_salt, salt=None)
        self.assertIn(norm_salt(use_defaults=True), salts3)

        # check explicit salts
        with catch_warnings(record=True) as wlog:

            # check too-small salts
            self.assertRaises(ValueError, norm_salt, salt='')
            self.assertRaises(ValueError, norm_salt, salt='a')
            self.consumeWarningList(wlog)

            # check correct salts
            self.assertEqual(norm_salt(salt='ab'), 'ab')
            self.assertEqual(norm_salt(salt='aba'), 'aba')
            self.assertEqual(norm_salt(salt='abba'), 'abba')
            self.consumeWarningList(wlog)

            # check too-large salts
            self.assertRaises(ValueError, norm_salt, salt='aaaabb')
            self.consumeWarningList(wlog)

            self.assertEqual(norm_salt(salt='aaaabb', relaxed=True), 'aaaa')
            self.consumeWarningList(wlog, PasslibHashWarning)

        # check generated salts
        with catch_warnings(record=True) as wlog:

            # check too-small salt size
            self.assertRaises(ValueError, gen_salt, 0)
            self.assertRaises(ValueError, gen_salt, 1)
            self.consumeWarningList(wlog)

            # check correct salt size
            self.assertIn(gen_salt(2), salts2)
            self.assertIn(gen_salt(3), salts3)
            self.assertIn(gen_salt(4), salts4)
            self.consumeWarningList(wlog)

            # check too-large salt size
            self.assertRaises(ValueError, gen_salt, 5)
            self.consumeWarningList(wlog)

            self.assertIn(gen_salt(5, relaxed=True), salts4)
            self.consumeWarningList(wlog, ["salt too large"])

        # test with max_salt_size=None
        del d1.max_salt_size
        with self.assertWarningList([]):
            self.assertEqual(len(gen_salt(None)), 3)
            self.assertEqual(len(gen_salt(5)), 5)