summaryrefslogtreecommitdiff
path: root/passlib
diff options
context:
space:
mode:
authorEli Collins <elic@assurancetechnologies.com>2012-03-10 17:48:58 -0500
committerEli Collins <elic@assurancetechnologies.com>2012-03-10 17:48:58 -0500
commitd3c7d16915f7ef3919245f211b8dab8ae35ade70 (patch)
tree47e128e356e5d5363c7efdde5de944a52fd6191a /passlib
parent50965db6ee2b6ff2c9227ea6c740e9513963c4f6 (diff)
downloadpasslib-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.py77
-rw-r--r--passlib/hosts.py15
-rw-r--r--passlib/registry.py3
-rw-r--r--passlib/tests/test_handlers.py22
-rw-r--r--passlib/tests/test_hosts.py16
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')),