diff options
| author | Eli Collins <elic@assurancetechnologies.com> | 2012-03-10 17:48:58 -0500 |
|---|---|---|
| committer | Eli Collins <elic@assurancetechnologies.com> | 2012-03-10 17:48:58 -0500 |
| commit | d3c7d16915f7ef3919245f211b8dab8ae35ade70 (patch) | |
| tree | 47e128e356e5d5363c7efdde5de944a52fd6191a /passlib | |
| parent | 50965db6ee2b6ff2c9227ea6c740e9513963c4f6 (diff) | |
| download | passlib-d3c7d16915f7ef3919245f211b8dab8ae35ade70.tar.gz | |
did rewrite of unix_fallback as unix_disabled; unix_fallback is now deprecated
Diffstat (limited to 'passlib')
| -rw-r--r-- | passlib/handlers/misc.py | 77 | ||||
| -rw-r--r-- | passlib/hosts.py | 15 | ||||
| -rw-r--r-- | passlib/registry.py | 3 | ||||
| -rw-r--r-- | passlib/tests/test_handlers.py | 22 | ||||
| -rw-r--r-- | passlib/tests/test_hosts.py | 16 |
5 files changed, 118 insertions, 15 deletions
diff --git a/passlib/handlers/misc.py b/passlib/handlers/misc.py index 4244e14..38b8c25 100644 --- a/passlib/handlers/misc.py +++ b/passlib/handlers/misc.py @@ -4,6 +4,7 @@ #imports #========================================================= #core +import sys import logging; log = logging.getLogger(__name__) from warnings import warn #site @@ -14,6 +15,7 @@ import passlib.utils.handlers as uh #pkg #local __all__ = [ + "unix_disabled", "unix_fallback", "plaintext", ] @@ -24,6 +26,12 @@ __all__ = [ class unix_fallback(uh.StaticHandler): """This class provides the fallback behavior for unix shadow files, and follows the :ref:`password-hash-api`. + .. note:: + + This class has been deprecated as of Passlib 1.6, + and will be removed in Passlib 1.8. + Use 'unix_disabled' instead. + This class does not implement a hash, but instead provides fallback behavior as found in /etc/shadow on most unix variants. If used, should be the last scheme in the context. @@ -43,6 +51,10 @@ class unix_fallback(uh.StaticHandler): return hash is not None def __init__(self, enable_wildcard=False, **kwds): + warn("'unix_fallback' is deprecated, " + "and will be removed in Passlib 1.8; " + "please use 'unix_disabled' instead.", + DeprecationWarning) super(unix_fallback, self).__init__(**kwds) self.enable_wildcard = enable_wildcard @@ -67,6 +79,71 @@ class unix_fallback(uh.StaticHandler): else: return enable_wildcard +class unix_disabled(object): + """This class provides disabled password behavior for unix shadow files, + and follows the :ref:`password-hash-api`. This class does not implement a + hash, but instead provides disabled account behavior as found in + ``/etc/shadow`` on most unix variants. + + * this class will positively identify all hash strings. + because of this it should be checked last. + * "encrypting" a password will simply return the disabled account marker. + * it will reject all passwords, no matter the hash. + + The :meth:`encrypt` method supports one optional keyword: + + :param marker: + Optional marker string which overrides the platform default + used to indicate a disabled account. + + If not specified, this will default to ``*`` on BSD systems, + and use the Linux default ``!`` for all other platforms. + (:attr:`!unix_disabled.marker` will contain the default value) + """ + name = "unix_disabled" + setting_kwds = ("marker",) + context_kwds = () + + if 'bsd' in sys.platform: + marker = u("*") + else: + # use the linux default for other systems + # (glibc also supports adding old hash after the marker + # so it can be restored later). + marker = u("!") + + @classmethod + def identify(cls, hash): + return hash is not None + + @classmethod + def encrypt(cls, secret, marker=None): + return cls.genhash(secret, None, marker) + + @classmethod + def verify(cls, secret, hash): + if secret is None: + raise TypeError("no secret provided") + if hash is None: + raise TypeError("no hash provided") + return False + + @classmethod + def genconfig(cls): + return None + + @classmethod + def genhash(cls, secret, config, marker=None): + if secret is None: + raise TypeError("secret must be string") + if config is not None: + # NOTE: config/hash will generally be "!" or "*", + # but we want to preserve it in case it has some other content, + # such as ``"!" + original hash``, which glibc uses. + return to_native_str(config, errname="config") + else: + return to_native_str(marker or cls.marker, errname="marker") + class plaintext(object): """This class stores passwords in plaintext, and follows the :ref:`password-hash-api`. diff --git a/passlib/hosts.py b/passlib/hosts.py index 6fc5570..5d3abc6 100644 --- a/passlib/hosts.py +++ b/passlib/hosts.py @@ -27,7 +27,7 @@ __all__ = [ linux_context = linux2_context = LazyCryptContext( schemes = [ "sha512_crypt", "sha256_crypt", "md5_crypt", - "des_crypt", "unix_fallback" ], + "des_crypt", "unix_disabled" ], deprecated = [ "des_crypt" ], ) @@ -50,9 +50,14 @@ linux_context = linux2_context = LazyCryptContext( # netbsd - des, ext, md5, bcrypt, sha1 # openbsd - des, ext, md5, bcrypt -freebsd_context = LazyCryptContext([ "bcrypt", "md5_crypt", "bsd_nthash", "des_crypt", "unix_fallback" ]) -openbsd_context = LazyCryptContext([ "bcrypt", "md5_crypt", "bsdi_crypt", "des_crypt", "unix_fallback" ]) -netbsd_context = LazyCryptContext([ "bcrypt", "sha1_crypt", "md5_crypt", "bsdi_crypt", "des_crypt", "unix_fallback" ]) +freebsd_context = LazyCryptContext(["bcrypt", "md5_crypt", "bsd_nthash", + "des_crypt", "unix_disabled"]) + +openbsd_context = LazyCryptContext(["bcrypt", "md5_crypt", "bsdi_crypt", + "des_crypt", "unix_disabled"]) + +netbsd_context = LazyCryptContext(["bcrypt", "sha1_crypt", "md5_crypt", + "bsdi_crypt", "des_crypt", "unix_disabled"]) #========================================================= #current host @@ -73,7 +78,7 @@ if has_crypt: if found: #only offer fallback if there's another scheme in front, #as this can't actually hash any passwords - yield "unix_fallback" + yield "unix_disabled" else: #no idea what OS this could happen on, but just in case... warn("crypt.crypt() function is present, but doesn't support any " diff --git a/passlib/registry.py b/passlib/registry.py index bf252fd..5806816 100644 --- a/passlib/registry.py +++ b/passlib/registry.py @@ -147,7 +147,8 @@ _handler_locations = { "sha256_crypt": ("passlib.handlers.sha2_crypt", "sha256_crypt"), "sha512_crypt": ("passlib.handlers.sha2_crypt", "sha512_crypt"), "sun_md5_crypt": ("passlib.handlers.sun_md5_crypt","sun_md5_crypt"), - "unix_fallback": ("passlib.handlers.misc", "unix_fallback"), + "unix_disabled": ("passlib.handlers.misc", "unix_disabled"), + "unix_fallback": ("passlib.handlers.misc", "unix_fallback"), } #: master regexp for detecting valid handler names diff --git a/passlib/tests/test_handlers.py b/passlib/tests/test_handlers.py index 260d011..2ab9837 100644 --- a/passlib/tests/test_handlers.py +++ b/passlib/tests/test_handlers.py @@ -2164,8 +2164,23 @@ class sun_md5_crypt_test(HandlerCase): return self.handler.verify(secret, hash) #========================================================= -#unix fallback +#unix disabled / fallback #========================================================= +class unix_disabled_test(HandlerCase): + handler = hash.unix_disabled + accepts_all_hashes = True + is_disabled_handler = True + + known_correct_hashes = [ + # everything should hash to "!" (or "*" on BSD), + # and nothing should verify against either string + ("password", "!"), + (UPASS_TABLE, "*"), + ] + + # TODO: test custom marker support + # TODO: test default marker selection + class unix_fallback_test(HandlerCase): handler = hash.unix_fallback accepts_all_hashes = True @@ -2177,6 +2192,11 @@ class unix_fallback_test(HandlerCase): (UPASS_TABLE, "!"), ] + # silence annoying deprecation warning + def setUp(self): + super(unix_fallback_test, self).setUp() + warnings.filterwarnings("ignore", "'unix_fallback' is deprecated") + def test_90_wildcard(self): "test enable_wildcard flag" h = self.handler diff --git a/passlib/tests/test_hosts.py b/passlib/tests/test_hosts.py index 06cc3c5..de744a8 100644 --- a/passlib/tests/test_hosts.py +++ b/passlib/tests/test_hosts.py @@ -24,14 +24,14 @@ class HostsTest(TestCase): # they mainly try to ensure no typos # or dynamic behavior foul-ups. - def check_unix_fallback(self, ctx): + def check_unix_disabled(self, ctx): for hash in [ "", "!", "*", "!$1$TXl/FX/U$BZge.lr.ux6ekjEjxmzwz0", ]: - self.assertEqual(ctx.identify(hash), 'unix_fallback') + self.assertEqual(ctx.identify(hash), 'unix_disabled') self.assertFalse(ctx.verify('test', hash)) def test_linux_context(self): @@ -45,7 +45,7 @@ class HostsTest(TestCase): 'kAJJz.Rwp0A/I', ]: self.assertTrue(ctx.verify("test", hash)) - self.check_unix_fallback(ctx) + self.check_unix_disabled(ctx) def test_bsd_contexts(self): for ctx in [ @@ -63,7 +63,7 @@ class HostsTest(TestCase): self.assertTrue(ctx.verify("test", h1)) else: self.assertEqual(ctx.identify(h1), "bcrypt") - self.check_unix_fallback(ctx) + self.check_unix_disabled(ctx) def test_host_context(self): ctx = getattr(hosts, "host_context", None) @@ -71,16 +71,16 @@ class HostsTest(TestCase): return self.skipTest("host_context not available on this platform") # validate schemes is non-empty, - # and contains unix_fallback + at least one real scheme + # and contains unix_disabled + at least one real scheme schemes = ctx.policy.schemes() self.assertTrue(schemes, "appears to be unix system, but no known schemes supported by crypt") - self.assertTrue('unix_fallback' in schemes) - schemes.remove("unix_fallback") + self.assertTrue('unix_disabled' in schemes) + schemes.remove("unix_disabled") self.assertTrue(schemes, "should have schemes beside fallback scheme") self.assertTrue(set(unix_crypt_schemes).issuperset(schemes)) # check for hash support - self.check_unix_fallback(ctx) + self.check_unix_disabled(ctx) for scheme, hash in [ ("sha512_crypt", ('$6$rounds=41128$VoQLvDjkaZ6L6BIE$4pt.1Ll1XdDYduEwEYPCMOBiR6W6' 'znsyUEoNlcVXpv2gKKIbQolgmTGe6uEEVJ7azUxuc8Tf7zV9SD2z7Ij751')), |
