Example #1
0
    def test_register_crypt_handler(self):
        """test register_crypt_handler()"""

        self.assertRaises(TypeError, register_crypt_handler, {})

        self.assertRaises(ValueError, register_crypt_handler, type('x', (uh.StaticHandler,), dict(name=None)))
        self.assertRaises(ValueError, register_crypt_handler, type('x', (uh.StaticHandler,), dict(name="AB_CD")))
        self.assertRaises(ValueError, register_crypt_handler, type('x', (uh.StaticHandler,), dict(name="ab-cd")))
        self.assertRaises(ValueError, register_crypt_handler, type('x', (uh.StaticHandler,), dict(name="ab__cd")))
        self.assertRaises(ValueError, register_crypt_handler, type('x', (uh.StaticHandler,), dict(name="default")))

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

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

        self.assertTrue('dummy_1' not in list_crypt_handlers())

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

        self.assertRaises(KeyError, register_crypt_handler, dummy_1b)
        self.assertIs(get_crypt_handler("dummy_1"), dummy_1)

        register_crypt_handler(dummy_1b, force=True)
        self.assertIs(get_crypt_handler("dummy_1"), dummy_1b)

        self.assertTrue('dummy_1' in list_crypt_handlers())
Example #2
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 warnings.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)
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 warnings.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
        from passlib import hash
        hash.__dict__["_fake"] = "dummy"
        for name in ["_fake", "__package__"]:
            self.assertRaises(KeyError, get_crypt_handler, name)
            self.assertIs(get_crypt_handler(name, None), None)
Example #4
0
    def test_register_crypt_handler(self):
        """test register_crypt_handler()"""

        self.assertRaises(TypeError, register_crypt_handler, {})

        self.assertRaises(ValueError, register_crypt_handler, type('x', (uh.StaticHandler,), dict(name=None)))
        self.assertRaises(ValueError, register_crypt_handler, type('x', (uh.StaticHandler,), dict(name="AB_CD")))
        self.assertRaises(ValueError, register_crypt_handler, type('x', (uh.StaticHandler,), dict(name="ab-cd")))
        self.assertRaises(ValueError, register_crypt_handler, type('x', (uh.StaticHandler,), dict(name="ab__cd")))
        self.assertRaises(ValueError, register_crypt_handler, type('x', (uh.StaticHandler,), dict(name="default")))

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

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

        self.assertTrue('dummy_1' not in list_crypt_handlers())

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

        self.assertRaises(KeyError, register_crypt_handler, dummy_1b)
        self.assertIs(get_crypt_handler("dummy_1"), dummy_1)

        register_crypt_handler(dummy_1b, force=True)
        self.assertIs(get_crypt_handler("dummy_1"), dummy_1b)

        self.assertTrue('dummy_1' in list_crypt_handlers())
    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 #6
0
def get_passlib_hasher(handler, algorithm=None):
    """create *Hasher*-compatible wrapper for specified passlib hash.

    This takes in the name of a passlib hash (or the handler object itself),
    and returns a wrapper instance which should be compatible with
    Django 1.4's Hashers framework.

    If the named hash corresponds to one of Django's builtin hashers,
    an instance of the real hasher class will be returned.

    Note that the format of the handler won't be altered,
    so will probably not be compatible with Django's algorithm format,
    so the monkeypatch provided by this plugin must have been applied.
    """
    if isinstance(handler, str):
        handler = get_crypt_handler(handler)
    if hasattr(handler, "django_name"):
        # return native hasher instance
        # XXX: should add this to _hasher_cache[]
        name = handler.django_name
        if name == "sha1" and algorithm == "unsalted_sha1":
            # django 1.4.6+ uses a separate hasher for "sha1$$digest" hashes,
            # but passlib just reuses the "sha1$salt$digest" handler.
            # we want to resolve to correct django hasher.
            name = algorithm
        return _get_hasher(name)
    if handler.name == "django_disabled":
        raise ValueError("can't wrap unusable-password handler")
    try:
        return _hasher_cache[handler]
    except KeyError:
        name = "Passlib_%s_PasswordHasher" % handler.name.title()
        cls = type(name, (_HasherWrapper, ), dict(passlib_handler=handler))
        hasher = _hasher_cache[handler] = cls()
        return hasher
Example #7
0
def get_passlib_hasher(handler, algorithm=None):
    """create *Hasher*-compatible wrapper for specified passlib hash.

    This takes in the name of a passlib hash (or the handler object itself),
    and returns a wrapper instance which should be compatible with
    Django 1.4's Hashers framework.

    If the named hash corresponds to one of Django's builtin hashers,
    an instance of the real hasher class will be returned.

    Note that the format of the handler won't be altered,
    so will probably not be compatible with Django's algorithm format,
    so the monkeypatch provided by this plugin must have been applied.
    """
    if isinstance(handler, str):
        handler = get_crypt_handler(handler)
    if hasattr(handler, "django_name"):
        # return native hasher instance
        # XXX: should add this to _hasher_cache[]
        name = handler.django_name
        if name == "sha1" and algorithm == "unsalted_sha1":
            # django 1.4.6+ uses a separate hasher for "sha1$$digest" hashes,
            # but passlib just reuses the "sha1$salt$digest" handler.
            # we want to resolve to correct django hasher.
            name = algorithm
        return _get_hasher(name)
    if handler.name == "django_disabled":
        raise ValueError("can't wrap unusable-password handler")
    try:
        return _hasher_cache[handler]
    except KeyError:
        name = "Passlib_%s_PasswordHasher" % handler.name.title()
        cls = type(name, (_HasherWrapper,), dict(passlib_handler=handler))
        hasher = _hasher_cache[handler] = cls()
        return hasher
