Ejemplo n.º 1
0
    def test_crypt(self):
        "test crypt.crypt() wrappers"
        from passlib.utils import has_crypt, safe_crypt, test_crypt

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

        # XXX: this assumes *every* crypt() implementation supports des_crypt.
        #      if this fails for some platform, this test will need modifying.

        # test return type
        self.assertIsInstance(safe_crypt(u("test"), u("aa")), unicode)

        # test ascii password
        h1 = u('aaqPiZY5xR5l.')
        self.assertEqual(safe_crypt(u('test'), u('aa')), h1)
        self.assertEqual(safe_crypt(b('test'), b('aa')), h1)

        # test utf-8 / unicode password
        h2 = u('aahWwbrUsKZk.')
        self.assertEqual(safe_crypt(u('test\u1234'), 'aa'), h2)
        self.assertEqual(safe_crypt(b('test\xe1\x88\xb4'), 'aa'), h2)

        # test latin-1 password
        hash = safe_crypt(b('test\xff'), 'aa')
        if PY3: # py3 supports utf-8 bytes only.
            self.assertEqual(hash, None)
        else: # but py2 is fine.
            self.assertEqual(hash, u('aaOx.5nbTU/.M'))

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

        # check test_crypt()
        h1x = h1[:-1] + 'x'
        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:
            fake = None
            mod._crypt = lambda secret, hash: fake
            for fake in [None, "", ":", ":0", "*0"]:
                self.assertEqual(safe_crypt("test", "aa"), None)
                self.assertFalse(test_crypt("test", h1))
            fake = 'xxx'
            self.assertEqual(safe_crypt("test", "aa"), "xxx")
        finally:
            mod._crypt = orig
Ejemplo n.º 2
0
    def test_crypt(self):
        "test crypt.crypt() wrappers"
        from passlib.utils import has_crypt, safe_crypt, test_crypt

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

        # XXX: this assumes *every* crypt() implementation supports des_crypt.
        #      if this fails for some platform, this test will need modifying.

        # test return type
        self.assertIsInstance(safe_crypt(u("test"), u("aa")), unicode)

        # test ascii password
        h1 = u('aaqPiZY5xR5l.')
        self.assertEqual(safe_crypt(u('test'), u('aa')), h1)
        self.assertEqual(safe_crypt(b('test'), b('aa')), h1)

        # test utf-8 / unicode password
        h2 = u('aahWwbrUsKZk.')
        self.assertEqual(safe_crypt(u('test\u1234'), 'aa'), h2)
        self.assertEqual(safe_crypt(b('test\xe1\x88\xb4'), 'aa'), h2)

        # test latin-1 password
        hash = safe_crypt(b('test\xff'), 'aa')
        if PY3:  # py3 supports utf-8 bytes only.
            self.assertEqual(hash, None)
        else:  # but py2 is fine.
            self.assertEqual(hash, u('aaOx.5nbTU/.M'))

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

        # check test_crypt()
        h1x = h1[:-1] + 'x'
        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:
            fake = None
            mod._crypt = lambda secret, hash: fake
            for fake in [None, "", ":", ":0", "*0"]:
                self.assertEqual(safe_crypt("test", "aa"), None)
                self.assertFalse(test_crypt("test", h1))
            fake = 'xxx'
            self.assertEqual(safe_crypt("test", "aa"), "xxx")
        finally:
            mod._crypt = orig
Ejemplo n.º 3
0
 def crypt_supports_variant(self, hash):
     """check if OS crypt is expected to support given ident"""
     from passlib.handlers.bcrypt import bcrypt, IDENT_2X, IDENT_2Y
     from passlib.utils import safe_crypt
     ident = bcrypt.from_string(hash)
     return (safe_crypt("test", ident + "04$5BJqKfqMQvV7nS.yUguNcu")
             or "").startswith(ident)
Ejemplo n.º 4
0
 def _calc_checksum_os_crypt(self, secret):
     config = self.ident + self.salt
     hash = safe_crypt(secret, config)
     if hash:
         assert hash.startswith(config) and len(hash) == len(config) + 23
         return hash[-22:]
     return self._try_alternate_backends(secret)
Ejemplo n.º 5
0
 def _calc_checksum_os_crypt(self, secret):
     config = self.ident + self.salt
     hash = safe_crypt(secret, config)
     if hash:
         assert hash.startswith(config) and len(hash) == len(config) + 23
         return hash[-22:]
     return self._try_alternate_backends(secret)
