Mock CTO interview: migrating users with legacy password hashes

Mock CTO Interview November 13, 2026 python

You: "I imported the legacy hashes with an algorithm prefix and wrote a custom password hasher.

python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# ======================================================================
# Q: CTO: "How did you migrate users with their old passwords?"
#
# You: "I imported the legacy hashes with an algorithm prefix and wrote a custom
# password hasher. Because the modern hasher is first in PASSWORD_HASHERS,
# Django automatically rehashes on the first successful login. So no mass
# password reset was needed, and over time the old hashes disappeared. Those who
# never logged in received a reset email after six months."
# ======================================================================

class LegacyASPHasher(BasePasswordHasher):
    algorithm = 'legacy_md5'          # stored as legacy_md5$salt$hash

    def verify(self, password, encoded):
        _, salt, hash_ = encoded.split('$', 2)
        candidate = hashlib.md5((salt + password).encode()).hexdigest()
        return constant_time_compare(candidate, hash_)

    def safe_summary(self, encoded):
        return {'algorithm': self.algorithm}

PASSWORD_HASHERS = [
    'django.contrib.auth.hashers.Argon2PasswordHasher',   # preferred -> rehash
    'django.contrib.auth.hashers.PBKDF2PasswordHasher',
    'accounts.hashers.LegacyASPHasher',
]