Example #8
0
def get_passlib_hasher(handler):
    """create *Hasher*-compatible wrapper for specified passlib hash.

    This takes in the name of a passlib hash (or the handler object itself),
    and returns a wrapper instance which should be compatible with
    Django 1.4's Hashers framework.

    If the named hash corresponds to one of Django's builtin hashers,
    an instance of the real hasher class will be returned.

    Note that the format of the handler won't be altered,
    so will probably not be compatible with Django's algorithm format,
    so the monkeypatch provided by this plugin must have been applied.

    .. note::
        This function requires Django 1.4 or later.
    """
    if DJANGO_VERSION < (1,4):
        raise RuntimeError("get_passlib_hasher() requires Django >= 1.4")
    if isinstance(handler, str):
        handler = get_crypt_handler(handler)
    if hasattr(handler, "django_name"):
        # return native hasher instance
        # XXX: should cache this too.
        return _get_hasher(handler.django_name)
    if handler.name == "django_disabled":
        raise ValueError("can't wrap unusable-password handler")
    try:
        return _hasher_cache[handler]
    except KeyError:
        name = "Passlib_%s_PasswordHasher" % handler.name.title()
        cls = type(name, (_HasherWrapper,), dict(passlib_handler=handler))
        hasher = _hasher_cache[handler] = cls()
        return hasher
Example #9
0
    def test_hash_proxy(self):
        """test passlib.hash proxy object"""
        # check dir works
        dir(hash)

        # check repr works
        repr(hash)

        # check non-existent attrs raise error
        self.assertRaises(AttributeError, getattr, hash, 'fooey')

        # GAE tries to set __loader__,
        # make sure that doesn't call register_crypt_handler.
        old = getattr(hash, "__loader__", None)
        test = object()
        hash.__loader__ = test
        self.assertIs(hash.__loader__, test)
        if old is None:
            del hash.__loader__
            self.assertFalse(hasattr(hash, "__loader__"))
        else:
            hash.__loader__ = old
            self.assertIs(hash.__loader__, old)

        # check storing attr calls register_crypt_handler
        class dummy_1(uh.StaticHandler):
            name = "dummy_1"

        hash.dummy_1 = dummy_1
        self.assertIs(get_crypt_handler("dummy_1"), dummy_1)

        # check storing under wrong name results in error
        self.assertRaises(ValueError, setattr, hash, "dummy_1x", dummy_1)
Example #10
0
    def test_hash_proxy(self):
        """test passlib.hash proxy object"""
        # check dir works
        dir(hash)

        # check repr works
        repr(hash)

        # check non-existent attrs raise error
        self.assertRaises(AttributeError, getattr, hash, 'fooey')

        # GAE tries to set __loader__,
        # make sure that doesn't call register_crypt_handler.
        old = getattr(hash, "__loader__", None)
        test = object()
        hash.__loader__ = test
        self.assertIs(hash.__loader__, test)
        if old is None:
            del hash.__loader__
            self.assertFalse(hasattr(hash, "__loader__"))
        else:
            hash.__loader__ = old
            self.assertIs(hash.__loader__, old)

        # check storing attr calls register_crypt_handler
        class dummy_1(uh.StaticHandler):
            name = "dummy_1"
        hash.dummy_1 = dummy_1
        self.assertIs(get_crypt_handler("dummy_1"), dummy_1)

        # check storing under wrong name results in error
        self.assertRaises(ValueError, setattr, hash, "dummy_1x", dummy_1)
Example #11
0
def get_passlib_hasher(handler):
    """create *Hasher*-compatible wrapper for specified passlib hash.

    This takes in the name of a passlib hash (or the handler object itself),
    and returns a wrapper instance which should be compatible with
    Django 1.4's Hashers framework.

    If the named hash corresponds to one of Django's builtin hashers,
    an instance of the real hasher class will be returned.

    Note that the format of the handler won't be altered,
    so will probably not be compatible with Django's algorithm format,
    so the monkeypatch provided by this plugin must have been applied.

    .. note::
        This function requires Django 1.4 or later.
    """
    if DJANGO_VERSION < (1, 4):
        raise RuntimeError("get_passlib_hasher() requires Django >= 1.4")
    if isinstance(handler, str):
        handler = get_crypt_handler(handler)
    if hasattr(handler, "django_name"):
        # return native hasher instance
        # XXX: should cache this too.
        return _get_hasher(handler.django_name)
    if handler.name == "django_disabled":
        raise ValueError("can't wrap unusable-password handler")
    try:
        return _hasher_cache[handler]
    except KeyError:
        name = "Passlib_%s_PasswordHasher" % handler.name.title()
        cls = type(name, (_HasherWrapper, ), dict(passlib_handler=handler))
        hasher = _hasher_cache[handler] = cls()
        return hasher
Example #12
0
 def _get_wrapped(self):
     handler = self._wrapped_handler
     if handler is None:
         handler = get_crypt_handler(self._wrapped_name)
         self._check_handler(handler)
         self._wrapped_handler = handler
     return handler
Example #13
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 warnings.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 #14
0
 def _get_passlib_hasher(self, passlib_name):
     """
     resolve passlib hasher by name, using context if available.
     """
     context = self.context
     if context is None:
         return registry.get_crypt_handler(passlib_name)
     else:
         return context.handler(passlib_name)
Example #15
0
 def _get_passlib_hasher(self, passlib_name):
     """
     resolve passlib hasher by name, using context if available.
     """
     context = self.context
     if context is None:
         return registry.get_crypt_handler(passlib_name)
     else:
         return context.handler(passlib_name)
