summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Graham <timograham@gmail.com>2013-11-29 20:49:56 -0500
committerTim Graham <timograham@gmail.com>2013-11-30 14:18:37 -0500
commitfddb0131d37109c809ec391e1a134ef1d9e442a7 (patch)
tree402eb84892c1286f9dedd704c94b983e95940e84
parent2688462f914960b568dce4cb529db77e982a5284 (diff)
Fixed #21535 -- Fixed password hash iteration upgrade.
Thanks jared_mess for the report.
-rw-r--r--django/contrib/auth/hashers.py2
-rw-r--r--django/contrib/auth/tests/test_hashers.py36
-rw-r--r--docs/releases/1.6.1.txt1
3 files changed, 36 insertions, 3 deletions
diff --git a/django/contrib/auth/hashers.py b/django/contrib/auth/hashers.py
index a4e8133460..713240b502 100644
--- a/django/contrib/auth/hashers.py
+++ b/django/contrib/auth/hashers.py
@@ -57,7 +57,7 @@ def check_password(password, encoded, setter=None, preferred='default'):
must_update = hasher.algorithm != preferred.algorithm
if not must_update:
- must_update = hasher.must_update(encoded)
+ must_update = preferred.must_update(encoded)
is_correct = hasher.verify(password, encoded)
if setter and is_correct and must_update:
setter(password)
diff --git a/django/contrib/auth/tests/test_hashers.py b/django/contrib/auth/tests/test_hashers.py
index d76a81b1a3..58628cd6cd 100644
--- a/django/contrib/auth/tests/test_hashers.py
+++ b/django/contrib/auth/tests/test_hashers.py
@@ -1,13 +1,13 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-import unittest
from unittest import skipUnless
from django.conf.global_settings import PASSWORD_HASHERS as default_hashers
from django.contrib.auth.hashers import (is_password_usable, BasePasswordHasher,
check_password, make_password, PBKDF2PasswordHasher, load_hashers, PBKDF2SHA1PasswordHasher,
get_hasher, identify_hasher, UNUSABLE_PASSWORD_PREFIX, UNUSABLE_PASSWORD_SUFFIX_LENGTH)
+from django.test import SimpleTestCase
from django.utils import six
@@ -22,7 +22,11 @@ except ImportError:
bcrypt = None
-class TestUtilsHashPass(unittest.TestCase):
+class PBKDF2SingleIterationHasher(PBKDF2PasswordHasher):
+ iterations = 1
+
+
+class TestUtilsHashPass(SimpleTestCase):
def setUp(self):
load_hashers(password_hashers=default_hashers)
@@ -279,6 +283,34 @@ class TestUtilsHashPass(unittest.TestCase):
finally:
hasher.iterations = old_iterations
+ def test_pbkdf2_upgrade_new_hasher(self):
+ self.assertEqual('pbkdf2_sha256', get_hasher('default').algorithm)
+ hasher = get_hasher('default')
+ self.assertNotEqual(hasher.iterations, 1)
+
+ state = {'upgraded': False}
+
+ def setter(password):
+ state['upgraded'] = True
+
+ with self.settings(PASSWORD_HASHERS=[
+ 'django.contrib.auth.tests.test_hashers.PBKDF2SingleIterationHasher']):
+ encoded = make_password('letmein')
+ algo, iterations, salt, hash = encoded.split('$', 3)
+ self.assertEqual(iterations, '1')
+
+ # Check that no upgrade is triggerd
+ self.assertTrue(check_password('letmein', encoded, setter))
+ self.assertFalse(state['upgraded'])
+
+ # Revert to the old iteration count and check if the password would get
+ # updated to the new iteration count.
+ with self.settings(PASSWORD_HASHERS=[
+ 'django.contrib.auth.hashers.PBKDF2PasswordHasher',
+ 'django.contrib.auth.tests.test_hashers.PBKDF2SingleIterationHasher']):
+ self.assertTrue(check_password('letmein', encoded, setter))
+ self.assertTrue(state['upgraded'])
+
def test_load_library_no_algorithm(self):
with self.assertRaises(ValueError) as e:
BasePasswordHasher()._load_library()
diff --git a/docs/releases/1.6.1.txt b/docs/releases/1.6.1.txt
index f7c76afbb1..4b23737d94 100644
--- a/docs/releases/1.6.1.txt
+++ b/docs/releases/1.6.1.txt
@@ -40,3 +40,4 @@ Bug fixes
* Fixed test client ``logout()`` method when using the cookie-based session
backend (#21448).
* Fixed a crash when a ``GeometryField`` uses a non-geometric widget (#21496).
+* Fixed password hash upgrade when changing the iteration count (#21535).