Ejemplo n.º 6
0
 def _calc_checksum_os_crypt(self, secret):
     config = self.to_string(config=True)
     hash = safe_crypt(secret, config)
     if hash:
         assert hash.startswith(config) and len(hash) == len(config) + 29
         return hash[-28:]
     return self._try_alternate_backends(secret)
Ejemplo n.º 7
0
 def _calc_checksum_os_crypt(self, secret):
     config = self.to_string()
     hash = safe_crypt(secret, config)
     if hash:
         assert hash.startswith(config[:9]) and len(hash) == 20
         return hash[-11:]
     return self._try_alternate_backends(secret)
Ejemplo n.º 8
0
 def _calc_checksum_os_crypt(self, secret):
     # NOTE: we let safe_crypt() encode unicode secret -> utf8;
     #       no official policy since des-crypt predates unicode
     hash = safe_crypt(secret, self.salt)
     if hash:
         assert hash.startswith(self.salt) and len(hash) == 13
         return hash[2:]
     return self._try_alternate_backends(secret)
Ejemplo n.º 9
0
 def _calc_checksum_os_crypt(self, secret):
     # NOTE: we let safe_crypt() encode unicode secret -> utf8;
     #       no official policy since des-crypt predates unicode
     hash = safe_crypt(secret, self.salt)
     if hash:
         assert hash.startswith(self.salt) and len(hash) == 13
         return hash[2:]
     return self._try_alternate_backends(secret)
Ejemplo n.º 10
0
 def _calc_checksum_os_crypt(self, secret):
     config = self.to_string(config=True)
     hash = safe_crypt(secret, config)
     if hash:
         assert hash.startswith(config) and len(hash) == len(config) + 29
         return hash[-28:]
     else:
         return self._calc_checksum_builtin(secret)
Ejemplo n.º 11
0
 def _calc_checksum_os_crypt(self, secret):
     config = self.to_string(config=True)
     hash = safe_crypt(secret, config)
     if hash:
         assert hash.startswith(config) and len(hash) == len(config) + 29
         return hash[-28:]
     else:
         return self._calc_checksum_builtin(secret)
Ejemplo n.º 12
0
 def _calc_checksum_os_crypt(self, secret):
     config = self.ident + self.salt
     hash = safe_crypt(secret, config)
     if hash:
         assert hash.startswith(config) and len(hash) == len(config) + 23
         return hash[-22:]
     else:
         return self._calc_checksum_builtin(secret)
Ejemplo n.º 13
0
 def _calc_checksum_os_crypt(self, secret):
     config = self.to_string()
     hash = safe_crypt(secret, config)
     if hash:
         assert hash.startswith(config[:9]) and len(hash) == 20
         return hash[-11:]
     else:
         return self._calc_checksum_builtin(secret)
Ejemplo n.º 14
0
 def _calc_checksum_os_crypt(self, secret):
     config = self.to_string()
     hash = safe_crypt(secret, config)
     if hash:
         assert hash.startswith(config[:9]) and len(hash) == 20
         return hash[-11:]
     else:
         return self._calc_checksum_builtin(secret)
Ejemplo n.º 15
0
 def _calc_checksum_os_crypt(self, secret):
     config = self.ident + self.salt
     hash = safe_crypt(secret, config)
     if hash:
         assert hash.startswith(config) and len(hash) == len(config) + 23
         return hash[-22:]
     else:
         return self._calc_checksum_builtin(secret)
Ejemplo n.º 16
0
 def _calc_checksum_os_crypt(self, secret):
     # NOTE: safe_crypt encodes unicode secret -> utf8
     # no official policy since des-crypt predates unicode
     hash = safe_crypt(secret, self.salt)
     if hash:
         assert hash.startswith(self.salt) and len(hash) == 13
         return hash[2:]
     else:
         return self._calc_checksum_builtin(secret)
Ejemplo n.º 17
0
 def _calc_checksum_os_crypt(self, secret):
     hash = safe_crypt(secret, self.to_string())
     if hash:
         # NOTE: avoiding full parsing routine via from_string().checksum,
         # and just extracting the bit we need.
         cs = self.checksum_size
         assert hash.startswith(self.ident) and hash[-cs - 1] == _UDOLLAR
         return hash[-cs:]
     return self._try_alternate_backends(secret)
Ejemplo n.º 18
0
 def _calc_checksum_os_crypt(self, secret):
     # NOTE: safe_crypt encodes unicode secret -> utf8
     # no official policy since des-crypt predates unicode
     hash = safe_crypt(secret, self.salt)
     if hash:
         assert hash.startswith(self.salt) and len(hash) == 13
         return hash[2:]
     else:
         return self._calc_checksum_builtin(secret)