Example #16
0
def hasher_to_passlib_name(hasher_name):
    "convert hasher name -> passlib handler name"
    if hasher_name.startswith(PASSLIB_HASHER_PREFIX):
        return hasher_name[len(PASSLIB_HASHER_PREFIX):]
    for name in list_crypt_handlers():
        if name.startswith(DJANGO_PASSLIB_PREFIX) or name in _other_django_hashes:
            handler = get_crypt_handler(name)
            if getattr(handler, "django_name", None) == hasher_name:
                return name
    # XXX: this should only happen for custom hashers that have been registered.
    #      work in progress (below) that would take care of those.
    raise ValueError("can't translate hasher name to passlib name: %r" %
                     hasher_name)
Example #17
0
def hasher_to_passlib_name(hasher_name):
    "convert hasher name -> passlib handler name"
    if hasher_name.startswith(PASSLIB_HASHER_PREFIX):
        return hasher_name[len(PASSLIB_HASHER_PREFIX):]
    for name in list_crypt_handlers():
        if name.startswith(
                DJANGO_PASSLIB_PREFIX) or name in _other_django_hashes:
            handler = get_crypt_handler(name)
            if getattr(handler, "django_name", None) == hasher_name:
                return name
    # XXX: this should only happen for custom hashers that have been registered.
    #      _HasherHandler (below) is work in progress that would fix this.
    raise ValueError("can't translate hasher name to passlib name: %r" %
                     hasher_name)
    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 check_hashes(self, tests, new_hash=None, deprecated=None):
        u = FakeUser()
        deprecated = None

        # check new hash construction
        if new_hash:
            u.set_password("placeholder")
            handler = get_crypt_handler(new_hash)
            self.assertTrue(handler.identify(u.password))

        # run against hashes from tests...
        for test in tests:
            for secret, hash in test.all_correct_hashes:

                # check against valid password
                u.password = hash
                if has_django0 and isinstance(secret, unicode):
                    secret = secret.encode("utf-8")
                self.assertTrue(u.check_password(secret))
                if new_hash and deprecated and test.handler.name in deprecated:
                    self.assertFalse(handler.identify(hash))
                    self.assertTrue(handler.identify(u.password))

                # check against invalid password
                u.password = hash
                self.assertFalse(u.check_password('x'+secret))
                if new_hash and deprecated and test.handler.name in deprecated:
                    self.assertFalse(handler.identify(hash))
                    self.assertEquals(u.password, hash)

        # check disabled handling
        if has_django1:
            u.set_password(None)
            handler = get_crypt_handler("django_disabled")
            self.assertTrue(handler.identify(u.password))
            self.assertFalse(u.check_password('placeholder'))
Example #20
0
    def check_hashes(self, tests, new_hash=None, deprecated=None):
        u = FakeUser()
        deprecated = None

        # check new hash construction
        if new_hash:
            u.set_password("placeholder")
            handler = get_crypt_handler(new_hash)
            self.assertTrue(handler.identify(u.password))

        # run against hashes from tests...
        for test in tests:
            for secret, hash in test.all_correct_hashes:

                # check against valid password
                u.password = hash
                if has_django0 and isinstance(secret, unicode):
                    secret = secret.encode("utf-8")
                self.assertTrue(u.check_password(secret))
                if new_hash and deprecated and test.handler.name in deprecated:
                    self.assertFalse(handler.identify(hash))
                    self.assertTrue(handler.identify(u.password))

                # check against invalid password
                u.password = hash
                self.assertFalse(u.check_password('x' + secret))
                if new_hash and deprecated and test.handler.name in deprecated:
                    self.assertFalse(handler.identify(hash))
                    self.assertEquals(u.password, hash)

        # check disabled handling
        if has_django1:
            u.set_password(None)
            handler = get_crypt_handler("django_disabled")
            self.assertTrue(handler.identify(u.password))
            self.assertFalse(u.check_password('placeholder'))
Example #21
0
 def _iter_os_crypt_schemes():
     "helper which iterates over supported os_crypt schemes"
     found = False
     for name in unix_crypt_schemes:
         handler = get_crypt_handler(name)
         if handler.has_backend("os_crypt"):
             found = True
             yield name
     if found:
         #only offer fallback if there's another scheme in front,
         #as this can't actually hash any passwords
         yield "unix_fallback"
     else:
         #no idea what OS this could happen on, but just in case...
         warn("crypt.crypt() function is present, but doesn't support any formats known to passlib!")
Example #22
0
 def _iter_os_crypt_schemes():
     "helper which iterates over supported os_crypt schemes"
     found = False
     for name in unix_crypt_schemes:
         handler = get_crypt_handler(name)
         if handler.has_backend("os_crypt"):
             found = True
             yield name
     if found:
         # only offer disabled handler if there's another scheme in front,
         # as this can't actually hash any passwords
         yield "unix_disabled"
     else: # pragma: no cover -- sanity check
         # no idea what OS this could happen on...
         warn("crypt.crypt() function is present, but doesn't support any "
              "formats known to passlib!", PasslibRuntimeWarning)
Example #23
0
 def _iter_os_crypt_schemes():
     """helper which iterates over supported os_crypt schemes"""
     found = False
     for name in unix_crypt_schemes:
         handler = get_crypt_handler(name)
         if handler.has_backend("os_crypt"):
             found = True
             yield name
     if found:
         # only offer disabled handler if there's another scheme in front,
         # as this can't actually hash any passwords
         yield "unix_disabled"
     else: # pragma: no cover -- sanity check
         # no idea what OS this could happen on...
         warn("crypt.crypt() function is present, but doesn't support any "
              "formats known to passlib!", PasslibRuntimeWarning)
Example #24
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 warnings.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 #25
0
 def _iter_os_crypt_schemes():
     "helper which iterates over supported os_crypt schemes"
     found = False
     for name in unix_crypt_schemes:
         handler = get_crypt_handler(name)
         if handler.has_backend("os_crypt"):
             found = True
             yield name
     if found:
         #only offer fallback if there's another scheme in front,
         #as this can't actually hash any passwords
         yield "unix_fallback"
     else:
         #no idea what OS this could happen on, but just in case...
         warn(
             "crypt.crypt() function is present, but doesn't support any formats known to passlib!"
         )
Example #26
0
def hasher_to_passlib_name(hasher_name):
    """convert hasher name -> passlib handler name"""
    if hasher_name.startswith(PASSLIB_HASHER_PREFIX):
        return hasher_name[len(PASSLIB_HASHER_PREFIX):]
    if hasher_name == "unsalted_sha1":
        # django 1.4.6+ uses a separate hasher for "sha1$$digest" hashes,
        # but passlib just reuses the "sha1$salt$digest" handler.
        hasher_name = "sha1"
    for name in list_crypt_handlers():
        if name.startswith(DJANGO_PASSLIB_PREFIX) or name in _other_django_hashes:
            handler = get_crypt_handler(name)
            if getattr(handler, "django_name", None) == hasher_name:
                return name
    # XXX: this should only happen for custom hashers that have been registered.
    #      _HasherHandler (below) is work in progress that would fix this.
    raise ValueError("can't translate hasher name to passlib name: %r" %
                     hasher_name)
Example #27
0
    def __init__(self, name, samples=1):
        #
        #get handler, extract boundary information
        #
        self.handler = handler = get_crypt_handler(name)
        if 'rounds' not in handler.setting_kwds:
            raise ValueError("scheme does not support rounds: %r" % (handler.name,))
        self.min_rounds = getattr(handler, "min_rounds", 2)
        self.max_rounds = getattr(handler, "max_rounds", (1<<32)-1)
        rc = self.rounds_cost = getattr(handler, "rounds_cost", "linear")

        #
        #set up functions that vary based on rounds cost function
        #
        if rc == "linear":
            def get_rps(rounds, delta):
                return rounds/delta
            def guess_rounds(rps, target):
                return int(rps*target+.5)
            erradj = 2
        elif rc == "log2":
            def get_rps(rounds, delta):
                return (2**rounds)/delta
            def guess_rounds(rps, target):
                return int(logb(rps*target,2)+.5)
            erradj = 1.1
        else:
            raise NotImplementedError("unknown rounds cost function: %r" % (rc,))
        self.get_rps = get_rps
        self.guess_rounds = guess_rounds
        self.erradj = erradj

        #
        #init cache
        #
        self.samples = samples
        self.cache = {}
        self.srange = range(samples)
Example #28
0
import base64
import hashlib

import passlib.exc as exc
import passlib.utils.handlers as uh

from passlib.registry import get_crypt_handler
from passlib.utils import to_unicode
from passlib.utils.compat import uascii_to_str

passlib_bcrypt = get_crypt_handler("bcrypt")


class bcrypt_sha1(uh.StaticHandler):

    name = "bcrypt_sha1"
    _hash_prefix = u"$bcrypt_sha1$"

    def _calc_checksum(self, secret):
        # Hash the secret with sha1 first
        secret = hashlib.sha1(secret).hexdigest()

        # Hash it with bcrypt
        return passlib_bcrypt.encrypt(secret)

    def to_string(self):
        assert self.checksum is not None
        return uascii_to_str(self._hash_prefix +
                             base64.b64encode(self.checksum))

    @classmethod
Example #29
0
File: util.py Project: lulzzz/zato
def get_hash_rounds_info(hash_algo='pbkdf2_sha512', target=200):
    """ Returns the number of rounds required for a single password verification
    using hash_algo to take target milliseconds on current CPU.
    """
    target = target / 1000.0
    hasher = get_crypt_handler(hash_algo)

    if hasher.rounds_cost == 'log2':
        # time cost varies logarithmically with rounds parameter,
        # so speed = (2**rounds) / elapsed
        def rounds_to_cost(rounds):
            return 2**rounds

        def cost_to_rounds(cost):
            return math.log(cost, 2)
    elif hasher.rounds_cost == 'linear':
        rounds_to_cost = cost_to_rounds = lambda value: value
    else:
        raise ValueError(
            'Don\'t know how to handle hasher.rounds_cost `{}`'.format(
                hasher.rounds_cost))

    def clamp_rounds(rounds):
        """ Convert float rounds to int value, clamped to hasher's limits.
        """
        if hasher.max_rounds and rounds > hasher.max_rounds:
            rounds = hasher.max_rounds
        rounds = int(rounds)
        if getattr(hasher, '_avoid_even_rounds', False):
            rounds |= 1
        return max(hasher.min_rounds, rounds)

    def average(seq):
        if not hasattr(seq, '__length__'):
            seq = tuple(seq)
        return sum(seq) / len(seq)

    def estimate_iters_per_sec(rounds):
        """ Estimate performance in interations/s using specified # of rounds.
        """
        secret = '3.14159 26535 89793 23846'  # π number
        hash = hasher.using(rounds=rounds).hash(secret)

        def helper():
            start = timer()
            hasher.verify(secret, hash)
            return timer() - start

        elapsed = min(average(helper() for _ in range(4)) for _ in range(4))
        return rounds_to_cost(rounds) / elapsed

    #---------------------------------------------------------------
    # Get rough estimate of performance using fraction of default_rounds
    # (so we don't take crazy long amounts of time on slow systems)
    #---------------------------------------------------------------
    rounds = clamp_rounds(
        cost_to_rounds(.5 * rounds_to_cost(hasher.default_rounds)))
    iters_per_sec = estimate_iters_per_sec(rounds)

    #---------------------------------------------------------------
    # Re-do estimate using previous result,
    # to get more accurate sample using a larger number of rounds.
    #---------------------------------------------------------------
    for _ in range(2):
        rounds = clamp_rounds(cost_to_rounds(iters_per_sec * target))
        iters_per_sec = estimate_iters_per_sec(rounds)

    # Actual value to use in password hashing
    rounds = cost_to_rounds(iters_per_sec * target)

    # Metadata about current CPU the computation was run on
    cpu_info = get_cpu_info()

    return {
        'iters_per_sec': int(iters_per_sec),
        'rounds': int(rounds),
        'cpu_info': {
            'vendor_id': cpu_info['vendor_id'],
            'brand': cpu_info['brand'],
            'hz_advertised': cpu_info['hz_advertised'],
            'hz_actual': cpu_info['hz_actual']
        }
    }
