summaryrefslogtreecommitdiff
path: root/passlib/ext/django/utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'passlib/ext/django/utils.py')
-rw-r--r--passlib/ext/django/utils.py37
1 files changed, 29 insertions, 8 deletions
diff --git a/passlib/ext/django/utils.py b/passlib/ext/django/utils.py
index 3c03637..ab10b6f 100644
--- a/passlib/ext/django/utils.py
+++ b/passlib/ext/django/utils.py
@@ -119,6 +119,10 @@ 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)
@@ -132,13 +136,14 @@ def hasher_to_passlib_name(hasher_name):
#=============================================================================
# wrapping passlib handlers as django hashers
#=============================================================================
-_FAKE_SALT = "--fake-salt--"
+_GEN_SALT_SIGNAL = "--!!!generate-new-salt!!!--"
class _HasherWrapper(object):
"""helper for wrapping passlib handlers in Hasher-compatible class."""
# filled in by subclass, drives the other methods.
passlib_handler = None
+ iterations = None
@classproperty
def algorithm(cls):
@@ -146,19 +151,22 @@ class _HasherWrapper(object):
return PASSLIB_HASHER_PREFIX + cls.passlib_handler.name
def salt(self):
- # XXX: our encode wrapper generates a new salt each time it's called,
- # so just returning a 'no value' flag here.
- return _FAKE_SALT
+ # NOTE: passlib's handler.encrypt() should generate new salt each time,
+ # so this just returns a special constant which tells
+ # encode() (below) not to pass a salt keyword along.
+ return _GEN_SALT_SIGNAL
def verify(self, password, encoded):
return self.passlib_handler.verify(password, encoded)
def encode(self, password, salt=None, iterations=None):
kwds = {}
- if salt is not None and salt != _FAKE_SALT:
+ if salt is not None and salt != _GEN_SALT_SIGNAL:
kwds['salt'] = salt
if iterations is not None:
kwds['rounds'] = iterations
+ elif self.iterations is not None:
+ kwds['rounds'] = self.iterations
return self.passlib_handler.encrypt(password, **kwds)
_translate_kwds = dict(checksum="hash", rounds="iterations")
@@ -178,10 +186,17 @@ class _HasherWrapper(object):
items.append((_(key), value))
return SortedDict(items)
+ # added in django 1.6
+ def must_update(self, encoded):
+ # TODO: would like to do something useful here,
+ # but would require access to password context,
+ # which would mean a serious recoding of this ext.
+ return False
+
# cache of hasher wrappers generated by get_passlib_hasher()
_hasher_cache = WeakKeyDictionary()
-def get_passlib_hasher(handler):
+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),
@@ -204,8 +219,14 @@ def get_passlib_hasher(handler):
handler = get_crypt_handler(handler)
if hasattr(handler, "django_name"):
# return native hasher instance
- # XXX: should cache this too.
- return _get_hasher(handler.django_name)
+ # 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: