def test_10_wrapped_attributes(self): d1 = uh.PrefixWrapper("d1", "ldap_md5", "{XXX}", "{MD5}") self.assertEqual(d1.name, "d1") self.assertIs(d1.setting_kwds, ldap_md5.setting_kwds) self.assertFalse('max_rounds' in dir(d1)) d2 = uh.PrefixWrapper("d2", "sha256_crypt", "{XXX}") self.assertIs(d2.setting_kwds, sha256_crypt.setting_kwds) self.assertTrue('max_rounds' in dir(d2))
def test_12_ident(self): # test ident is proxied h = uh.PrefixWrapper("h2", "ldap_md5", "{XXX}") self.assertEqual(h.ident, u("{XXX}{MD5}")) self.assertIs(h.ident_values, None) # test lack of ident means no proxy h = uh.PrefixWrapper("h2", "des_crypt", "{XXX}") self.assertIs(h.ident, None) self.assertIs(h.ident_values, None) # test orig_prefix disabled ident proxy h = uh.PrefixWrapper("h1", "ldap_md5", "{XXX}", "{MD5}") self.assertIs(h.ident, None) self.assertIs(h.ident_values, None) # test custom ident overrides default h = uh.PrefixWrapper("h3", "ldap_md5", "{XXX}", ident="{X") self.assertEqual(h.ident, u("{X")) self.assertIs(h.ident_values, None) # test custom ident must match h = uh.PrefixWrapper("h3", "ldap_md5", "{XXX}", ident="{XXX}A") self.assertRaises(ValueError, uh.PrefixWrapper, "h3", "ldap_md5", "{XXX}", ident="{XY") self.assertRaises(ValueError, uh.PrefixWrapper, "h3", "ldap_md5", "{XXX}", ident="{XXXX") # test ident_values is proxied h = uh.PrefixWrapper("h4", "phpass", "{XXX}") self.assertIs(h.ident, None) self.assertEqual(h.ident_values, (u("{XXX}$P$"), u("{XXX}$H$"))) # test ident=True means use prefix even if hash has no ident. h = uh.PrefixWrapper("h5", "des_crypt", "{XXX}", ident=True) self.assertEqual(h.ident, u("{XXX}")) self.assertIs(h.ident_values, None) # ... but requires prefix self.assertRaises(ValueError, uh.PrefixWrapper, "h6", "des_crypt", ident=True) # orig_prefix + HasManyIdent - warning with self.assertWarningList("orig_prefix.*may not work correctly"): h = uh.PrefixWrapper("h7", "phpass", orig_prefix="$", prefix="?") self.assertEqual(h.ident_values, None) # TODO: should output (u("?P$"), u("?H$"))) self.assertEqual(h.ident, None)
def _init_ldap_crypt_handlers(): # NOTE: I don't like to implicitly modify globals() like this, # but don't want to write out all these handlers out either :) g = globals() for wname in unix_crypt_schemes: name = 'ldap_' + wname g[name] = uh.PrefixWrapper(name, wname, prefix=u("{CRYPT}"), lazy=True) del g
def test_13_repr(self): """test repr()""" h = uh.PrefixWrapper("h2", "md5_crypt", "{XXX}", orig_prefix="$1$") self.assertRegex(repr(h), r"""(?x)^PrefixWrapper\( ['"]h2['"],\s+ ['"]md5_crypt['"],\s+ prefix=u?["']{XXX}['"],\s+ orig_prefix=u?["']\$1\$['"] \)$""")
def test_01_active_loading(self): """test PrefixWrapper active loading of handler""" d1 = uh.PrefixWrapper("d1", "ldap_md5", "{XXX}", "{MD5}") # check base state self.assertEqual(d1._wrapped_name, "ldap_md5") self.assertIs(d1._wrapped_handler, ldap_md5) self.assertIs(d1.wrapped, ldap_md5) # replace w/ wrong handler, make sure doesn't reload w/ dummy with dummy_handler_in_registry("ldap_md5") as dummy: self.assertIs(d1.wrapped, ldap_md5)
def test_02_explicit(self): """test PrefixWrapper with explicitly specified handler""" d1 = uh.PrefixWrapper("d1", ldap_md5, "{XXX}", "{MD5}") # check base state self.assertEqual(d1._wrapped_name, None) self.assertIs(d1._wrapped_handler, ldap_md5) self.assertIs(d1.wrapped, ldap_md5) # replace w/ wrong handler, make sure doesn't reload w/ dummy with dummy_handler_in_registry("ldap_md5") as dummy: self.assertIs(d1.wrapped, ldap_md5)
def test_11_wrapped_methods(self): d1 = uh.PrefixWrapper("d1", "ldap_md5", "{XXX}", "{MD5}") dph = "{XXX}X03MO1qnZdYdgyfeuILPmQ==" lph = "{MD5}X03MO1qnZdYdgyfeuILPmQ==" # genconfig self.assertIs(d1.genconfig(), None) # genhash self.assertEqual(d1.genhash("password", None), dph) self.assertEqual(d1.genhash("password", dph), dph) self.assertRaises(ValueError, d1.genhash, "password", lph) # encrypt self.assertEqual(d1.encrypt("password"), dph) # identify self.assertTrue(d1.identify(dph)) self.assertFalse(d1.identify(lph)) # verify self.assertRaises(ValueError, d1.verify, "password", lph) self.assertTrue(d1.verify("password", dph))
def raw_nthash(cls, secret, hex=False): warn("nthash.raw_nthash() is deprecated, and will be removed " "in Passlib 1.8, please use nthash.raw() instead", DeprecationWarning) ret = nthash.raw(secret) return hexlify(ret).decode("ascii") if hex else ret #=================================================================== # eoc #=================================================================== bsd_nthash = uh.PrefixWrapper("bsd_nthash", nthash, prefix="$3$$", ident="$3$$", doc="""The class support FreeBSD's representation of NTHASH (which is compatible with the :ref:`modular-crypt-format`), and follows the :ref:`password-hash-api`. It has no salt and a single fixed round. The :meth:`~passlib.ifc.PasswordHash.encrypt` and :meth:`~passlib.ifc.PasswordHash.genconfig` methods accept no optional keywords. """) ##class ntlm_pair(object): ## "combined lmhash & nthash" ## name = "ntlm_pair" ## setting_kwds = () ## _hash_regex = re.compile(u"^(?P<lm>[0-9a-f]{32}):(?P<nt>[0-9][a-f]{32})$", ## re.I) ## ## @classmethod ## def identify(cls, hash): ## hash = to_unicode(hash, "latin-1", "hash")
log = logging.getLogger(__name__) # site # pkg import lib.passlib.utils.handlers as uh from lib.passlib.utils.compat import u # local __all__ = [ "roundup_plaintext", "ldap_hex_md5", "ldap_hex_sha1", ] #============================================================================= # #============================================================================= roundup_plaintext = uh.PrefixWrapper("roundup_plaintext", "plaintext", prefix=u("{plaintext}"), lazy=True) # NOTE: these are here because they're currently only known to be used by roundup ldap_hex_md5 = uh.PrefixWrapper("ldap_hex_md5", "hex_md5", u("{MD5}"), lazy=True) ldap_hex_sha1 = uh.PrefixWrapper("ldap_hex_sha1", "hex_sha1", u("{SHA}"), lazy=True) #============================================================================= # eof #=============================================================================
and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` will be issued instead. Correctable errors include ``rounds`` that are too small or too large, and ``salt`` strings that are too long. .. versionadded:: 1.6 """ % dict(digest=hash_name.upper(), dsc=base.default_salt_size, dr=rounds) )) #------------------------------------------------------------------------ # derived handlers #------------------------------------------------------------------------ pbkdf2_sha1 = create_pbkdf2_hash("sha1", 20, 131000, ident=u("$pbkdf2$")) pbkdf2_sha256 = create_pbkdf2_hash("sha256", 32, 29000) pbkdf2_sha512 = create_pbkdf2_hash("sha512", 64, 25000) ldap_pbkdf2_sha1 = uh.PrefixWrapper("ldap_pbkdf2_sha1", pbkdf2_sha1, "{PBKDF2}", "$pbkdf2$", ident=True) ldap_pbkdf2_sha256 = uh.PrefixWrapper("ldap_pbkdf2_sha256", pbkdf2_sha256, "{PBKDF2-SHA256}", "$pbkdf2-sha256$", ident=True) ldap_pbkdf2_sha512 = uh.PrefixWrapper("ldap_pbkdf2_sha512", pbkdf2_sha512, "{PBKDF2-SHA512}", "$pbkdf2-sha512$", ident=True) #============================================================================= # cryptacular's pbkdf2 hash #============================================================================= # bytes used by cta hash for base64 values 63 & 64 CTA_ALTCHARS = b"-_" class cta_pbkdf2_sha1(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler): """This class implements Cryptacular's PBKDF2-based crypt algorithm, and follows the :ref:`password-hash-api`. It supports a variable-length salt, and a variable number of rounds.
def test_14_bad_hash(self): """test orig_prefix sanity check""" # shoudl throw InvalidHashError if wrapped hash doesn't begin # with orig_prefix. h = uh.PrefixWrapper("h2", "md5_crypt", orig_prefix="$6$") self.assertRaises(ValueError, h.encrypt, 'test')
#============================================================================= # BCrypt #============================================================================= django_bcrypt = uh.PrefixWrapper( "django_bcrypt", bcrypt, prefix=u('bcrypt$'), ident=u("bcrypt$"), # NOTE: this docstring is duplicated in the docs, since sphinx # seems to be having trouble reading it via autodata:: doc= """This class implements Django 1.4's BCrypt wrapper, and follows the :ref:`password-hash-api`. This is identical to :class:`!bcrypt` itself, but with the Django-specific prefix ``"bcrypt$"`` prepended. See :doc:`/lib/passlib.hash.bcrypt` for more details, the usage and behavior is identical. This should be compatible with the hashes generated by Django 1.4's :class:`!BCryptPasswordHasher` class. .. versionadded:: 1.6 """) django_bcrypt.django_name = "bcrypt" django_bcrypt._using_clone_attrs += ("django_name", ) #============================================================================= # BCRYPT + SHA256