Example #30
0
    def django_to_passlib(self, django_name, cached=True):
        """
        Convert Django hasher / name to Passlib hasher / name.
        If present, CryptContext will be checked instead of main registry.

        :param django_name:
            Django hasher class or algorithm name.
            "default" allowed if context provided.

        :raises ValueError:
            if can't resolve hasher.

        :returns:
            passlib hasher or name
        """
        # check for django hasher
        if hasattr(django_name, "algorithm"):

            # check for passlib adapter
            if isinstance(django_name, _PasslibHasherWrapper):
                return django_name.passlib_handler

            # resolve django hasher -> name
            django_name = django_name.algorithm

        # check cache
        if cached:
            cache = self._passlib_hasher_cache
            try:
                return cache[django_name]
            except KeyError:
                pass
            result = cache[django_name] = \
                self.django_to_passlib(django_name, cached=False)
            return result

        # check if it's an obviously-wrapped name
        if django_name.startswith(PASSLIB_WRAPPER_PREFIX):
            passlib_name = django_name[len(PASSLIB_WRAPPER_PREFIX):]
            return self._get_passlib_hasher(passlib_name)

        # resolve default
        if django_name == "default":
            context = self.context
            if context is None:
                raise TypeError("can't determine default scheme w/ context")
            return context.handler()

        # special case: Django uses a separate hasher for "sha1$$digest"
        # hashes (unsalted_sha1) and "sha1$salt$digest" (sha1);
        # but passlib uses "django_salted_sha1" for both of these.
        if django_name == "unsalted_sha1":
            django_name = "sha1"

        # resolve name
        # XXX: bother caching these lists / mapping?
        #      not needed in long-term due to cache above.
        context = self.context
        if context is None:
            # check registry
            # TODO: should make iteration via registry easier
            candidates = (
                registry.get_crypt_handler(passlib_name)
                for passlib_name in registry.list_crypt_handlers()
                if passlib_name.startswith(DJANGO_COMPAT_PREFIX) or
                   passlib_name in _other_django_hashes
            )
        else:
            # check context
            candidates = context.schemes(resolve=True)
        for handler in candidates:
            if getattr(handler, "django_name", None) == django_name:
                return handler

        # give up
        # NOTE: this should only happen for custom django hashers that we don't
        #       know the equivalents for. _HasherHandler (below) is work in
        #       progress that would allow us to at least return a wrapper.
        raise ValueError("can't translate django name to passlib name: %r" %
                         (django_name,))
Example #31
0
    def _from_dict(self, kwds):
        "configure policy from constructor keywords"
        #
        #init cache & options
        #
        context_options = {}
        options = self._options = {None:{"context":context_options}}
        self._cache = {}

        #
        #normalize & sort keywords
        #
        for cat, name, opt, value in parse_policy_items(kwds):
            copts = options.get(cat)
            if copts is None:
                copts = options[cat] = {}
            config = copts.get(name)
            if config is None:
                copts[name] = {opt:value}
            else:
                config[opt] = value

        #
        #parse list of schemes, and resolve to handlers.
        #
        schemes = context_options.get("schemes") or []
        handlers = self._handlers = []
        handler_names = set()
        for scheme in schemes:
            #resolve & validate handler
            if is_crypt_handler(scheme):
                handler = scheme
            else:
                handler = get_crypt_handler(scheme)
            name = handler.name
            if not name:
                raise TypeError("handler lacks name: %r" % (handler,))

            #check name hasn't been re-used
            if name in handler_names:
                #XXX: should this just be a warning ?
                raise KeyError("multiple handlers with same name: %r" % (name,))

            #add to handler list
            handlers.append(handler)
            handler_names.add(name)

        #
        #build _deprecated & _default maps
        #
        dmap = self._deprecated = {}
        fmap = self._default = {}
        mvmap = self._min_verify_time = {}
        for cat, config in options.iteritems():
            kwds = config.pop("context", None)
            if not kwds:
                continue

            #list of deprecated schemes
            deps = kwds.get("deprecated") or []
            if deps:
                if handlers:
                    for scheme in deps:
                        if scheme not in handler_names:
                            raise KeyError("known scheme in deprecated list: %r" % (scheme,))
                dmap[cat] = frozenset(deps)

            #default scheme
            fb = kwds.get("default")
            if fb:
                if handlers:
                    if hasattr(fb, "name"):
                        fb = fb.name
                    if fb not in handler_names:
                        raise KeyError("unknown scheme set as default: %r" % (fb,))
                    fmap[cat] = self.get_handler(fb, required=True)
                else:
                    fmap[cat] = fb

            #min verify time
            value = kwds.get("min_verify_time")
            if value:
                mvmap[cat] = value
Example #32
0
        return self.method.name

    @property
    def class_name(self):
        return get_class_name(self.method)

    @property
    def description(self):
        return get_description(self.method)

    @property
    def require_password(self):
        return requires_password(self.method)

    @property
    def require_user(self):
        return requires_user(self.method)

    @property
    def supported(self):
        return is_supported(self.method)

    def __call__(self, password, **params):
        return make_hash(self.method, password, **params)


# Init the hash mappings:
# attr_name -> MethodWrapper(attr_name, implementation_class)
methods = OrderedDict((name, MethodWrapper(get_crypt_handler(name)))
                      for name in list_crypt_handlers())