Ejemplo n.º 19
0
 def _calc_checksum_os_crypt(self, secret):
     hash = safe_crypt(secret, self.to_string())
     if hash:
         # NOTE: avoiding full parsing routine via from_string().checksum,
         # and just extracting the bit we need.
         cs = self.checksum_size
         assert hash.startswith(self.ident) and hash[-cs-1] == _UDOLLAR
         return hash[-cs:]
     return self._try_alternate_backends(secret)
Ejemplo n.º 20
0
 def _calc_checksum_os_crypt(self, secret):
     config = self.ident + self.salt
     hash = safe_crypt(secret, config)
     if hash:
         assert hash.startswith(config) and len(hash) == len(config) + 23
         return hash[-22:]
     else:
         # py3's crypt.crypt() can't handle non-utf8 bytes.
         # fallback to builtin alg, which is always available.
         return self._calc_checksum_builtin(secret)
Ejemplo n.º 21
0
 def _calc_checksum_os_crypt(self, secret):
     config = self.to_string()
     hash = safe_crypt(secret, config)
     if hash:
         assert hash.startswith(config[:9]) and len(hash) == 20
         return hash[-11:]
     else:
         # py3's crypt.crypt() can't handle non-utf8 bytes.
         # fallback to builtin alg, which is always available.
         return self._calc_checksum_builtin(secret)
Ejemplo n.º 22
0
 def _calc_checksum_os_crypt(self, secret):
     config = self.to_string()
     hash = safe_crypt(secret, config)
     if hash is None:
         # py3's crypt.crypt() can't handle non-utf8 bytes.
         # fallback to builtin alg, which is always available.
         return self._calc_checksum_builtin(secret)
     if not hash.startswith(config[:9]) or len(hash) != 20:
         raise uh.exc.CryptBackendError(self, config, hash)
     return hash[-11:]
Ejemplo n.º 23
0
 def _calc_checksum_os_crypt(self, secret):
     config = self.ident + self.salt
     hash = safe_crypt(secret, config)
     if hash:
         assert hash.startswith(config) and len(hash) == len(config) + 23
         return hash[-22:]
     else:
         # py3's crypt.crypt() can't handle non-utf8 bytes.
         # fallback to builtin alg, which is always available.
         return self._calc_checksum_builtin(secret)
Ejemplo n.º 24
0
 def _calc_checksum_os_crypt(self, secret):
     config = self._get_config()
     hash = safe_crypt(secret, config)
     if hash:
         assert hash.startswith(config) and len(hash) == len(config) + 31
         return hash[-31:]
     # get here mainly if 1) under py3, and 2) secret is latin-1 or other non-unicode bytes.
     # in this case, another backend like pybcrypt should be able to get around
     # py3's limitations.
     return self._try_alternate_backends(secret)
Ejemplo n.º 25
0
 def _calc_checksum_os_crypt(self, secret):
     config = self._get_config()
     hash = safe_crypt(secret, config)
     if hash:
         assert hash.startswith(config) and len(hash) == len(config)+31
         return hash[-31:]
     # get here mainly if 1) under py3, and 2) secret is latin-1 or other non-unicode bytes.
     # in this case, another backend like pybcrypt should be able to get around
     # py3's limitations.
     return self._try_alternate_backends(secret)
Ejemplo n.º 26
0
 def _calc_checksum_os_crypt(self, secret):
     # NOTE: we let safe_crypt() encode unicode secret -> utf8;
     #       no official policy since des-crypt predates unicode
     hash = safe_crypt(secret, self.salt)
     if hash:
         assert hash.startswith(self.salt) and len(hash) == 13
         return hash[2:]
     else:
         # py3's crypt.crypt() can't handle non-utf8 bytes.
         # fallback to builtin alg, which is always available.
         return self._calc_checksum_builtin(secret)
Ejemplo n.º 27
0
 def _calc_checksum_os_crypt(self, secret):
     # NOTE: we let safe_crypt() encode unicode secret -> utf8;
     #       no official policy since des-crypt predates unicode
     hash = safe_crypt(secret, self.salt)
     if hash is None:
         # py3's crypt.crypt() can't handle non-utf8 bytes.
         # fallback to builtin alg, which is always available.
         return self._calc_checksum_builtin(secret)
     if not hash.startswith(self.salt) or len(hash) != 13:
         raise uh.exc.CryptBackendError(self, self.salt, hash)
     return hash[2:]
