Beispiel #1
0
 def test_bad_algorithm(self):
     msg = (
         "Unknown password hashing algorithm '%s'. Did you specify it in "
         "the PASSWORD_HASHERS setting?"
     )
     with self.assertRaisesMessage(ValueError, msg % 'lolcat'):
         make_password('lètmein', hasher='lolcat')
     with self.assertRaisesMessage(ValueError, msg % 'lolcat'):
         identify_hasher('lolcat$salt$hash')
Beispiel #2
0
 def test_unusable(self):
     encoded = make_password(None)
     self.assertEqual(len(encoded), len(UNUSABLE_PASSWORD_PREFIX) + UNUSABLE_PASSWORD_SUFFIX_LENGTH)
     self.assertFalse(is_password_usable(encoded))
     self.assertFalse(check_password(None, encoded))
     self.assertFalse(check_password(encoded, encoded))
     self.assertFalse(check_password(UNUSABLE_PASSWORD_PREFIX, encoded))
     self.assertFalse(check_password('', encoded))
     self.assertFalse(check_password('lètmein', encoded))
     self.assertFalse(check_password('lètmeinz', encoded))
     with self.assertRaises(ValueError):
         identify_hasher(encoded)
     # Assert that the unusable passwords actually contain a random part.
     # This might fail one day due to a hash collision.
     self.assertNotEqual(encoded, make_password(None), "Random password collision?")
 def test_crypt(self):
     encoded = make_password("lètmei", "ab", "crypt")
     self.assertEqual(encoded, "crypt$$ab1Hv2Lg7ltQo")
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password("lètmei", encoded))
     self.assertFalse(check_password("lètmeiz", encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "crypt")
 def test_md5(self):
     encoded = make_password("lètmein", "seasalt", "md5")
     self.assertEqual(encoded, "md5$seasalt$3f86d0d3d465b7b458c231bf3555c0e3")
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password("lètmein", encoded))
     self.assertFalse(check_password("lètmeinz", encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "md5")
 def test_sha1(self):
     encoded = make_password("lètmein", "seasalt", "sha1")
     self.assertEqual(encoded, "sha1$seasalt$cff36ea83f5706ce9aa7454e63e431fc726b2dc8")
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password("lètmein", encoded))
     self.assertFalse(check_password("lètmeinz", encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "sha1")
 def test_pkbdf2(self):
     encoded = make_password("lètmein", "seasalt", "pbkdf2_sha256")
     self.assertEqual(encoded, "pbkdf2_sha256$10000$seasalt$CWWFdHOWwPnki7HvkcqN9iA2T3KLW1cf2uZ5kvArtVY=")
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password("lètmein", encoded))
     self.assertFalse(check_password("lètmeinz", encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "pbkdf2_sha256")
 def test_bcrypt(self):
     encoded = make_password("lètmein", hasher="bcrypt")
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(encoded.startswith("bcrypt$"))
     self.assertTrue(check_password("lètmein", encoded))
     self.assertFalse(check_password("lètmeinz", encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "bcrypt")
Beispiel #8
0
    def test_bcrypt_sha256(self):
        encoded = make_password('lètmein', hasher='bcrypt_sha256')
        self.assertTrue(is_password_usable(encoded))
        self.assertTrue(encoded.startswith('bcrypt_sha256$'))
        self.assertTrue(check_password('lètmein', encoded))
        self.assertFalse(check_password('lètmeinz', encoded))
        self.assertEqual(identify_hasher(encoded).algorithm, "bcrypt_sha256")

        # Verify that password truncation no longer works
        password = ('VSK0UYV6FFQVZ0KG88DYN9WADAADZO1CTSIVDJUNZSUML6IBX7LN7ZS3R5'
                    'JGB3RGZ7VI7G7DJQ9NI8BQFSRPTG6UWTTVESA5ZPUN')
        encoded = make_password(password, hasher='bcrypt_sha256')
        self.assertTrue(check_password(password, encoded))
        self.assertFalse(check_password(password[:72], encoded))
        # Blank passwords
        blank_encoded = make_password('', hasher='bcrypt_sha256')
        self.assertTrue(blank_encoded.startswith('bcrypt_sha256$'))
        self.assertTrue(is_password_usable(blank_encoded))
        self.assertTrue(check_password('', blank_encoded))
        self.assertFalse(check_password(' ', blank_encoded))
        # Long password
        self.assertRaises(
            ValueError,
            make_password,
            b"1" * (MAXIMUM_PASSWORD_LENGTH + 1),
            hasher="bcrypt_sha256",
        )
Beispiel #9
0
 def test_unsalted_md5(self):
     encoded = make_password('lètmein', '', 'unsalted_md5')
     self.assertEqual(encoded, '88a434c88cca4e900f7874cd98123f43')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password('lètmein', encoded))
     self.assertFalse(check_password('lètmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "unsalted_md5")
     # Alternate unsalted syntax
     alt_encoded = "md5$$%s" % encoded
     self.assertTrue(is_password_usable(alt_encoded))
     self.assertTrue(check_password('lètmein', alt_encoded))
     self.assertFalse(check_password('lètmeinz', alt_encoded))
     # Blank passwords
     blank_encoded = make_password('', '', 'unsalted_md5')
     self.assertTrue(is_password_usable(blank_encoded))
     self.assertTrue(check_password('', blank_encoded))
     self.assertFalse(check_password(' ', blank_encoded))
     # Long password
     self.assertRaises(
         ValueError,
         make_password,
         b"1" * (MAXIMUM_PASSWORD_LENGTH + 1),
         "",
         "unsalted_md5",
     )
Beispiel #10
0
 def test_bcrypt(self):
     encoded = make_password('lètmein', hasher='bcrypt')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(encoded.startswith('bcrypt$'))
     self.assertTrue(check_password('lètmein', encoded))
     self.assertFalse(check_password('lètmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "bcrypt")
Beispiel #11
0
 def test_crypt(self):
     encoded = make_password('lètmei', 'ab', 'crypt')
     self.assertEqual(encoded, 'crypt$$ab1Hv2Lg7ltQo')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password('lètmei', encoded))
     self.assertFalse(check_password('lètmeiz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "crypt")
Beispiel #12
0
 def test_crypt(self):
     encoded = make_password('letmein', 'ab', 'crypt')
     self.assertEqual(encoded, 'crypt$$abN/qM.L/H8EQ')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password(u'letmein', encoded))
     self.assertFalse(check_password('letmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "crypt")
Beispiel #13
0
 def test_unsalted_md5(self):
     encoded = make_password('letmein', 'seasalt', 'unsalted_md5')
     self.assertEqual(encoded, '0d107d09f5bbe40cade3de5c71e9e9b7')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password(u'letmein', encoded))
     self.assertFalse(check_password('letmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "unsalted_md5")
Beispiel #14
0
 def clean_password(self, ix=''):
     if ix != '':
         ix = '_%i' % ix
     password = self.cleaned_data.get('password%s' % ix)
     if password:
         # lazy loading because of passlib
         from django.contrib.auth.hashers import identify_hasher
         self.password_provided = True
         try:
             identify_hasher(password)
         except ValueError:
             raise forms.ValidationError(
                 self.error_messages['bad_hash'],
                 code='bad_hash',
             )
     return password
Beispiel #15
0
 def test_unsalted_md5(self):
     encoded = make_password('lètmein', 'seasalt', 'unsalted_md5')
     self.assertEqual(encoded, '88a434c88cca4e900f7874cd98123f43')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password('lètmein', encoded))
     self.assertFalse(check_password('lètmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "unsalted_md5")
Beispiel #16
0
    def render(self, name, value, attrs=None, renderer=None):
        final_attrs = flatatt(self.build_attrs(attrs))

        if not value or not is_password_usable(value):
            summary = ugettext("No password set.")
        else:
            try:
                identify_hasher(value)
            except ValueError:
                summary = ugettext("Invalid password format or unknown"
                                   " hashing algorithm.")
            else:
                summary = ugettext('*************')

        return format_html('<div{attrs}><strong>{summary}</strong></div>',
                           attrs=final_attrs, summary=summary)
Beispiel #17
0
    def test_sha1(self):
        encoded = make_password('letmein', 'seasalt', 'sha1')
        self.assertEqual(encoded, 
'sha1$seasalt$fec3530984afba6bade3347b7140d1a7da7da8c7')
        self.assertTrue(is_password_usable(encoded))
        self.assertTrue(check_password(u'letmein', encoded))
        self.assertFalse(check_password('letmeinz', encoded))
        self.assertEqual(identify_hasher(encoded).algorithm, "sha1")
Beispiel #18
0
 def test_md5(self):
     encoded = make_password('letmein', 'seasalt', 'md5')
     self.assertEqual(encoded, 
                      'md5$seasalt$f5531bef9f3687d0ccf0f617f0e25573')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password(u'letmein', encoded))
     self.assertFalse(check_password('letmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "md5")
Beispiel #19
0
    def render(self, name, value, attrs):
        from django.forms.util import flatatt
        final_attrs = flatatt(self.build_attrs(attrs))

        if not value or value == UNUSABLE_PASSWORD:
            summary = ugettext("No password set.")
        else:
            try:
                identify_hasher(value)
            except ValueError:
                summary = ugettext("Invalid password format or unknown"
                                   " hashing algorithm.")
            else:
                summary = ugettext('*************')

        return format_html('<div{attrs}><strong>{summary}</strong></div>',
                           attrs=final_attrs, summary=summary)
Beispiel #20
0
    def test_pkbdf2(self):
        encoded = make_password('letmein', 'seasalt', 'pbkdf2_sha256')
        self.assertEqual(encoded, 
'pbkdf2_sha256$10000$seasalt$FQCNpiZpTb0zub+HBsH6TOwyRxJ19FwvjbweatNmK/Y=')
        self.assertTrue(is_password_usable(encoded))
        self.assertTrue(check_password(u'letmein', encoded))
        self.assertFalse(check_password('letmeinz', encoded))
        self.assertEqual(identify_hasher(encoded).algorithm, "pbkdf2_sha256")
Beispiel #21
0
 def test_unsalted_sha1(self):
     encoded = make_password('lètmein', '', 'unsalted_sha1')
     self.assertEqual(encoded, 'sha1$$6d138ca3ae545631b3abd71a4f076ce759c5700b')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password('lètmein', encoded))
     self.assertFalse(check_password('lètmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "unsalted_sha1")
     # Raw SHA1 isn't acceptable
     alt_encoded = encoded[6:]
     self.assertFalse(check_password('lètmein', alt_encoded))
Beispiel #22
0
    def render(self, name, value, attrs):
        try:
            from django.forms.utils import flatatt
        except ImportError:
            from django.forms.util import flatatt  # Django < 1.7
        final_attrs = flatatt(self.build_attrs(attrs))

        if not value or not is_password_usable(value):
            summary = _("No password set.")
        else:
            try:
                identify_hasher(value)
            except ValueError:
                summary = _("Invalid password format or unknown"
                                   " hashing algorithm.")
            else:
                summary = _('*************')

        return format_html('<div{attrs}><strong>{summary}</strong></div>',
                           attrs=final_attrs, summary=summary)
Beispiel #23
0
 def test_unsalted_md5(self):
     encoded = make_password('lètmein', '', 'unsalted_md5')
     self.assertEqual(encoded, '88a434c88cca4e900f7874cd98123f43')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password('lètmein', encoded))
     self.assertFalse(check_password('lètmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "unsalted_md5")
     # Alternate unsalted syntax
     alt_encoded = "md5$$%s" % encoded
     self.assertTrue(is_password_usable(alt_encoded))
     self.assertTrue(check_password('lètmein', alt_encoded))
     self.assertFalse(check_password('lètmeinz', alt_encoded))
Beispiel #24
0
 def test_unsalted_sha1(self):
     encoded = make_password('lètmein', 'seasalt', 'unsalted_sha1')
     self.assertEqual(encoded, '38474bd98757137304be00938b15cef5b8ad9c98')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password(u'lètmein', encoded))
     self.assertFalse(check_password('lètmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "unsalted_sha1")
     # Alternate unsalted syntax
     alt_encoded = "sha1$$%s" % encoded
     self.assertTrue(is_password_usable(alt_encoded))
     self.assertTrue(check_password(u'lètmein', alt_encoded))
     self.assertFalse(check_password('lètmeinz', alt_encoded))
    def render(self, name, value, attrs=None):
        """
        Redefine the render to have an error message if there is any error
        else an empty string ('').
        """
        encoded = value
        final_attrs = self.build_attrs(attrs)
        if not encoded or encoded.startswith(UNUSABLE_PASSWORD_PREFIX):
            summary = mark_safe("<strong>%s</strong>" % _(
                'oscm_admin_noPasswordSet'))
        else:
            try:
                identify_hasher(encoded)
            except ValueError:
                summary = mark_safe(
                    "<strong>%s</strong>" % _(
                        'oscm_admin_invalidPasswordFormatOrUnknownHashAlgo'))
            else:
                # Return empty string
                summary = ''

        return format_html("<div{0}>{1}</div>", flatatt(final_attrs), summary)
Beispiel #26
0
 def test_pbkdf2(self):
     encoded = make_password('lètmein', 'seasalt', 'pbkdf2_sha256')
     self.assertEqual(encoded, 'pbkdf2_sha256$100000$seasalt$BNZ6eyaNc8qFTJPjrAq99hSYb73EgAdytAtdBg2Sdcc=')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password('lètmein', encoded))
     self.assertFalse(check_password('lètmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "pbkdf2_sha256")
     # Blank passwords
     blank_encoded = make_password('', 'seasalt', 'pbkdf2_sha256')
     self.assertTrue(blank_encoded.startswith('pbkdf2_sha256$'))
     self.assertTrue(is_password_usable(blank_encoded))
     self.assertTrue(check_password('', blank_encoded))
     self.assertFalse(check_password(' ', blank_encoded))
Beispiel #27
0
 def test_pkbdf2(self):
     encoded = make_password("lètmein", "seasalt", "pbkdf2_sha256")
     self.assertEqual(encoded, "pbkdf2_sha256$20000$seasalt$oBSd886ysm3AqYun62DOdin8YcfbU1z9cksZSuLP9r0=")
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password("lètmein", encoded))
     self.assertFalse(check_password("lètmeinz", encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "pbkdf2_sha256")
     # Blank passwords
     blank_encoded = make_password("", "seasalt", "pbkdf2_sha256")
     self.assertTrue(blank_encoded.startswith("pbkdf2_sha256$"))
     self.assertTrue(is_password_usable(blank_encoded))
     self.assertTrue(check_password("", blank_encoded))
     self.assertFalse(check_password(" ", blank_encoded))
Beispiel #28
0
 def test_pbkdf2(self):
     encoded = make_password('lètmein', 'seasalt', 'pbkdf2_sha256')
     self.assertEqual(encoded, 'pbkdf2_sha256$36000$seasalt$mEUPPFJkT/xtwDU8rB7Q+puHRZnR07WRjerTkt/3HI0=')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password('lètmein', encoded))
     self.assertFalse(check_password('lètmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "pbkdf2_sha256")
     # Blank passwords
     blank_encoded = make_password('', 'seasalt', 'pbkdf2_sha256')
     self.assertTrue(blank_encoded.startswith('pbkdf2_sha256$'))
     self.assertTrue(is_password_usable(blank_encoded))
     self.assertTrue(check_password('', blank_encoded))
     self.assertFalse(check_password(' ', blank_encoded))
Beispiel #29
0
 def test_md5(self):
     encoded = make_password('lètmein', 'seasalt', 'md5')
     self.assertEqual(encoded, 'md5$seasalt$3f86d0d3d465b7b458c231bf3555c0e3')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password('lètmein', encoded))
     self.assertFalse(check_password('lètmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "md5")
     # Blank passwords
     blank_encoded = make_password('', 'seasalt', 'md5')
     self.assertTrue(blank_encoded.startswith('md5$'))
     self.assertTrue(is_password_usable(blank_encoded))
     self.assertTrue(check_password('', blank_encoded))
     self.assertFalse(check_password(' ', blank_encoded))
Beispiel #30
0
 def test_sha1(self):
     encoded = make_password('lètmein', 'seasalt', 'sha1')
     self.assertEqual(encoded, 'sha1$seasalt$cff36ea83f5706ce9aa7454e63e431fc726b2dc8')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password('lètmein', encoded))
     self.assertFalse(check_password('lètmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "sha1")
     # Blank passwords
     blank_encoded = make_password('', 'seasalt', 'sha1')
     self.assertTrue(blank_encoded.startswith('sha1$'))
     self.assertTrue(is_password_usable(blank_encoded))
     self.assertTrue(check_password('', blank_encoded))
     self.assertFalse(check_password(' ', blank_encoded))
Beispiel #31
0
 def test_unsalted_sha1(self):
     encoded = make_password('lètmein', '', 'unsalted_sha1')
     self.assertEqual(encoded,
                      'sha1$$6d138ca3ae545631b3abd71a4f076ce759c5700b')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password('lètmein', encoded))
     self.assertFalse(check_password('lètmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "unsalted_sha1")
     # Raw SHA1 isn't acceptable
     alt_encoded = encoded[6:]
     self.assertFalse(check_password('lètmein', alt_encoded))
     # Blank passwords
     blank_encoded = make_password('', '', 'unsalted_sha1')
     self.assertTrue(blank_encoded.startswith('sha1$'))
     self.assertTrue(is_password_usable(blank_encoded))
     self.assertTrue(check_password('', blank_encoded))
     self.assertFalse(check_password(' ', blank_encoded))
Beispiel #32
0
    def test_sha512(self):
        encoded = make_password('lètmein', 'seasalt', 'sha512')
        assert encoded == (
            'sha512$seasalt$16bf4502ffdfce9551b90319d06674e6faa3e174144123d'
            '392d94470ebf0aa77096b871f9e84f60ed2bac2f10f755368b068e52547e04'
            '35fef8b4f6ca237d7d8')
        assert is_password_usable(encoded)
        assert check_password('lètmein', encoded)
        assert not check_password('lètmeinz', encoded)
        assert identify_hasher(encoded).algorithm == "sha512"

        # Blank passwords
        blank_encoded = make_password('', 'seasalt', 'sha512')
        assert blank_encoded.startswith('sha512$')
        assert is_password_usable(blank_encoded)
        assert check_password('', blank_encoded)
        assert not check_password(' ', blank_encoded)
Beispiel #33
0
 def test_scrypt(self):
     encoded = make_password("lètmein", "seasalt", "scrypt")
     self.assertEqual(
         encoded,
         "scrypt$16384$seasalt$8$1$Qj3+9PPyRjSJIebHnG81TMjsqtaIGxNQG/aEB/NY"
         "afTJ7tibgfYz71m0ldQESkXFRkdVCBhhY8mx7rQwite/Pw==",
     )
     self.assertIs(is_password_usable(encoded), True)
     self.assertIs(check_password("lètmein", encoded), True)
     self.assertIs(check_password("lètmeinz", encoded), False)
     self.assertEqual(identify_hasher(encoded).algorithm, "scrypt")
     # Blank passwords.
     blank_encoded = make_password("", "seasalt", "scrypt")
     self.assertIs(blank_encoded.startswith("scrypt$"), True)
     self.assertIs(is_password_usable(blank_encoded), True)
     self.assertIs(check_password("", blank_encoded), True)
     self.assertIs(check_password(" ", blank_encoded), False)
Beispiel #34
0
 def test_unsalted_md5(self):
     encoded = make_password('lètmein', '', 'unsalted_md5')
     self.assertEqual(encoded, '88a434c88cca4e900f7874cd98123f43')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password('lètmein', encoded))
     self.assertFalse(check_password('lètmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "unsalted_md5")
     # Alternate unsalted syntax
     alt_encoded = "md5$$%s" % encoded
     self.assertTrue(is_password_usable(alt_encoded))
     self.assertTrue(check_password('lètmein', alt_encoded))
     self.assertFalse(check_password('lètmeinz', alt_encoded))
     # Blank passwords
     blank_encoded = make_password('', '', 'unsalted_md5')
     self.assertTrue(is_password_usable(blank_encoded))
     self.assertTrue(check_password('', blank_encoded))
     self.assertFalse(check_password(' ', blank_encoded))
Beispiel #35
0
 def test_unsalted_sha1(self):
     encoded = make_password('lètmein', '', 'unsalted_sha1')
     self.assertEqual(encoded, 'sha1$$6d138ca3ae545631b3abd71a4f076ce759c5700b')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password('lètmein', encoded))
     self.assertFalse(check_password('lètmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "unsalted_sha1")
     # Raw SHA1 isn't acceptable
     alt_encoded = encoded[6:]
     self.assertFalse(check_password('lètmein', alt_encoded))
     # Long password
     self.assertRaises(
         ValueError,
         make_password,
         b"1" * (MAXIMUM_PASSWORD_LENGTH + 1),
         "",
         "unslated_sha1",
     )
Beispiel #36
0
    def render(self, name, value, attrs):
        encoded = value

        if not is_password_usable(encoded):
            return "None"

        final_attrs = self.build_attrs(attrs)

        try:
            hasher = identify_hasher(encoded)
        except ValueError:
            summary = "<strong>Invalid password format or unknown hashing algorithm.</strong>"
        else:
            summary = ""
            for key, value in hasher.safe_summary(encoded).iteritems():
                summary += "<strong>%(key)s</strong>: %(value)s " % {"key": ugettext(key), "value": value}

        return mark_safe("<div%(attrs)s>%(summary)s</div>" % {"attrs": flatatt(final_attrs), "summary": summary})
Beispiel #37
0
def password_check(value, user):
    """
    Check that the password passes the following validation:

    Password is long enough (based on configuration setting)
    Password contains at least one digit
    Password contains at least one letter
    Password contains at least one uppercase character
    Password contains at least one special character
    Password has not been reused in a configurable number of password cycles
    """
    if len(value) < settings.AUTH_PASSWORD_LENGTH:
        raise serializers.ValidationError('Password is too short')
    # check for digit
    if not any(char.isdigit() for char in value):
        raise serializers.ValidationError(
            'Password must contain at least 1 digit.')
    # check for letter
    if not any(char.isalpha() for char in value):
        raise serializers.ValidationError(
            'Password must contain at least 1 letter.')
    # check for upper case letter
    if not any(char.isupper() for char in value):
        raise serializers.ValidationError(
            'Password must contain at least 1 uppercase letter.')
    # check for symbol
    if not any(not char.isalnum() for char in value):
        raise serializers.ValidationError(
            'Password must contain at least 1 special character.')

    # new users won't have a password history at this point
    if user is not None:
        prior_passwords = PasswordHistory.objects.filter(
            user_id=user.id).order_by(
                'created_at').reverse()[:settings.AUTH_PASSWORD_HISTORY_COUNT]

        for p in prior_passwords:
            hasher = identify_hasher(p.password)
            if hasher.verify(value, p.password):
                raise serializers.ValidationError(
                    'Password can not have been one of the last %d passwords' %
                    settings.AUTH_PASSWORD_HISTORY_COUNT)

    return value
Beispiel #38
0
 def test_pbkdf2(self):
     encoded = make_password('lètmein', 'seasalt', 'pbkdf2_sha256')
     self.assertEqual(encoded, 'pbkdf2_sha256$320000$seasalt$Toj2II2rBvFiGQcPmUml1Nlni2UtvyRWwz/jz4q6q/4=')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password('lètmein', encoded))
     self.assertFalse(check_password('lètmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "pbkdf2_sha256")
     # Blank passwords
     blank_encoded = make_password('', 'seasalt', 'pbkdf2_sha256')
     self.assertTrue(blank_encoded.startswith('pbkdf2_sha256$'))
     self.assertTrue(is_password_usable(blank_encoded))
     self.assertTrue(check_password('', blank_encoded))
     self.assertFalse(check_password(' ', blank_encoded))
     # Salt entropy check.
     hasher = get_hasher('pbkdf2_sha256')
     encoded_weak_salt = make_password('lètmein', 'iodizedsalt', 'pbkdf2_sha256')
     encoded_strong_salt = make_password('lètmein', hasher.salt(), 'pbkdf2_sha256')
     self.assertIs(hasher.must_update(encoded_weak_salt), True)
     self.assertIs(hasher.must_update(encoded_strong_salt), False)
Beispiel #39
0
 def test_sha1(self):
     encoded = make_password('lètmein', 'seasalt', 'sha1')
     self.assertEqual(encoded, 'sha1$seasalt$cff36ea83f5706ce9aa7454e63e431fc726b2dc8')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password('lètmein', encoded))
     self.assertFalse(check_password('lètmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "sha1")
     # Blank passwords
     blank_encoded = make_password('', 'seasalt', 'sha1')
     self.assertTrue(blank_encoded.startswith('sha1$'))
     self.assertTrue(is_password_usable(blank_encoded))
     self.assertTrue(check_password('', blank_encoded))
     self.assertFalse(check_password(' ', blank_encoded))
     # Salt entropy check.
     hasher = get_hasher('sha1')
     encoded_weak_salt = make_password('lètmein', 'iodizedsalt', 'sha1')
     encoded_strong_salt = make_password('lètmein', hasher.salt(), 'sha1')
     self.assertIs(hasher.must_update(encoded_weak_salt), True)
     self.assertIs(hasher.must_update(encoded_strong_salt), False)
Beispiel #40
0
 def test_md5(self):
     encoded = make_password("lètmein", "seasalt", "md5")
     self.assertEqual(encoded, "md5$seasalt$3f86d0d3d465b7b458c231bf3555c0e3")
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password("lètmein", encoded))
     self.assertFalse(check_password("lètmeinz", encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "md5")
     # Blank passwords
     blank_encoded = make_password("", "seasalt", "md5")
     self.assertTrue(blank_encoded.startswith("md5$"))
     self.assertTrue(is_password_usable(blank_encoded))
     self.assertTrue(check_password("", blank_encoded))
     self.assertFalse(check_password(" ", blank_encoded))
     # Salt entropy check.
     hasher = get_hasher("md5")
     encoded_weak_salt = make_password("lètmein", "iodizedsalt", "md5")
     encoded_strong_salt = make_password("lètmein", hasher.salt(), "md5")
     self.assertIs(hasher.must_update(encoded_weak_salt), True)
     self.assertIs(hasher.must_update(encoded_strong_salt), False)
Beispiel #41
0
def import_hash(algorithm, hash):
    """Import a hash as given by the RestAuth import data format.

    Raises ValueError if the hasher cannot be identified.
    """
    if algorithm == 'django':
        return hash

    try:
        import hashers_passlib
        hasher = getattr(hashers_passlib, str(algorithm))()
    except AttributeError:
        try:
            from hashers_passlib import converters
            hasher = getattr(hashers_passlib, str(converters))()
        except AttributeError:
            hasher = identify_hasher(algorithm)  # try to get from Django

    return hasher.from_orig(hash)
Beispiel #42
0
 def test_argon2(self):
     encoded = make_password('lètmein', hasher='argon2')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(encoded.startswith('argon2$'))
     self.assertTrue(check_password('lètmein', encoded))
     self.assertFalse(check_password('lètmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, 'argon2')
     # Blank passwords
     blank_encoded = make_password('', hasher='argon2')
     self.assertTrue(blank_encoded.startswith('argon2$'))
     self.assertTrue(is_password_usable(blank_encoded))
     self.assertTrue(check_password('', blank_encoded))
     self.assertFalse(check_password(' ', blank_encoded))
     # Old hashes without version attribute
     encoded = (
         'argon2$argon2i$m=8,t=1,p=1$c29tZXNhbHQ$gwQOXSNhxiOxPOA0+PY10P9QFO'
         '4NAYysnqRt1GSQLE55m+2GYDt9FEjPMHhP2Cuf0nOEXXMocVrsJAtNSsKyfg')
     self.assertTrue(check_password('secret', encoded))
     self.assertFalse(check_password('wrong', encoded))
Beispiel #43
0
    def render(self, name, value, attrs):
        encoded = value
        final_attrs = self.build_attrs(attrs)

        if not encoded or encoded.startswith(UNUSABLE_PASSWORD_PREFIX):
            summary = mark_safe("<strong>%s</strong>" %
                                ugettext("No password set."))
        else:
            try:
                hasher = identify_hasher(encoded)
            except ValueError:
                summary = mark_safe("<strong>%s</strong>" % ugettext(
                    "Invalid password format or unknown hashing algorithm."))
            else:
                summary = format_html_join(
                    '', "<strong>{0}</strong>: {1} ",
                    ((ugettext(key), value)
                     for key, value in hasher.safe_summary(encoded).items()))

        return format_html("<div{0}>{1}</div>", flatatt(final_attrs), summary)
Beispiel #44
0
    def test_bcrypt_sha256(self):
        encoded = make_password('lètmein', hasher='bcrypt_sha256')
        self.assertTrue(is_password_usable(encoded))
        self.assertTrue(encoded.startswith('bcrypt_sha256$'))
        self.assertTrue(check_password('lètmein', encoded))
        self.assertFalse(check_password('lètmeinz', encoded))
        self.assertEqual(identify_hasher(encoded).algorithm, "bcrypt_sha256")

        # Verify that password truncation no longer works
        password = ('VSK0UYV6FFQVZ0KG88DYN9WADAADZO1CTSIVDJUNZSUML6IBX7LN7ZS3R5'
                    'JGB3RGZ7VI7G7DJQ9NI8BQFSRPTG6UWTTVESA5ZPUN')
        encoded = make_password(password, hasher='bcrypt_sha256')
        self.assertTrue(check_password(password, encoded))
        self.assertFalse(check_password(password[:72], encoded))
        # Blank passwords
        blank_encoded = make_password('', hasher='bcrypt_sha256')
        self.assertTrue(blank_encoded.startswith('bcrypt_sha256$'))
        self.assertTrue(is_password_usable(blank_encoded))
        self.assertTrue(check_password('', blank_encoded))
        self.assertFalse(check_password(' ', blank_encoded))
Beispiel #45
0
 def get_context(self, name, value, attrs):
     context = super().get_context(name, value, attrs)
     summary = []
     if not value or value.startswith(UNUSABLE_PASSWORD_PREFIX):
         summary.append({"label": gettext("No password set.")})
     else:
         try:
             hasher = identify_hasher(value)
         except ValueError:
             summary.append({
                 "label":
                 gettext(
                     "Invalid password format or unknown hashing algorithm."
                 )
             })
         else:
             for key, value_ in hasher.safe_summary(value).items():
                 summary.append({"label": gettext(key), "value": value_})
     context["summary"] = summary
     return context
Beispiel #46
0
    def check_password(self, raw_password):
        def setter(raw_password):
            self.set_password(raw_password)
            self.save(update_fields=["password"])

        if raw_password is None:
            return False

        hasher = get_hasher("default")
        must_update = False
        if self.password.find('$') > 0:
            hasher = identify_hasher(self.password)
            must_update = True

        is_correct = hasher.verify(raw_password, self.password)
        if is_correct and must_update:
            self.set_password(raw_password)
            self.save(update_fields=["password"])

        return is_correct
Beispiel #47
0
    def render(self, name, value, attrs):
        encoded = value
        final_attrs = self.build_attrs(attrs)

        if not encoded or encoded.startswith(UNUSABLE_PASSWORD_PREFIX):
            summary = mark_safe("<strong>%s</strong>" % ugettext("Пароль не задан."))
        else:
            try:
                hasher = identify_hasher(encoded)
            except ValueError:
                summary = mark_safe("<strong>%s</strong>" % ugettext(
                    "Неверный формат пароля или неизвестный алгоритм хэширования."))
            else:
                summary = format_html_join('',
                                           "<strong>{}</strong>: {} ",
                                           ((ugettext(key), value)
                                            for key, value in hasher.safe_summary(encoded).items())
                                           )

        return format_html("<div{}>{}</div>", flatatt(final_attrs), summary)
Beispiel #48
0
 def test_unsalted_md5(self):
     encoded = make_password('lètmein', '', 'unsalted_md5')
     self.assertEqual(encoded, '88a434c88cca4e900f7874cd98123f43')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password('lètmein', encoded))
     self.assertFalse(check_password('lètmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "unsalted_md5")
     # Alternate unsalted syntax
     alt_encoded = "md5$$%s" % encoded
     self.assertTrue(is_password_usable(alt_encoded))
     self.assertTrue(check_password('lètmein', alt_encoded))
     self.assertFalse(check_password('lètmeinz', alt_encoded))
     # Long password
     self.assertRaises(
         ValueError,
         make_password,
         b"1" * (MAXIMUM_PASSWORD_LENGTH + 1),
         "",
         "unsalted_md5",
     )
Beispiel #49
0
 def test_bcrypt(self):
     encoded = make_password('lètmein', hasher='bcrypt')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(encoded.startswith('bcrypt$'))
     self.assertTrue(check_password('lètmein', encoded))
     self.assertFalse(check_password('lètmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "bcrypt")
     # Blank passwords
     blank_encoded = make_password('', hasher='bcrypt')
     self.assertTrue(blank_encoded.startswith('bcrypt$'))
     self.assertTrue(is_password_usable(blank_encoded))
     self.assertTrue(check_password('', blank_encoded))
     self.assertFalse(check_password(' ', blank_encoded))
     # Long password
     self.assertRaises(
         ValueError,
         make_password,
         b"1" * (MAXIMUM_PASSWORD_LENGTH + 1),
         hasher="bcrypt",
     )
Beispiel #50
0
    def render(self, name, value, attrs):
        encoded = value

        if not is_password_usable(encoded):
            return "None"

        final_attrs = self.build_attrs(attrs)

        try:
            hasher = identify_hasher(encoded)
        except ValueError:
            summary = mark_safe(
                "<strong>Invalid password format or unknown hashing algorithm.</strong>"
            )
        else:
            summary = format_html_join(
                '', "<strong>{0}</strong>: {1} ",
                ((ugettext(key), value)
                 for key, value in hasher.safe_summary(encoded).items()))

        return format_html("<div{0}>{1}</div>", flatatt(final_attrs), summary)
Beispiel #51
0
 def test_crypt(self):
     encoded = make_password('lètmei', 'ab', 'crypt')
     self.assertEqual(encoded, 'crypt$$ab1Hv2Lg7ltQo')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password('lètmei', encoded))
     self.assertFalse(check_password('lètmeiz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "crypt")
     # Blank passwords
     blank_encoded = make_password('', 'ab', 'crypt')
     self.assertTrue(blank_encoded.startswith('crypt$'))
     self.assertTrue(is_password_usable(blank_encoded))
     self.assertTrue(check_password('', blank_encoded))
     self.assertFalse(check_password(' ', blank_encoded))
     # Long password
     self.assertRaises(
         ValueError,
         make_password,
         b"1" * (MAXIMUM_PASSWORD_LENGTH + 1),
         "seasalt",
         "crypt",
     )
Beispiel #52
0
    def check_password(self, user, raw_password):
        """
Compares a raw (UNENCRYPTED!!!) password to entries in the users's
password history.

:arg object user: A :class:`~django.contrib.auth.models.User` instance.
:arg str raw_password: A unicode string representing a password.
:returns: ``False`` if a password has been used before, ``True`` if not.
:rtype: bool
"""
        result = True
        if user.check_password(raw_password):
            result = False
        else:
            entries = self.filter(user=user).all()[:self.default_offset]
            for entry in entries:
                hasher = identify_hasher(entry.password)
                if hasher.verify(raw_password, entry.password):
                    result = False
                    break
        return result
Beispiel #53
0
 def test_pbkdf2(self):
     encoded = make_password("lètmein", "seasalt", "pbkdf2_sha256")
     self.assertEqual(
         encoded,
         "pbkdf2_sha256$390000$seasalt$8xBlGd3jVgvJ+92hWPxi5ww0uuAuAnKgC45eudxro7c=",
     )
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password("lètmein", encoded))
     self.assertFalse(check_password("lètmeinz", encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "pbkdf2_sha256")
     # Blank passwords
     blank_encoded = make_password("", "seasalt", "pbkdf2_sha256")
     self.assertTrue(blank_encoded.startswith("pbkdf2_sha256$"))
     self.assertTrue(is_password_usable(blank_encoded))
     self.assertTrue(check_password("", blank_encoded))
     self.assertFalse(check_password(" ", blank_encoded))
     # Salt entropy check.
     hasher = get_hasher("pbkdf2_sha256")
     encoded_weak_salt = make_password("lètmein", "iodizedsalt", "pbkdf2_sha256")
     encoded_strong_salt = make_password("lètmein", hasher.salt(), "pbkdf2_sha256")
     self.assertIs(hasher.must_update(encoded_weak_salt), True)
     self.assertIs(hasher.must_update(encoded_strong_salt), False)
Beispiel #54
0
 def test_md5(self):
     encoded = make_password('lètmein', 'seasalt', 'md5')
     self.assertEqual(encoded,
                      'md5$seasalt$3f86d0d3d465b7b458c231bf3555c0e3')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password('lètmein', encoded))
     self.assertFalse(check_password('lètmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "md5")
     # Blank passwords
     blank_encoded = make_password('', 'seasalt', 'md5')
     self.assertTrue(blank_encoded.startswith('md5$'))
     self.assertTrue(is_password_usable(blank_encoded))
     self.assertTrue(check_password('', blank_encoded))
     self.assertFalse(check_password(' ', blank_encoded))
     # Long password
     self.assertRaises(
         ValueError,
         make_password,
         b"1" * (MAXIMUM_PASSWORD_LENGTH + 1),
         "seasalt",
         "md5",
     )
Beispiel #55
0
 def test_sha1(self):
     encoded = make_password('lètmein', 'seasalt', 'sha1')
     self.assertEqual(
         encoded, 'sha1$seasalt$cff36ea83f5706ce9aa7454e63e431fc726b2dc8')
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password('lètmein', encoded))
     self.assertFalse(check_password('lètmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "sha1")
     # Blank passwords
     blank_encoded = make_password('', 'seasalt', 'sha1')
     self.assertTrue(blank_encoded.startswith('sha1$'))
     self.assertTrue(is_password_usable(blank_encoded))
     self.assertTrue(check_password('', blank_encoded))
     self.assertFalse(check_password(' ', blank_encoded))
     # Long password
     self.assertRaises(
         ValueError,
         make_password,
         b"1" * (MAXIMUM_PASSWORD_LENGTH + 1),
         "seasalt",
         "sha1",
     )
Beispiel #56
0
    def render(self, name, value, attrs):
        encoded = value
        final_attrs = self.build_attrs(attrs)

        if not encoded or encoded.startswith(UNUSABLE_PASSWORD_PREFIX):
            summary = mark_safe("<strong>%s</strong>" % ugettext("No password set."))
        else:
            try:
                hasher = identify_hasher(encoded)
            except ValueError:
                summary = mark_safe("<strong>%s</strong>" % ugettext(
                    "Invalid password format or unknown hashing algorithm."
                ))
            else:
                summary = format_html_join(
                    '', '<strong>{}</strong>: {} ',
                    ((ugettext(key), value) for key, value in hasher.safe_summary(encoded).items())
                )
        #Write by Kaajavi
        summary = "Raw passwords are not stored, so there is no way to see this \
                  user's password, but you can change the password using \
                  <a href=\"../password/\">this form</a>."

        return format_html("<div{}>{}</div>", flatatt(final_attrs), format_html(summary))
Beispiel #57
0
 def test_pbkdf2(self):
     encoded = make_password("lètmein", "seasalt", "pbkdf2_sha256")
     self.assertEqual(
         encoded,
         "pbkdf2_sha256$480000$seasalt$G4ja8YRtfnNyEx4Ii2pbFMp/l8s4nnbMdJ+Fob/qNK8=",
     )
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password("lètmein", encoded))
     self.assertFalse(check_password("lètmeinz", encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "pbkdf2_sha256")
     # Blank passwords
     blank_encoded = make_password("", "seasalt", "pbkdf2_sha256")
     self.assertTrue(blank_encoded.startswith("pbkdf2_sha256$"))
     self.assertTrue(is_password_usable(blank_encoded))
     self.assertTrue(check_password("", blank_encoded))
     self.assertFalse(check_password(" ", blank_encoded))
     # Salt entropy check.
     hasher = get_hasher("pbkdf2_sha256")
     encoded_weak_salt = make_password("lètmein", "iodizedsalt",
                                       "pbkdf2_sha256")
     encoded_strong_salt = make_password("lètmein", hasher.salt(),
                                         "pbkdf2_sha256")
     self.assertIs(hasher.must_update(encoded_weak_salt), True)
     self.assertIs(hasher.must_update(encoded_strong_salt), False)
Beispiel #58
0
 def test_pbkdf2(self):
     encoded = make_password('lètmein', 'seasalt', 'pbkdf2_sha256')
     self.assertEqual(
         encoded,
         'pbkdf2_sha256$260000$seasalt$YlZ2Vggtqdc61YjArZuoApoBh9JNGYoDRBUGu6tcJQo='
     )
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password('lètmein', encoded))
     self.assertFalse(check_password('lètmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "pbkdf2_sha256")
     # Blank passwords
     blank_encoded = make_password('', 'seasalt', 'pbkdf2_sha256')
     self.assertTrue(blank_encoded.startswith('pbkdf2_sha256$'))
     self.assertTrue(is_password_usable(blank_encoded))
     self.assertTrue(check_password('', blank_encoded))
     self.assertFalse(check_password(' ', blank_encoded))
     # Salt entropy check.
     hasher = get_hasher('pbkdf2_sha256')
     encoded_weak_salt = make_password('lètmein', 'iodizedsalt',
                                       'pbkdf2_sha256')
     encoded_strong_salt = make_password('lètmein', hasher.salt(),
                                         'pbkdf2_sha256')
     self.assertIs(hasher.must_update(encoded_weak_salt), True)
     self.assertIs(hasher.must_update(encoded_strong_salt), False)
Beispiel #59
0
 def test_pkbdf2(self):
     encoded = make_password('lètmein', 'seasalt', 'pbkdf2_sha256')
     self.assertEqual(
         encoded,
         'pbkdf2_sha256$12000$seasalt$Ybw8zsFxqja97tY/o6G+Fy1ksY4U/Hw3DRrGED6Up4s='
     )
     self.assertTrue(is_password_usable(encoded))
     self.assertTrue(check_password('lètmein', encoded))
     self.assertFalse(check_password('lètmeinz', encoded))
     self.assertEqual(identify_hasher(encoded).algorithm, "pbkdf2_sha256")
     # Blank passwords
     blank_encoded = make_password('', 'seasalt', 'pbkdf2_sha256')
     self.assertTrue(blank_encoded.startswith('pbkdf2_sha256$'))
     self.assertTrue(is_password_usable(blank_encoded))
     self.assertTrue(check_password('', blank_encoded))
     self.assertFalse(check_password(' ', blank_encoded))
     # Long password
     self.assertRaises(
         ValueError,
         make_password,
         b"1" * (MAXIMUM_PASSWORD_LENGTH + 1),
         "seasalt",
         "pbkdf2_sha256",
     )
Beispiel #60
0
    def test_config(self):
        """test hashing interface

        this function is run against both the actual django code, to
        verify the assumptions of the unittests are correct;
        and run against the passlib extension, to verify it matches
        those assumptions.
        """
        log = self.getLogger()
        patched, config = self.patched, self.config
        # this tests the following methods:
        #   User.set_password()
        #   User.check_password()
        #   make_password() -- 1.4 only
        #   check_password()
        #   identify_hasher()
        #   User.has_usable_password()
        #   User.set_unusable_password()
        # XXX: this take a while to run. what could be trimmed?

        #  TODO: get_hasher()

        #=======================================================
        # setup helpers & imports
        #=======================================================
        ctx = self.context
        setter = create_mock_setter()
        PASS1 = "toomanysecrets"
        WRONG1 = "letmein"

        from django.contrib.auth.hashers import (check_password, make_password,
                                                 is_password_usable,
                                                 identify_hasher)

        #=======================================================
        # make sure extension is configured correctly
        #=======================================================
        if patched:
            # contexts should match
            from passlib.ext.django.models import password_context
            self.assertEqual(password_context.to_dict(resolve=True),
                             ctx.to_dict(resolve=True))

            # should have patched both places
            from django.contrib.auth.models import check_password as check_password2
            self.assertEqual(check_password2, check_password)

        #=======================================================
        # default algorithm
        #=======================================================
        # User.set_password() should use default alg
        user = FakeUser()
        user.set_password(PASS1)
        self.assertTrue(ctx.handler().verify(PASS1, user.password))
        self.assert_valid_password(user)

        # User.check_password() - n/a

        # make_password() should use default alg
        hash = make_password(PASS1)
        self.assertTrue(ctx.handler().verify(PASS1, hash))

        # check_password() - n/a

        #=======================================================
        # empty password behavior
        #=======================================================

        # User.set_password() should use default alg
        user = FakeUser()
        user.set_password('')
        hash = user.password
        self.assertTrue(ctx.handler().verify('', hash))
        self.assert_valid_password(user, hash)

        # User.check_password() should return True
        self.assertTrue(user.check_password(""))
        self.assert_valid_password(user, hash)

        # no make_password()

        # check_password() should return True
        self.assertTrue(check_password("", hash))

        #=======================================================
        # 'unusable flag' behavior
        #=======================================================

        # sanity check via user.set_unusable_password()
        user = FakeUser()
        user.set_unusable_password()
        self.assert_unusable_password(user)

        # ensure User.set_password() sets unusable flag
        user = FakeUser()
        user.set_password(None)
        self.assert_unusable_password(user)

        # User.check_password() should always fail
        self.assertFalse(user.check_password(None))
        self.assertFalse(user.check_password('None'))
        self.assertFalse(user.check_password(''))
        self.assertFalse(user.check_password(PASS1))
        self.assertFalse(user.check_password(WRONG1))
        self.assert_unusable_password(user)

        # make_password() should also set flag
        self.assertTrue(make_password(None).startswith("!"))

        # check_password() should return False (didn't handle disabled under 1.3)
        self.assertFalse(check_password(PASS1, '!'))

        # identify_hasher() and is_password_usable() should reject it
        self.assertFalse(is_password_usable(user.password))
        self.assertRaises(ValueError, identify_hasher, user.password)

        #=======================================================
        # hash=None
        #=======================================================
        # User.set_password() - n/a

        # User.check_password() - returns False
        # FIXME: at some point past 1.8, some of these django started handler None differently;
        #        and/or throwing TypeError.  need to investigate when that change occurred;
        #        update these tests, and maybe passlib.ext.django as well.
        user = FakeUser()
        user.password = None
        self.assertFalse(user.check_password(PASS1))
        self.assertFalse(user.has_usable_password())

        # make_password() - n/a

        # check_password() - error
        self.assertFalse(check_password(PASS1, None))

        # identify_hasher() - error
        self.assertRaises(TypeError, identify_hasher, None)

        #=======================================================
        # empty & invalid hash values
        # NOTE: django 1.5 behavior change due to django ticket 18453
        # NOTE: passlib integration tries to match current django version
        #=======================================================
        for hash in (
                "",  # empty hash
                "$789$foo",  # empty identifier
        ):
            # User.set_password() - n/a

            # User.check_password()
            # As of django 1.5, blank OR invalid hash returns False
            user = FakeUser()
            user.password = hash
            self.assertFalse(user.check_password(PASS1))

            # verify hash wasn't changed/upgraded during check_password() call
            self.assertEqual(user.password, hash)
            self.assertEqual(user.pop_saved_passwords(), [])

            # User.has_usable_password()
            self.assertFalse(user.has_usable_password())

            # make_password() - n/a

            # check_password()
            self.assertFalse(check_password(PASS1, hash))

            # identify_hasher() - throws error
            self.assertRaises(ValueError, identify_hasher, hash)

        #=======================================================
        # run through all the schemes in the context,
        # testing various bits of per-scheme behavior.
        #=======================================================
        for scheme in ctx.schemes():

            #
            # TODO: break this loop up into separate parameterized tests.
            #

            #-------------------------------------------------------
            # setup constants & imports, pick a sample secret/hash combo
            #-------------------------------------------------------

            handler = ctx.handler(scheme)
            log.debug("testing scheme: %r => %r", scheme, handler)
            deprecated = ctx.handler(scheme).deprecated
            assert not deprecated or scheme != ctx.default_scheme()
            try:
                testcase = get_handler_case(scheme)
            except exc.MissingBackendError:
                continue
            assert handler_derived_from(handler, testcase.handler)
            if handler.is_disabled:
                continue

            # verify that django has a backend available
            # (since our hasher may use different set of backends,
            #  get_handler_case() above may work, but django will have nothing)
            if not patched and not check_django_hasher_has_backend(
                    handler.django_name):
                assert scheme in ["django_bcrypt", "django_bcrypt_sha256", "django_argon2"], \
                    "%r scheme should always have active backend" % scheme
                # TODO: make this a SkipTest() once this loop has been parameterized.
                log.warn("skipping scheme %r due to missing django dependancy",
                         scheme)
                continue

            # find a sample (secret, hash) pair to test with
            try:
                secret, hash = sample_hashes[scheme]
            except KeyError:
                get_sample_hash = testcase("setUp").get_sample_hash
                while True:
                    secret, hash = get_sample_hash()
                    if secret:  # don't select blank passwords
                        break
            other = 'dontletmein'

            #-------------------------------------------------------
            # User.set_password() - not tested here
            #-------------------------------------------------------

            #-------------------------------------------------------
            # User.check_password()+migration against known hash
            #-------------------------------------------------------
            user = FakeUser()
            user.password = hash

            # check against invalid password
            self.assertFalse(user.check_password(None))
            ##self.assertFalse(user.check_password(''))
            self.assertFalse(user.check_password(other))
            self.assert_valid_password(user, hash)

            # check against valid password
            self.assertTrue(user.check_password(secret))

            # check if it upgraded the hash
            # NOTE: needs_update kept separate in case we need to test rounds.
            needs_update = deprecated
            if needs_update:
                self.assertNotEqual(user.password, hash)
                self.assertFalse(handler.identify(user.password))
                self.assertTrue(ctx.handler().verify(secret, user.password))
                self.assert_valid_password(user, saved=user.password)
            else:
                self.assert_valid_password(user, hash)

            # don't need to check rest for most deployments
            if TEST_MODE(max="default"):
                continue

            #-------------------------------------------------------
            # make_password() correctly selects algorithm
            #-------------------------------------------------------
            alg = DjangoTranslator().passlib_to_django_name(scheme)
            hash2 = make_password(secret, hasher=alg)
            self.assertTrue(handler.verify(secret, hash2))

            #-------------------------------------------------------
            # check_password()+setter against known hash
            #-------------------------------------------------------
            # should call setter only if it needs_update
            self.assertTrue(check_password(secret, hash, setter=setter))
            self.assertEqual(setter.popstate(),
                             [secret] if needs_update else [])

            # should not call setter
            self.assertFalse(check_password(other, hash, setter=setter))
            self.assertEqual(setter.popstate(), [])

            ### check preferred kwd is ignored (feature we don't currently support fully)
            ##self.assertTrue(check_password(secret, hash, setter=setter, preferred='fooey'))
            ##self.assertEqual(setter.popstate(), [secret])

            # TODO: get_hasher()

            #-------------------------------------------------------
            # identify_hasher() recognizes known hash
            #-------------------------------------------------------
            self.assertTrue(is_password_usable(hash))
            name = DjangoTranslator().django_to_passlib_name(
                identify_hasher(hash).algorithm)
            self.assertEqual(name, scheme)