Example #33
0
 def __enter__(self):
     from passlib import registry
     registry._unload_handler_name(self.name, locations=False)
     registry.register_crypt_handler(self.dummy)
     assert registry.get_crypt_handler(self.name) is self.dummy
     return self.dummy
Example #34
0
import base64
import hashlib

import passlib.exc as exc
import passlib.utils.handlers as uh

from passlib.registry import get_crypt_handler
from passlib.utils import to_unicode
from passlib.utils.compat import uascii_to_str


passlib_bcrypt = get_crypt_handler("bcrypt")


class bcrypt_sha1(uh.StaticHandler):

    name = "bcrypt_sha1"
    _hash_prefix = u"$bcrypt_sha1$"

    def _calc_checksum(self, secret):
        # Hash the secret with sha1 first
        secret = hashlib.sha1(secret).hexdigest()

        # Hash it with bcrypt
        return passlib_bcrypt.hash(secret)

    def to_string(self):
        assert self.checksum is not None
        return uascii_to_str(self._hash_prefix + base64.b64encode(self.checksum))

    @classmethod
Example #35
0
    def test_crypt(self):
        """test crypt.crypt() wrappers"""
        from passlib.utils import has_crypt, safe_crypt, test_crypt
        from passlib.registry import get_supported_os_crypt_schemes, get_crypt_handler

        # test everything is disabled
        supported = get_supported_os_crypt_schemes()
        if not has_crypt:
            self.assertEqual(supported, ())
            self.assertEqual(safe_crypt("test", "aa"), None)
            self.assertFalse(test_crypt("test", "aaqPiZY5xR5l."))  # des_crypt() hash of "test"
            raise self.skipTest("crypt.crypt() not available")

        # expect there to be something supported, if crypt() is present
        if not supported:
            # NOTE: failures here should be investigated.  usually means one of:
            # 1) at least one of passlib's os_crypt detection routines is giving false negative
            # 2) crypt() ONLY supports some hash alg which passlib doesn't know about
            # 3) crypt() is present but completely disabled (never encountered this yet)
            raise self.fail("crypt() present, but no supported schemes found!")

        # pick cheap alg if possible, with minimum rounds, to speed up this test.
        # NOTE: trusting hasher class works properly (should have been verified using it's own UTs)
        for scheme in ("md5_crypt", "sha256_crypt"):
            if scheme in supported:
                break
        else:
            scheme = supported[-1]
        hasher = get_crypt_handler(scheme)
        if getattr(hasher, "min_rounds", None):
            hasher = hasher.using(rounds=hasher.min_rounds)

        # helpers to generate hashes & config strings to work with
        def get_hash(secret):
            assert isinstance(secret, unicode)
            hash = hasher.hash(secret)
            if isinstance(hash, bytes):  # py2
                hash = hash.decode("utf-8")
            assert isinstance(hash, unicode)
            return hash

        # test ascii password & return type
        s1 = u("test")
        h1 = get_hash(s1)
        result = safe_crypt(s1, h1)
        self.assertIsInstance(result, unicode)
        self.assertEqual(result, h1)
        self.assertEqual(safe_crypt(to_bytes(s1), to_bytes(h1)), h1)

        # make sure crypt doesn't just blindly return h1 for whatever we pass in
        h1x = h1[:-2] + 'xx'
        self.assertEqual(safe_crypt(s1, h1x), h1)

        # test utf-8 / unicode password
        s2 = u('test\u1234')
        h2 = get_hash(s2)
        self.assertEqual(safe_crypt(s2, h2), h2)
        self.assertEqual(safe_crypt(to_bytes(s2), to_bytes(h2)), h2)

        # test rejects null chars in password
        self.assertRaises(ValueError, safe_crypt, '\x00', h1)

        # check test_crypt()
        self.assertTrue(test_crypt("test", h1))
        self.assertFalse(test_crypt("test", h1x))

        # check crypt returning variant error indicators
        # some platforms return None on errors, others empty string,
        # The BSDs in some cases return ":"
        import passlib.utils as mod
        orig = mod._crypt
        try:
            retval = None
            mod._crypt = lambda secret, hash: retval

            for retval in [None, "", ":", ":0", "*0"]:
                self.assertEqual(safe_crypt("test", h1), None)
                self.assertFalse(test_crypt("test", h1))

            retval = 'xxx'
            self.assertEqual(safe_crypt("test", h1), "xxx")
            self.assertFalse(test_crypt("test", h1))

        finally:
            mod._crypt = orig
