def test_accounts_password_reuse(self): """ Assert against the password reuse policy """ user = self._user_factory_with_history() staff = self._user_factory_with_history(is_staff=True) # students need to user at least one different passwords before reuse self.assertFalse( PasswordHistory.is_allowable_password_reuse(user, "test")) self.assertTrue( PasswordHistory.is_allowable_password_reuse(user, "different")) self._change_password(user, "different") self.assertTrue( PasswordHistory.is_allowable_password_reuse(user, "test")) # staff needs to use at least two different passwords before reuse self.assertFalse( PasswordHistory.is_allowable_password_reuse(staff, "test")) self.assertTrue( PasswordHistory.is_allowable_password_reuse(staff, "different")) self._change_password(staff, "different") self.assertFalse( PasswordHistory.is_allowable_password_reuse(staff, "test")) self.assertFalse( PasswordHistory.is_allowable_password_reuse(staff, "different")) self.assertTrue( PasswordHistory.is_allowable_password_reuse(staff, "third")) self._change_password(staff, "third") self.assertTrue( PasswordHistory.is_allowable_password_reuse(staff, "test"))
def test_pbkdf2_sha256_password_reuse(self): """ Assert against the password reuse policy but using the normal Django PBKDF2 """ user = self._user_factory_with_history() staff = self._user_factory_with_history(is_staff=True) # students need to user at least one different passwords before reuse self.assertFalse(PasswordHistory.is_allowable_password_reuse(user, "test")) self.assertTrue(PasswordHistory.is_allowable_password_reuse(user, "different")) self._change_password(user, "different") self.assertTrue(PasswordHistory.is_allowable_password_reuse(user, "test")) # staff needs to use at least two different passwords before reuse self.assertFalse(PasswordHistory.is_allowable_password_reuse(staff, "test")) self.assertTrue(PasswordHistory.is_allowable_password_reuse(staff, "different")) self._change_password(staff, "different") self.assertFalse(PasswordHistory.is_allowable_password_reuse(staff, "test")) self.assertFalse(PasswordHistory.is_allowable_password_reuse(staff, "different")) self.assertTrue(PasswordHistory.is_allowable_password_reuse(staff, "third")) self._change_password(staff, "third") self.assertTrue(PasswordHistory.is_allowable_password_reuse(staff, "test"))
def test_disabled_feature(self): """ Test that behavior is normal when this feature is not turned on """ user = UserFactory() staff = AdminFactory() # if feature is disabled user can keep reusing same password self.assertTrue(PasswordHistory.is_allowable_password_reuse(user, "test")) self.assertTrue(PasswordHistory.is_allowable_password_reuse(staff, "test")) self.assertFalse(PasswordHistory.should_user_reset_password_now(user)) self.assertFalse(PasswordHistory.should_user_reset_password_now(staff))
def test_disabled_feature(self): """ Test that behavior is normal when this feature is not turned on """ user = UserFactory() staff = AdminFactory() # if feature is disabled user can keep reusing same password self.assertTrue(PasswordHistory.is_allowable_password_reuse(user, "test")) self.assertTrue(PasswordHistory.is_allowable_password_reuse(staff, "test")) self.assertFalse(PasswordHistory.should_user_reset_password_now(user)) self.assertFalse(PasswordHistory.should_user_reset_password_now(staff))
def _validate_password_security(password, user): """ Check password reuse and similar operational security policy considerations. """ # Check reuse if not PasswordHistory.is_allowable_password_reuse(user, password): if user.is_staff: num_distinct = settings.ADVANCED_SECURITY_CONFIG[ 'MIN_DIFFERENT_STAFF_PASSWORDS_BEFORE_REUSE'] else: num_distinct = settings.ADVANCED_SECURITY_CONFIG[ 'MIN_DIFFERENT_STUDENT_PASSWORDS_BEFORE_REUSE'] raise SecurityPolicyError( ungettext( "You are re-using a password that you have used recently. " "You must have {num} distinct password before reusing a previous password.", "You are re-using a password that you have used recently. " "You must have {num} distinct passwords before reusing a previous password.", num_distinct).format(num=num_distinct)) # Check reset frequency if PasswordHistory.is_password_reset_too_soon(user): num_days = settings.ADVANCED_SECURITY_CONFIG[ 'MIN_TIME_IN_DAYS_BETWEEN_ALLOWED_RESETS'] raise SecurityPolicyError( ungettext( "You are resetting passwords too frequently. Due to security policies, " "{num} day must elapse between password resets.", "You are resetting passwords too frequently. Due to security policies, " "{num} days must elapse between password resets.", num_days).format(num=num_days))
def validate_password_security(password, user): """ Check password reuse and similar operational security policy considerations. """ # Check reuse if not PasswordHistory.is_allowable_password_reuse(user, password): if user.is_staff: num_distinct = settings.ADVANCED_SECURITY_CONFIG['MIN_DIFFERENT_STAFF_PASSWORDS_BEFORE_REUSE'] else: num_distinct = settings.ADVANCED_SECURITY_CONFIG['MIN_DIFFERENT_STUDENT_PASSWORDS_BEFORE_REUSE'] raise SecurityPolicyError(ungettext( "You are re-using a password that you have used recently. " "You must have {num} distinct password before reusing a previous password.", "You are re-using a password that you have used recently. " "You must have {num} distinct passwords before reusing a previous password.", num_distinct ).format(num=num_distinct)) # Check reset frequency if PasswordHistory.is_password_reset_too_soon(user): num_days = settings.ADVANCED_SECURITY_CONFIG['MIN_TIME_IN_DAYS_BETWEEN_ALLOWED_RESETS'] raise SecurityPolicyError(ungettext( "You are resetting passwords too frequently. Due to security policies, " "{num} day must elapse between password resets.", "You are resetting passwords too frequently. Due to security policies, " "{num} days must elapse between password resets.", num_days ).format(num=num_days))