Skip to content

Commit 446307f

Browse files
committed
Elaborate unit tests to cover a few more important uses:
* clarify that make_hash generates value depending on random seed * assure check_hash works despite this variation in hashes depending on seed * make sure otherwise valid password reset tokens fail when expired
1 parent 1c9899f commit 446307f

File tree

1 file changed

+53
-9
lines changed

1 file changed

+53
-9
lines changed

tests/test_mig_shared_pwcrypto.py

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -155,11 +155,11 @@ def test_make_hash_constant_string(self):
155155
random seed. I.e. the value may differ across interpreter invocations
156156
but remains constant in same interpreter.
157157
"""
158-
first = make_hash(
159-
DUMMY_WEAK_PW, _urandom=lambda vlen: DUMMY_SALT[:vlen])
160-
second = make_hash(
161-
DUMMY_WEAK_PW, _urandom=lambda vlen: DUMMY_SALT[:vlen])
162-
self.assertEqual(first, second, "hashing is not constant")
158+
first = make_hash(DUMMY_WEAK_PW,
159+
_urandom=lambda vlen: DUMMY_SALT[:vlen])
160+
second = make_hash(DUMMY_WEAK_PW,
161+
_urandom=lambda vlen: DUMMY_SALT[:vlen])
162+
self.assertEqual(first, second, "same seed hashing is not constant")
163163

164164
def test_check_hash_reject_weak(self):
165165
"""Test basic hash checking of a constant weak complexity password"""
@@ -209,8 +209,8 @@ def test_check_hash_accept_modern(self):
209209
allow_legacy=False)
210210
self.assertTrue(result, "check hash must accept modern complexity pw")
211211

212-
def test_check_hash_constant(self):
213-
"""Test basic hash checking of a constant string"""
212+
def test_check_hash_fixed(self):
213+
"""Test basic hash checking of a fixed string"""
214214
expected = make_hash(DUMMY_MEDIUM_PW)
215215
result = check_hash(self.dummy_conf, DUMMY_SERVICE, DUMMY_USER,
216216
DUMMY_MEDIUM_PW, expected, strict_policy=True)
@@ -232,6 +232,33 @@ def test_check_hash_random(self):
232232
random_pw, expected)
233233
self.assertTrue(result, "mismatch in random hash check")
234234

235+
def test_make_hash_variation(self):
236+
"""Test how hashing of a fixed string varies depending on random seed.
237+
I.e. the value likely remains constant in same interpreter but differs
238+
across interpreter invocations.
239+
"""
240+
first = make_hash(DUMMY_MODERN_PW,
241+
_urandom=lambda vlen: DUMMY_SALT[:vlen])
242+
second = make_hash(DUMMY_MODERN_PW,
243+
_urandom=lambda vlen: DUMMY_SALT[::-1][:vlen])
244+
self.assertNotEqual(first, second, "varying seed hashing is constant")
245+
246+
def test_check_hash_despite_variation(self):
247+
"""Test that check_hash works independently of random seed variation.
248+
I.e. the hash value differs across interpreter invocations but testing
249+
the same password against each succeeds.
250+
"""
251+
first = make_hash(DUMMY_MODERN_PW,
252+
_urandom=lambda vlen: DUMMY_SALT[:vlen])
253+
second = make_hash(DUMMY_MODERN_PW,
254+
_urandom=lambda vlen: DUMMY_SALT[::-1][:vlen])
255+
result = check_hash(self.dummy_conf, DUMMY_SERVICE, DUMMY_USER,
256+
DUMMY_MODERN_PW, first)
257+
self.assertTrue(result, "mismatch in 1st random password hash check")
258+
result = check_hash(self.dummy_conf, DUMMY_SERVICE, DUMMY_USER,
259+
DUMMY_MODERN_PW, second)
260+
self.assertTrue(result, "mismatch in 2nd random password hash check")
261+
235262
def test_check_digest(self):
236263
"""Test basic digest checking of a random string"""
237264
random_pw = generate_random_password(self.dummy_conf)
@@ -317,8 +344,8 @@ def test_check_encrypt(self):
317344
random_pw, encrypted, algo='aesgcm_static')
318345
self.assertTrue(result, "mismatch in aesgcm_static encrypt check")
319346

320-
def test_password_reset_token(self):
321-
"""Test basic password reset token handling on a random string"""
347+
def test_password_reset_token_generate_and_verify(self):
348+
"""Test basic password reset token generate and verify helper"""
322349
random_pw = generate_random_password(self.dummy_conf)
323350
hashed_pw = make_hash(random_pw)
324351
dummy_user = {'distinguished_name': DUMMY_USER}
@@ -333,6 +360,23 @@ def test_password_reset_token(self):
333360
DUMMY_SERVICE, timestamp)
334361
self.assertTrue(result, "failed password reset token handling")
335362

363+
def test_password_reset_token_verify_expired(self):
364+
"""Test basic password reset token verify failure after it expired"""
365+
random_pw = generate_random_password(self.dummy_conf)
366+
hashed_pw = make_hash(random_pw)
367+
dummy_user = {'distinguished_name': DUMMY_USER}
368+
dummy_user['password_hash'] = hashed_pw
369+
timestamp = 42
370+
expected = generate_reset_token(self.dummy_conf, dummy_user,
371+
DUMMY_SERVICE, timestamp)
372+
parsed = parse_reset_token(self.dummy_conf, expected, DUMMY_SERVICE)
373+
self.assertEqual(parsed[0], timestamp, "failed parse token time")
374+
self.assertEqual(parsed[1], hashed_pw, "failed parse token hash")
375+
timestamp = 4242
376+
result = verify_reset_token(self.dummy_conf, dummy_user, expected,
377+
DUMMY_SERVICE, timestamp)
378+
self.assertFalse(result, "failed password reset token expiry check")
379+
336380
# TODO: migrate remaining inline checks from module here instead
337381

338382

0 commit comments

Comments
 (0)