Example #36
0
def main(*args):
    #---------------------------------------------------------------
    # parse args
    #---------------------------------------------------------------
    args = list(args)

    def print_error(msg):
        print "error: %s\n" % msg

    # parse hasher
    if args:
        name = args.pop(0)
        if name == "-h" or name == "--help":
            print _usage
            return 1
        try:
            hasher = get_crypt_handler(name)
        except KeyError:
            print_error("unknown hash %r" % name)
            return 1
        if 'rounds' not in hasher.setting_kwds:
            print_error("%s does not support variable rounds" % name)
            return 1
    else:
        print_error("hash name not specified")
        print _usage
        return 1

    # parse target time
    if args:
        try:
            target = int(args.pop(0)) * .001
            if target <= 0:
                raise ValueError
        except ValueError:
            print_error("target time must be integer milliseconds > 0")
            return 1
    else:
        target = .350

    #---------------------------------------------------------------
    # setup some helper functions
    #---------------------------------------------------------------
    if hasher.rounds_cost == "log2":
        # time cost varies logarithmically with rounds parameter,
        # so speed = (2**rounds) / elapsed
        def rounds_to_cost(rounds):
            return 2**rounds

        def cost_to_rounds(cost):
            return math.log(cost, 2)
    else:
        # time cost varies linearly with rounds parameter,
        # so speed = rounds / elapsed
        assert hasher.rounds_cost == "linear"
        rounds_to_cost = cost_to_rounds = lambda value: value

    def clamp_rounds(rounds):
        """convert float rounds to int value, clamped to hasher's limits"""
        if hasher.max_rounds and rounds > hasher.max_rounds:
            rounds = hasher.max_rounds
        rounds = int(rounds)
        if getattr(hasher, "_avoid_even_rounds", False):
            rounds |= 1
        return max(hasher.min_rounds, rounds)

    def average(seq):
        if not hasattr(seq, "__length__"):
            seq = tuple(seq)
        return sum(seq) / len(seq)

    def estimate_speed(rounds):
        """estimate speed using specified # of rounds"""
        # time a single verify() call
        secret = "S0m3-S3Kr1T"
        hash = hasher.encrypt(secret, rounds=rounds)

        def helper():
            start = tick()
            hasher.verify(secret, hash)
            return tick() - start

        # try to get average time over a few samples
        # XXX: way too much variability between sampling runs,
        #      would like to improve this bit
        elapsed = min(average(helper() for _ in range(4)) for _ in range(4))
        return rounds_to_cost(rounds) / elapsed

    #---------------------------------------------------------------
    # get rough estimate of speed using fraction of default_rounds
    # (so we don't take crazy long amounts of time on slow systems)
    #---------------------------------------------------------------
    rounds = clamp_rounds(
        cost_to_rounds(.5 * rounds_to_cost(hasher.default_rounds)))
    speed = estimate_speed(rounds)

    #---------------------------------------------------------------
    # re-do estimate using previous result,
    # to get more accurate sample using a larger number of rounds.
    #---------------------------------------------------------------
    for _ in range(2):
        rounds = clamp_rounds(cost_to_rounds(speed * target))
        speed = estimate_speed(rounds)

    #---------------------------------------------------------------
    # using final estimate, calc desired number of rounds for target time
    #---------------------------------------------------------------
    if hasattr(hasher, "backends"):
        name = "%s (using %s backend)" % (name, hasher.get_backend())
    print "hash............: %s" % name
    if speed < 1000:
        speedstr = "%.2f" % speed
    else:
        speedstr = int(speed)
    print "speed...........: %s iterations/second" % speedstr
    print "target time.....: %d ms" % (target * 1000, )
    rounds = cost_to_rounds(speed * target)
    if hasher.rounds_cost == "log2":
        # for log2 rounds parameter, target time will usually fall
        # somewhere between two integer values, which will have large gulf
        # between them. if target is within <tolerance> percent of
        # one of two ends, report it, otherwise list both and let user decide.
        tolerance = .05
        lower = clamp_rounds(rounds)
        upper = clamp_rounds(math.ceil(rounds))
        lower_elapsed = rounds_to_cost(lower) / speed
        upper_elapsed = rounds_to_cost(upper) / speed
        if (target - lower_elapsed) / target < tolerance:
            print "target rounds...: %d" % lower
        elif (upper_elapsed - target) / target < tolerance:
            print "target rounds...: %d" % upper
        else:
            print "target rounds...: %d (%dms -- %dms faster than requested)" % \
                  (lower, lower_elapsed*1000, (target - lower_elapsed) * 1000)
            print "target rounds...: %d (%dms -- %dms slower than requested)" % \
                  (upper, upper_elapsed*1000, (upper_elapsed - target) * 1000)
    else:
        # for linear rounds parameter, just use nearest integer value
        rounds = clamp_rounds(round(rounds))
        print "target rounds...: %d" % (rounds, )
    print
Example #37
0
def passlib_to_hasher_name(passlib_name):
    """convert passlib handler name -> hasher name"""
    handler = get_crypt_handler(passlib_name)
    if hasattr(handler, "django_name"):
        return handler.django_name
    return PASSLIB_HASHER_PREFIX + passlib_name
