Beispiel #1
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 lib.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_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 lib.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_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())
Beispiel #4
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)
    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)
Beispiel #6
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)
Beispiel #7
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())
Beispiel #8
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 lib.passlib.tests import _test_bad_register as tbr
        self.assertIs(h, tbr.alt_dummy_bad)
Beispiel #9
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)
    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 lib.passlib.tests import _test_bad_register as tbr
        self.assertIs(h, tbr.alt_dummy_bad)
Beispiel #11
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)
Beispiel #12
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.

    .. 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 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
Beispiel #13
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,))
Beispiel #14
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
Beispiel #15
0
 def __enter__(self):
     from lib.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