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", )
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", )
def test_walkthrough(self): USERNAME = PASSWORD = '******' server_user = User.objects.create_user(USERNAME, '*****@*****.**', PASSWORD) consumer = self._get_consumer() # verify theres no tokens yet self.assertEqual(Token.objects.count(), 0) response = self.client.get(reverse('simple-sso-login')) # there should be a token now self.assertEqual(Token.objects.count(), 1) # this should be a HttpResponseRedirect self.assertEqual(response.status_code, HttpResponseRedirect.status_code) # check that it's the URL we expect url = urlparse(response['Location']) path = url.path self.assertEqual(path, reverse('simple-sso-authorize')) # follow that redirect response = self.client.get(response['Location']) # now we should have another redirect to the login self.assertEqual(response.status_code, HttpResponseRedirect.status_code, response.content) # check that the URL is correct url = urlparse(response['Location']) path = url.path self.assertEqual(path, reverse('login')) # follow that redirect login_url = response['Location'] response = self.client.get(login_url) # now we should have a 200 self.assertEqual(response.status_code, HttpResponse.status_code) # and log in using the username/password from above response = self.client.post(login_url, {'username': USERNAME, 'password': PASSWORD}) # now we should have a redirect back to the authorize view self.assertEqual(response.status_code, HttpResponseRedirect.status_code) # check that it's the URL we expect url = urlparse(response['Location']) path = url.path self.assertEqual(path, reverse('simple-sso-authorize')) # follow that redirect response = self.client.get(response['Location']) # this should again be a redirect self.assertEqual(response.status_code, HttpResponseRedirect.status_code) # this time back to the client app, confirm that! url = urlparse(response['Location']) path = url.path self.assertEqual(path, reverse('simple-sso-authenticate')) # follow it again response = self.client.get(response['Location']) # again a redirect! This time to / url = urlparse(response['Location']) path = url.path self.assertEqual(path, reverse('root')) # if we follow to root now, we should be logged in response = self.client.get(response['Location']) client_user = get_user(self.client) self.assertFalse(is_password_usable(client_user.password)) self.assertTrue(is_password_usable(server_user.password)) for key in ['username', 'email', 'first_name', 'last_name']: self.assertEqual(getattr(client_user, key), getattr(server_user, key))
def test_unsalted_md5(self): encoded = make_password("letmein", "", "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)) # Alternate unsalted syntax alt_encoded = "md5$$%s" % encoded self.assertTrue(is_password_usable(alt_encoded)) self.assertTrue(check_password(u"letmein", alt_encoded)) self.assertFalse(check_password("letmeinz", alt_encoded))
def test_unsalted_md5(self): encoded = make_password('letmein', '', '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)) # Alternate unsalted syntax alt_encoded = "md5$$%s" % encoded self.assertTrue(is_password_usable(alt_encoded)) self.assertTrue(check_password(u'letmein', alt_encoded)) self.assertFalse(check_password('letmeinz', alt_encoded))
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 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") # 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))
def test_simple(self): encoded = make_password("lètmein") self.assertTrue(encoded.startswith("pbkdf2_sha256$")) self.assertTrue(is_password_usable(encoded)) self.assertTrue(check_password("lètmein", encoded)) self.assertFalse(check_password("lètmeinz", encoded)) # Blank passwords blank_encoded = make_password("") 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))
def test_simple(self): encoded = make_password('lètmein') self.assertTrue(encoded.startswith('pbkdf2_sha256$')) self.assertTrue(is_password_usable(encoded)) self.assertTrue(check_password('lètmein', encoded)) self.assertFalse(check_password('lètmeinz', encoded)) # Blank passwords blank_encoded = make_password('') 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))
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))
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))
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))
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))
def test_pbkdf2(self): encoded = make_password('lètmein', 'seasalt', 'pbkdf2_sha256') self.assertEqual(encoded, 'pbkdf2_sha256$30000$seasalt$VrX+V8drCGo68wlvy6rfu8i1d1pfkdeXA4LJkRGJodY=') 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))
def test_pkbdf2(self): encoded = make_password("lètmein", "seasalt", "pbkdf2_sha256") self.assertEqual(encoded, "pbkdf2_sha256$24000$seasalt$V9DfCAVoweeLwxC/L2mb+7swhzF0XYdyQMqmusZqiTc=") 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))
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") # 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))
def test_pbkdf2(self): encoded = make_password('lètmein', 'seasalt', 'pbkdf2_sha256') self.assertEqual(encoded, 'pbkdf2_sha256$150000$seasalt$71l36B3C2UesFoWz5oshQ1SSTtCLnDO5RMysCfljq5o=') 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))
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))
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))
def test_pbkdf2(self): encoded = make_password('lètmein', 'seasalt', 'pbkdf2_sha256') self.assertEqual(encoded, 'pbkdf2_sha256$120000$seasalt$fsgWMpOXin7ZAmi4j+7XjKCZ4JCvxJTGiwwDrawRqSc=') 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))
def test_user_already_logged_in(self): USERNAME = PASSWORD = '******' server_user = User.objects.create_user(USERNAME, '*****@*****.**', PASSWORD) consumer = self._get_consumer() with UserLoginContext(self, server_user): # try logging in and auto-follow all 302s self.client.get(reverse('simple-sso-login'), follow=True) # check the user client_user = get_user(self.client) self.assertFalse(is_password_usable(client_user.password)) self.assertTrue(is_password_usable(server_user.password)) for key in ['username', 'email', 'first_name', 'last_name']: self.assertEqual(getattr(client_user, key), getattr(server_user, key))
def test_pbkdf2(self): encoded = make_password('lètmein', 'seasalt', 'pbkdf2_sha256') self.assertEqual(encoded, 'pbkdf2_sha256$180000$seasalt$gH56uAM9k5UGHuCzAYqLtJQ7AFgnXEZ4LMzt71ldHoc=') 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))
def test_unsalted_md5(self): encoded = make_password("letmein", "", "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)) # Alternate unsalted syntax alt_encoded = "md5$$%s" % encoded self.assertTrue(is_password_usable(alt_encoded)) self.assertTrue(check_password(u"letmein", alt_encoded)) self.assertFalse(check_password("letmeinz", alt_encoded)) # Long password self.assertRaises(ValueError, make_password, "1" * (MAXIMUM_PASSWORD_LENGTH + 1), "", "unsalted_md5")
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))
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))
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))
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))
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))
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))
def test_pbkdf2(self): encoded = make_password('lètmein', 'seasalt', 'pbkdf2_sha256') self.assertEqual(encoded, 'pbkdf2_sha256$24000$seasalt$V9DfCAVoweeLwxC/L2mb+7swhzF0XYdyQMqmusZqiTc=') 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))
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_onboarding_works(graphql_client, smsoutbox): result = execute_onboarding(graphql_client) for i in [1, 2, 3]: assert result['session'][f'onboardingStep{i}'] is None assert result['session']['phoneNumber'] == '5551234567' request = graphql_client.request user = JustfixUser.objects.get(phone_number='5551234567') oi = user.onboarding_info assert user.full_name == 'boop jones' assert user.pk == request.user.pk assert is_password_usable(user.password) is True assert oi.address == '123 boop way' assert oi.needs_repairs is True assert oi.lease_type == 'MARKET_RATE' assert len(smsoutbox) == 1 assert smsoutbox[0].to == "+15551234567" assert "Welcome to JustFix.nyc, boop" in smsoutbox[0].body
def change_password(request): """Handles the creation of a new user for authentication Method args: request -- the full HTTP request object """ errors_found = False errors = dict() req_body = json.loads(request.body.decode()) all_users = User.objects.all() # get user from auth token token = request.META.get('HTTP_AUTHORIZATION').split(" ")[1] current_user = User.objects.get(auth_token=token) # get old password from request old_password = req_body['old_password'] new_password = req_body['new_password'] # confirm that users old password is correct if not check_password(old_password, current_user.password): errors_found = True errors['old_password'] = "******" # confirm that new password is usable if not is_password_usable(new_password): errors_found = True errors['new_password'] = "******" # change the password if not errors: new_hash = make_password(new_password) current_user.password = new_hash # save the user current_user.save() # return sucsess or error response = json.dumps({"sucsess": "password changed"}) else: response = json.dumps(errors) return HttpResponse(response, content_type='application/json')
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)
def post(self, request, format=None): if request.user.is_authenticated: raise PermissionDenied users = User.objects.all() for user in users: if user.email == request.data['email']: return render(request, 'sign_up.html', {'message': 'already existed email.'}) if is_password_usable(request.data['password']) and request.data[ 'first_name'] != '' and request.data['last_name'] != '': user = User.objects.create_user(username=request.data['username'], email=request.data['email']) user.first_name = request.data['first_name'] user.last_name = request.data['last_name'] user.set_password(request.data['password']) user.save() return redirect('/sign_in') else: return render(request, 'sign_up.html', {'message': 'wrong input.'})
def render(self, name, value, attrs): encoded = value if not is_password_usable(encoded): return "None" final_attrs = self.build_attrs(attrs) encoded = smart_str(encoded) if len(encoded) == 32 and '$' not in encoded: hasher = get_hasher('md5') else: algorithm = encoded.split('$', 1)[0] hasher = get_hasher(algorithm) 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})
def view(request, album_id, secret): try: album_id = int(album_id) album = Album.objects.get(pk=album_id) logger.debug("User is trying to access album %d with secret %s." % (album_id, secret)) if album.secret != secret: logger.debug("Secret does not match.") return render(request, "album-share-failure.html") if request.method == "GET": # user owns the album if request.user == album.user or request.session.get( "album_%d" % album_id): return render(request, "base-interactive.html") if not hashers.is_password_usable(album.password): logger.debug("Album does not has a password yet.") return render(request, "album-share-failure.html") return landingpage.view_album_login(request) else: password = request.POST["album_password"] if hashers.check_password(password, album.password): request.session["album_%d" % album_id] = True return redirect("/album/%d/view/%s/" % (album_id, album.secret)) else: logger.debug("Password %s is incorrect." % password) today = datetime.date.today().strftime("%w") return render( request, "album-share-login.html", { "password_incorrect_error": "Passwort is not correct.", "day": today.strftime("%w") }) except Exception as e: logger.info(str(e)) return render(request, "album-share-failure.html")
def register(request): # if method is POST if request.method == "POST": # get post details display_name = request.POST['display_name'] email = request.POST['email'] username = request.POST['username'] if is_password_usable(request.POST['password']): password = request.POST['password'] else: context = { 'status': False, 'result': 'Password is not usable' } return JsonResponse(context) # create the user profile new_profile = Profile(display_name=display_name, email=email, password=password, username=username) # see if user already exists with that username try: new_profile.save() context = { 'status': True, 'result': 'User profile successfully created' } # if the unique username already exists except IntegrityError: context = { 'status': False, 'result': 'User already exists with that username' } # return the JsonResponse return JsonResponse(context) # if trying to GET return HttpResponse("Error, cannot complete GET request")
def password_change(request, template_name='account/password_settings.html', password_change_form=CurrentPasswordChangeForm): post_change_redirect = reverse_lazy('account:profile-settings') if request.method == "POST": form = password_change_form(user=request.user, data=request.POST) if form.is_valid(): form.save() # Updating the password logs out all other sessions for the user # except the current one if # django.contrib.auth.middleware.SessionAuthenticationMiddleware # is enabled. update_session_auth_hash(request, form.user) messages.success(request, _("Password has been changed")) return HttpResponseRedirect(post_change_redirect) else: form = password_change_form(user=request.user) context = { 'form': form, 'is_password_usable': is_password_usable(request.user.password) } return TemplateResponse(request, template_name, context)
def test_unusable_flag(self): """ test how methods handle 'unusable flag' in hash """ # NOTE: import has to be done w/in method, in case monkeypatching is applied by setUp() from django.contrib.auth.hashers import ( check_password, make_password, is_password_usable, identify_hasher, ) # 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)
def post(self, request): users = User.objects.all() for user in users: if user.email == request.data['email']: return Response({"error": "already existed email."}, status=status.HTTP_400_BAD_REQUEST) if user.username == request.data['username']: return Response({"error": "already existed username."}, status=status.HTTP_400_BAD_REQUEST) if is_password_usable(request.data['password']) and request.data[ 'first_name'] != '' and request.data['last_name'] != '': user = User.objects.create_user(username=request.data['username'], email=request.data['email']) user.first_name = request.data['first_name'] user.last_name = request.data['last_name'] user.set_password(request.data['password']) user.save() myuser = myUser.objects.create(user_id=user.id) serializer = UserSerializer(user) return Response(serializer.data, status=status.HTTP_201_CREATED) else: return Response({"error": "wrong input."}, status=status.HTTP_400_BAD_REQUEST)
def create_frontend_user_and_application(apps, schema_editor): # create user User = apps.get_model('auth', 'User') user = User.objects.create(username=USER_USERNAME, password=make_password(None)) assert not is_password_usable( user.password) # double-check that the password is unusable # create application Application = apps.get_model("oauth2_provider", "Application") application = Application.objects.create( name=APPLICATION_NAME, user=user, client_type='confidential', authorization_grant_type='client-credentials') # create access token AccessToken = apps.get_model("oauth2_provider", "AccessToken") AccessToken.objects.create(token=common.generate_token(), application=application, expires=timezone.now() + timedelta(days=(365 * 5)), scope='read')
def password_hashing(instance, **kwargs): if not is_password_usable(instance.password): instance.password = make_password(instance.password)
def create_default_oob_flow(apps: Apps, schema_editor: BaseDatabaseSchemaEditor): from authentik.stages.prompt.models import FieldTypes User = apps.get_model("authentik_core", "User") PolicyBinding = apps.get_model("authentik_policies", "PolicyBinding") Flow = apps.get_model("authentik_flows", "Flow") FlowStageBinding = apps.get_model("authentik_flows", "FlowStageBinding") UserLoginStage = apps.get_model("authentik_stages_user_login", "UserLoginStage") UserWriteStage = apps.get_model("authentik_stages_user_write", "UserWriteStage") PromptStage = apps.get_model("authentik_stages_prompt", "PromptStage") Prompt = apps.get_model("authentik_stages_prompt", "Prompt") ExpressionPolicy = apps.get_model("authentik_policies_expression", "ExpressionPolicy") db_alias = schema_editor.connection.alias # Only create the flow if the akadmin user exists, # and has an un-usable password akadmins = User.objects.filter(username="******") if not akadmins.exists(): return akadmin = akadmins.first() if is_password_usable(akadmin.password): return # Create a policy that sets the flow's user prefill_policy, _ = ExpressionPolicy.objects.using( db_alias).update_or_create( name="default-oob-prefill-user", defaults={"expression": PREFILL_POLICY_EXPRESSION}, ) password_usable_policy, _ = ExpressionPolicy.objects.using( db_alias).update_or_create( name="default-oob-password-usable", defaults={"expression": PW_USABLE_POLICY_EXPRESSION}, ) prompt_header, _ = Prompt.objects.using(db_alias).update_or_create( field_key="oob-header-text", defaults={ "label": "oob-header-text", "type": FieldTypes.STATIC, "placeholder": "Welcome to authentik! Please set a password for the default admin user, akadmin.", "order": 100, }, ) prompt_email, _ = Prompt.objects.using(db_alias).update_or_create( field_key="email", defaults={ "label": "Email", "type": FieldTypes.EMAIL, "placeholder": "Admin email", "order": 101, }, ) password_first = Prompt.objects.using(db_alias).get(field_key="password") password_second = Prompt.objects.using(db_alias).get( field_key="password_repeat") prompt_stage, _ = PromptStage.objects.using(db_alias).update_or_create( name="default-oob-password", ) prompt_stage.fields.set( [prompt_header, prompt_email, password_first, password_second]) prompt_stage.save() user_write, _ = UserWriteStage.objects.using(db_alias).update_or_create( name="default-password-change-write") login_stage, _ = UserLoginStage.objects.using(db_alias).update_or_create( name="default-authentication-login") flow, _ = Flow.objects.using(db_alias).update_or_create( slug="initial-setup", designation=FlowDesignation.STAGE_CONFIGURATION, defaults={ "name": "default-oob-setup", "title": "Welcome to authentik!", }, ) PolicyBinding.objects.using(db_alias).update_or_create( policy=password_usable_policy, target=flow, defaults={"order": 0}) FlowStageBinding.objects.using(db_alias).update_or_create( target=flow, stage=prompt_stage, defaults={ "order": 10, }, ) user_write_binding, _ = FlowStageBinding.objects.using( db_alias).update_or_create( target=flow, stage=user_write, defaults={ "order": 20, "evaluate_on_plan": False, "re_evaluate_policies": True }, ) PolicyBinding.objects.using(db_alias).update_or_create( policy=prefill_policy, target=user_write_binding, defaults={"order": 0}) FlowStageBinding.objects.using(db_alias).update_or_create( target=flow, stage=login_stage, defaults={ "order": 100, }, )
def has_usable_password(self): return is_password_usable(self.password)
def test_simple(self): encoded = make_password('lètmein') self.assertTrue(encoded.startswith('pbkdf2_sha256$')) self.assertTrue(is_password_usable(encoded)) self.assertTrue(check_password('lètmein', encoded)) self.assertFalse(check_password('lètmeinz', encoded))
def userLogged(request): if request.user.is_authenticated: return JsonResponse({"username": request.user.username, "name": request.user.first_name, "is_password_usable": is_password_usable(request.user.password)}, safe=False) return JsonResponse({"username": ""}, safe=False)
def verify_password(self, password): if is_password_usable(self.password_hash): return check_password(password, self.password_hash)
def test_bad_encoded(self): self.assertFalse(is_password_usable('lètmein_badencoded')) self.assertFalse(is_password_usable(''))
def test_is_password_usable(self): passwords = ("lètmein_badencoded", "", None) for password in passwords: with self.subTest(password=password): self.assertIs(is_password_usable(password), True)
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)
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))
def transform_password(self, request): if 'password' in request.data: password = request.data['password'] if not is_password_usable(password): request.data['password'] = make_password(password)
def save(self, *args, **kwargs): if not is_password_usable(self.password): self.set_password(self.password) return super(BaseUser, self).save(*args, **kwargs)
def test_bcrypt(self): encoded = make_password('letmein', hasher='bcrypt') self.assertTrue(is_password_usable(encoded)) self.assertTrue(encoded.startswith('bcrypt$')) self.assertTrue(check_password(u'letmein', encoded)) self.assertFalse(check_password('letmeinz', encoded))
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. """ 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" has_identify_hasher = False from passlib.ext.django.utils import hasher_to_passlib_name, passlib_to_hasher_name from django.contrib.auth.hashers import check_password, make_password, is_password_usable if patched or DJANGO_VERSION >= (1,5): # identify_hasher() # django 1.4 -- not present # django 1.5 -- present (added in django ticket 18184) # passlib integration -- present even under 1.4 from django.contrib.auth.hashers import identify_hasher has_identify_hasher = True #======================================================= # 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.assertIs(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 #======================================================= if DJANGO_VERSION < (1,6): # NOTE: django 1.4-1.5 treat empty password as invalid # User.set_password() should set unusable flag user = FakeUser() user.set_password('') self.assert_unusable_password(user) # User.check_password() should never return True user = FakeUser() user.password = hash = ctx.encrypt("") self.assertFalse(user.check_password("")) self.assert_valid_password(user, hash) # make_password() should reject empty passwords self.assertEqual(make_password(""), "!") # check_password() should never return True self.assertFalse(check_password("", hash)) else: # 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 if DJANGO_VERSION >= (1,6): self.assertTrue(make_password(None).startswith("!")) else: self.assertEqual(make_password(None), "!") # 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)) if has_identify_hasher: self.assertRaises(ValueError, identify_hasher, user.password) #======================================================= # hash=None #======================================================= # User.set_password() - n/a # User.check_password() - returns False 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 if has_identify_hasher: 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() # empty # ----- # django 1.4 -- blank threw error (fixed in 1.5) # django 1.5 -- blank hash returns False # # invalid # ------- # django 1.4 -- invalid hash threw error (fixed in 1.5) # django 1.5 -- invalid hash returns False user = FakeUser() user.password = hash if DJANGO_VERSION >= (1,5): # returns False for hash self.assertFalse(user.check_password(PASS1)) else: # throws error for hash self.assertRaises(ValueError, 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() # django 1.4 -- invalid/empty usable (fixed in 1.5) # django 1.5 -- invalid/empty no longer usable if DJANGO_VERSION < (1,5): self.assertTrue(user.has_usable_password()) else: self.assertFalse(user.has_usable_password()) # make_password() - n/a # check_password() # django 1.4 -- invalid/empty hash threw error (fixed in 1.5) # django 1.5 -- invalid/empty hash now returns False if DJANGO_VERSION < (1,5): self.assertRaises(ValueError, check_password, PASS1, hash) else: self.assertFalse(check_password(PASS1, hash)) # identify_hasher() - throws error if has_identify_hasher: 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(): #------------------------------------------------------- # setup constants & imports, pick a sample secret/hash combo #------------------------------------------------------- handler = ctx.handler(scheme) deprecated = ctx._is_deprecated_scheme(scheme) assert not deprecated or scheme != ctx.default_scheme() try: testcase = get_handler_case(scheme) except exc.MissingBackendError: assert scheme == "bcrypt" continue assert testcase.handler is handler if testcase.is_disabled_handler: continue if not has_active_backend(handler): # TODO: move this above get_handler_case(), # and omit MissingBackendError check. assert scheme in ["django_bcrypt", "django_bcrypt_sha256"], "%r scheme should always have active backend" % scheme continue try: secret, hash = sample_hashes[scheme] except KeyError: while True: secret, hash = testcase('setUp').get_sample_hash() if secret: # don't select blank passwords, especially under django 1.4/1.5 break other = 'dontletmein' # User.set_password() - n/a #------------------------------------------------------- # 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 #------------------------------------------------------- hash2 = make_password(secret, hasher=passlib_to_hasher_name(scheme)) 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 (django 1.4 feature we don't support) ##self.assertTrue(check_password(secret, hash, setter=setter, preferred='fooey')) ##self.assertEqual(setter.popstate(), [secret]) # TODO: get_hasher() #------------------------------------------------------- # identify_hasher() recognizes known hash #------------------------------------------------------- if has_identify_hasher: self.assertTrue(is_password_usable(hash)) name = hasher_to_passlib_name(identify_hasher(hash).algorithm) self.assertEqual(name, scheme)
def test_bytes(self): encoded = make_password(b"bytes_password") self.assertTrue(encoded.startswith("pbkdf2_sha256$")) self.assertIs(is_password_usable(encoded), True) self.assertIs(check_password(b"bytes_password", encoded), True)
def handle(self, username, email, is_remove, is_staff, is_superuser, groups, unusable_password, initial_password_hash, *args, **options): if is_remove: return self._handle_remove(username, email) old_groups, new_groups = set(), set() user, created = get_user_model().objects.get_or_create( username=username, defaults={'email': email}) if created: if initial_password_hash: if not is_password_usable(initial_password_hash): raise CommandError( 'The password hash provided for user {} is invalid.'. format(username)) user.password = initial_password_hash else: # Set the password to a random, unknown, but usable password # allowing self-service password resetting. Cases where unusable # passwords are required, should be explicit, and will be handled below. user.set_password(generate_password(length=25)) self.stderr.write(_('Created new user: "******"').format(user)) else: # NOTE, we will not update the email address of an existing user. self.stderr.write(_('Found existing user: "******"').format(user)) self._check_email_match(user, email) old_groups = set(user.groups.all()) self._maybe_update(user, 'is_staff', is_staff) self._maybe_update(user, 'is_superuser', is_superuser) # Set unusable password if specified if unusable_password and user.has_usable_password(): self.stderr.write( _('Setting unusable password for user "{}"').format(user)) user.set_unusable_password() # Ensure the user has a profile try: __ = user.profile except UserProfile.DoesNotExist: UserProfile.objects.create(user=user) self.stderr.write( _('Created new profile for user: "******"').format(user)) # resolve the specified groups for group_name in groups or set(): try: group = Group.objects.get(name=group_name) # pylint: disable=no-member new_groups.add(group) except Group.DoesNotExist: # warn, but move on. self.stderr.write( _('Could not find a group named "{}" - skipping.').format( group_name)) add_groups = new_groups - old_groups remove_groups = old_groups - new_groups self.stderr.write( _('Adding user "{username}" to groups {group_names}').format( username=user.username, group_names=[g.name for g in add_groups])) self.stderr.write( _('Removing user "{username}" from groups {group_names}').format( username=user.username, group_names=[g.name for g in remove_groups])) user.groups.set(new_groups) user.save()
def has_usable_password(self): """ Return False if set_unusable_password() has been called for this user. """ return is_password_usable(self.password)
def test_bytes(self): encoded = make_password(b'bytes_password') self.assertTrue(encoded.startswith('pbkdf2_sha256$')) self.assertIs(is_password_usable(encoded), True) self.assertIs(check_password(b'bytes_password', encoded), True)