Example #38
0
def main(*args):
    #---------------------------------------------------------------
    # parse args
    #---------------------------------------------------------------
    args = list(args)
    def print_error(msg):
        print "error: %s\n" % msg

    # parse hasher
    if args:
        name = args.pop(0)
        if name == "-h" or name == "--help":
            print _usage
            return 1
        try:
            hasher = get_crypt_handler(name)
        except KeyError:
            print_error("unknown hash %r" % name)
            return 1
        if 'rounds' not in hasher.setting_kwds:
            print_error("%s does not support variable rounds" % name)
            return 1
    else:
        print_error("hash name not specified")
        print _usage
        return 1

    # parse target time
    if args:
        try:
            target = int(args.pop(0))*.001
            if target <= 0:
                raise ValueError
        except ValueError:
            print_error("target time must be integer milliseconds > 0")
            return 1
    else:
        target = .350

    #---------------------------------------------------------------
    # setup some helper functions
    #---------------------------------------------------------------
    if hasher.rounds_cost == "log2":
        # time cost varies logarithmically with rounds parameter,
        # so speed = (2**rounds) / elapsed
        def rounds_to_cost(rounds):
            return 2 ** rounds
        def cost_to_rounds(cost):
            return math.log(cost, 2)
    else:
        # time cost varies linearly with rounds parameter,
        # so speed = rounds / elapsed
        assert hasher.rounds_cost == "linear"
        rounds_to_cost = cost_to_rounds = lambda value: value

    def clamp_rounds(rounds):
        """convert float rounds to int value, clamped to hasher's limits"""
        if hasher.max_rounds and rounds > hasher.max_rounds:
            rounds = hasher.max_rounds
        rounds = int(rounds)
        if getattr(hasher, "_avoid_even_rounds", False):
            rounds |= 1
        return max(hasher.min_rounds, rounds)

    def average(seq):
        if not hasattr(seq, "__length__"):
            seq = tuple(seq)
        return sum(seq) / len(seq)

    def estimate_speed(rounds):
        """estimate speed using specified # of rounds"""
        # time a single verify() call
        secret = "S0m3-S3Kr1T"
        hash = hasher.encrypt(secret, rounds=rounds)
        def helper():
            start = tick()
            hasher.verify(secret, hash)
            return tick() - start
        # try to get average time over a few samples
        # XXX: way too much variability between sampling runs,
        #      would like to improve this bit
        elapsed = min(average(helper() for _ in range(4)) for _ in range(4))
        return rounds_to_cost(rounds) / elapsed

    #---------------------------------------------------------------
    # get rough estimate of speed using fraction of default_rounds
    # (so we don't take crazy long amounts of time on slow systems)
    #---------------------------------------------------------------
    rounds = clamp_rounds(cost_to_rounds(.5 * rounds_to_cost(hasher.default_rounds)))
    speed = estimate_speed(rounds)

    #---------------------------------------------------------------
    # re-do estimate using previous result,
    # to get more accurate sample using a larger number of rounds.
    #---------------------------------------------------------------
    for _ in range(2):
        rounds = clamp_rounds(cost_to_rounds(speed * target))
        speed = estimate_speed(rounds)

    #---------------------------------------------------------------
    # using final estimate, calc desired number of rounds for target time
    #---------------------------------------------------------------
    if hasattr(hasher, "backends"):
        name = "%s (using %s backend)" % (name, hasher.get_backend())
    print "hash............: %s" % name
    if speed < 1000:
        speedstr = "%.2f" % speed
    else:
        speedstr = int(speed)
    print "speed...........: %s iterations/second" % speedstr
    print "target time.....: %d ms" % (target*1000,)
    rounds = cost_to_rounds(speed * target)
    if hasher.rounds_cost == "log2":
        # for log2 rounds parameter, target time will usually fall
        # somewhere between two integer values, which will have large gulf
        # between them. if target is within <tolerance> percent of
        # one of two ends, report it, otherwise list both and let user decide.
        tolerance = .05
        lower = clamp_rounds(rounds)
        upper = clamp_rounds(math.ceil(rounds))
        lower_elapsed = rounds_to_cost(lower) / speed
        upper_elapsed = rounds_to_cost(upper) / speed
        if (target-lower_elapsed)/target < tolerance:
            print "target rounds...: %d" % lower
        elif (upper_elapsed-target)/target < tolerance:
            print "target rounds...: %d" % upper
        else:
            print "target rounds...: %d (%dms -- %dms faster than requested)" % \
                  (lower, lower_elapsed*1000, (target - lower_elapsed) * 1000)
            print "target rounds...: %d (%dms -- %dms slower than requested)" % \
                  (upper, upper_elapsed*1000, (upper_elapsed - target) * 1000)
    else:
        # for linear rounds parameter, just use nearest integer value
        rounds = clamp_rounds(round(rounds))
        print "target rounds...: %d" % (rounds,)
    print
 def __enter__(self):
     from passlib import registry
     registry._unload_handler_name(self.name, locations=False)
     registry.register_crypt_handler(self.dummy)
     assert registry.get_crypt_handler(self.name) is self.dummy
     return self.dummy
Example #40
0
    def django_to_passlib(self, django_name, cached=True):
        """
        Convert Django hasher / name to Passlib hasher / name.
        If present, CryptContext will be checked instead of main registry.

        :param django_name:
            Django hasher class or algorithm name.
            "default" allowed if context provided.

        :raises ValueError:
            if can't resolve hasher.

        :returns:
            passlib hasher or name
        """
        # check for django hasher
        if hasattr(django_name, "algorithm"):

            # check for passlib adapter
            if isinstance(django_name, _PasslibHasherWrapper):
                return django_name.passlib_handler

            # resolve django hasher -> name
            django_name = django_name.algorithm

        # check cache
        if cached:
            cache = self._passlib_hasher_cache
            try:
                return cache[django_name]
            except KeyError:
                pass
            result = cache[django_name] = self.django_to_passlib(django_name,
                                                                 cached=False)
            return result

        # check if it's an obviously-wrapped name
        if django_name.startswith(PASSLIB_WRAPPER_PREFIX):
            passlib_name = django_name[len(PASSLIB_WRAPPER_PREFIX):]
            return self._get_passlib_hasher(passlib_name)

        # resolve default
        if django_name == "default":
            context = self.context
            if context is None:
                raise TypeError("can't determine default scheme w/ context")
            return context.handler()

        # special case: Django uses a separate hasher for "sha1$$digest"
        # hashes (unsalted_sha1) and "sha1$salt$digest" (sha1);
        # but passlib uses "django_salted_sha1" for both of these.
        if django_name == "unsalted_sha1":
            django_name = "sha1"

        # resolve name
        # XXX: bother caching these lists / mapping?
        #      not needed in long-term due to cache above.
        context = self.context
        if context is None:
            # check registry
            # TODO: should make iteration via registry easier
            candidates = (registry.get_crypt_handler(passlib_name)
                          for passlib_name in registry.list_crypt_handlers()
                          if passlib_name.startswith(DJANGO_COMPAT_PREFIX)
                          or passlib_name in _other_django_hashes)
        else:
            # check context
            candidates = context.schemes(resolve=True)
        for handler in candidates:
            if getattr(handler, "django_name", None) == django_name:
                return handler

        # give up
        # NOTE: this should only happen for custom django hashers that we don't
        #       know the equivalents for. _HasherHandler (below) is work in
        #       progress that would allow us to at least return a wrapper.
        raise ValueError("can't translate django name to passlib name: %r" %
                         (django_name, ))