Ejemplo n.º 28
0
 def _calc_checksum_os_crypt(self, secret):
     hash = safe_crypt(secret, self.to_string())
     if hash:
         # NOTE: avoiding full parsing routine via from_string().checksum,
         # and just extracting the bit we need.
         cs = self.checksum_size
         assert hash.startswith(self.ident) and hash[-cs-1] == _UDOLLAR
         return hash[-cs:]
     else:
         # py3's crypt.crypt() can't handle non-utf8 bytes.
         # fallback to builtin alg, which is always available.
         return self._calc_checksum_builtin(secret)
Ejemplo n.º 29
0
 def _calc_checksum_os_crypt(self, secret):
     hash = safe_crypt(secret, self.to_string())
     if hash:
         # NOTE: avoiding full parsing routine via from_string().checksum,
         # and just extracting the bit we need.
         cs = self.checksum_size
         assert hash.startswith(self.ident) and hash[-cs - 1] == _UDOLLAR
         return hash[-cs:]
     else:
         # py3's crypt.crypt() can't handle non-utf8 bytes.
         # fallback to builtin alg, which is always available.
         return self._calc_checksum_builtin(secret)
Ejemplo n.º 30
0
 def _calc_checksum_os_crypt(self, secret):
     config = self.to_string()
     hash = safe_crypt(secret, config)
     if hash is None:
         # py3's crypt.crypt() can't handle non-utf8 bytes.
         # fallback to builtin alg, which is always available.
         return self._calc_checksum_builtin(secret)
     # NOTE: avoiding full parsing routine via from_string().checksum,
     # and just extracting the bit we need.
     cs = self.checksum_size
     if not hash.startswith(self.ident) or hash[-cs - 1] != _UDOLLAR:
         raise uh.exc.CryptBackendError(self, config, hash)
     return hash[-cs:]
Ejemplo n.º 31
0
 def _calc_checksum_os_crypt(self, secret):
     config = self._get_config()
     hash = safe_crypt(secret, config)
     if hash:
         assert hash.startswith(config) and len(hash) == len(config) + 31
         return hash[-31:]
     else:
         # NOTE: it's unlikely any other backend will be available,
         # but checking before we bail, just in case.
         for name in self.backends:
             if name != "os_crypt" and self.has_backend(name):
                 func = getattr(self, "_calc_checksum_" + name)
                 return func(secret)
         raise uh.exc.MissingBackendError(
             "password can't be handled by os_crypt, "
             "recommend installing py-bcrypt.", )
Ejemplo n.º 32
0
 def _calc_checksum_os_crypt(self, secret):
     config = self._get_config()
     hash = safe_crypt(secret, config)
     if hash:
         assert hash.startswith(config) and len(hash) == len(config) + 31
         return hash[-31:]
     else:
         # NOTE: it's unlikely any other backend will be available,
         # but checking before we bail, just in case.
         for name in self.backends:
             if name != "os_crypt" and self.has_backend(name):
                 func = getattr(self, "_calc_checksum_" + name)
                 return func(secret)
         raise uh.exc.MissingBackendError(
             "password can't be handled by os_crypt, " "recommend installing py-bcrypt."
         )
Ejemplo n.º 33
0
 def _calc_checksum_os_crypt(self, secret, config):
     hash = safe_crypt(secret, config)
     if hash:
         assert hash.startswith(config) and len(hash) == len(config)+31
         return hash[-31:]
     else:
         # NOTE: Have to raise this error because python3's crypt.crypt() only accepts unicode.
         #       This means it can't handle any passwords that aren't either unicode
         #       or utf-8 encoded bytes.  However, hashing a password with an alternate
         #       encoding should be a pretty rare edge case; if user needs it, they can just
         #       install bcrypt backend.
         # XXX: is this the right error type to raise?
         #      maybe have safe_crypt() not swallow UnicodeDecodeError, and have handlers
         #      like sha256_crypt trap it if they have alternate method of handling them?
         raise uh.exc.MissingBackendError(
             "non-utf8 encoded passwords can't be handled by crypt.crypt() under python3, "
             "recommend running `pip install bcrypt`.",
             )
Ejemplo n.º 34
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
Ejemplo n.º 35
0
 def crypt_supports_variant(self, hash):
     """check if OS crypt is expected to support given ident"""
     from passlib.handlers.bcrypt import bcrypt, IDENT_2X, IDENT_2Y
     from passlib.utils import safe_crypt
     ident = bcrypt.from_string(hash)
     return (safe_crypt("test", ident + "04$5BJqKfqMQvV7nS.yUguNcu") or "").startswith(ident)