def test_expiry(self): req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertTrue(form.is_valid()) # Simulate user didn't log in for a long time period = datetime.timedelta(days=dap_settings.INACTIVE_USERS_EXPIRY) expire_at = timezone.now() - period self.user.last_login = expire_at self.user.save() LoginAttempt.objects.all().update(timestamp=expire_at) # Login attempt disabled user req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertFalse(form.is_valid()) self.assertEqual(form.non_field_errors(), [ form.error_messages['inactive']]) # Check log messages self.assertEqual(self.logger.handlers[0].stream.getvalue(), ( u'INFO Authentication attempt, username=rf, address=127.0.0.1\n' u'INFO Authentication success, username=rf, address=127.0.0.1\n' u'INFO Authentication attempt, username=rf, address=127.0.0.1\n' u'WARNING User rf disabled because last login was at %s\n' u'WARNING Authentication failure, username=rf, address=127.0.0.1, ' u'user inactive.\n' % expire_at))
def test_lock_period(self): for x in xrange(0, dap_settings.FAILED_AUTH_USERNAME_MAX + 1): req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertFalse(form.is_valid()) # User locked out self.assertEqual(form.non_field_errors(), [ form.error_messages['username_locked_out']]) # Alter timestamps as if they happened longer ago period = datetime.timedelta( seconds=dap_settings.FAILED_AUTH_LOCKOUT_PERIOD) expire_at = timezone.now() - period LoginAttempt.objects.all().update(timestamp=expire_at) req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertTrue(form.is_valid()) # Successful login resets lock count locking_attempts = LoginAttempt.objects.filter(lockout=True) self.assertEqual(locking_attempts.count(), 0)
def test_lock_period(self): pol = AuthenticationLockedUsername() text = unicode(pol.validation_msg) for x in xrange(0, pol.max_failed + 1): req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertFalse(form.is_valid()) # User locked out self.assertEqual(form.non_field_errors(), [text]) # Alter timestamps as if they happened longer ago period = datetime.timedelta(seconds=pol.lockout_duration) expire_at = timezone.now() - period LoginAttempt.objects.all().update(timestamp=expire_at) req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertTrue(form.is_valid()) # Successful login resets lock count locking_attempts = LoginAttempt.objects.filter(lockout=True) self.assertEqual(locking_attempts.count(), 0)
def test_username_lockout(self): """ Test too many failed login attempts for one username """ pol = AuthenticationLockedUsername() text = str(pol.validation_msg) for x in xrange(0, pol.max_failed): self.assertFalse(self.lockout_policy.is_locked('rf')) req = self.factory.get(reverse('login')) req.META['REMOTE_ADDR'] = '10.0.0.%d' % (x + 1) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertEqual(form.non_field_errors(), [ form.error_messages['invalid_login'] % { 'username': form.username_field.verbose_name}] ) attempts = LoginAttempt.objects.filter(username=self.user.username, successful=False, lockout=True) self.assertEqual(attempts.count(), pol.max_failed) self.assertTrue(self.lockout_policy.is_locked('rf')) # Another failed authentication triggers lockout req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertEqual(form.non_field_errors(), [text]) self.assertEqual(attempts.count(), pol.max_failed + 1) # Even valid authentication will no longer work now req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertFalse(form.is_valid()) self.assertEqual(self.logger.handlers[0].stream.getvalue(), ( u'INFO Authentication attempt, username=rf, address=10.0.0.1\n' u'INFO Authentication failure, username=rf, address=10.0.0.1, ' u'invalid authentication.\n' u'INFO Authentication attempt, username=rf, address=10.0.0.2\n' u'INFO Authentication failure, username=rf, address=10.0.0.2, ' u'invalid authentication.\n' u'INFO Authentication attempt, username=rf, address=10.0.0.3\n' u'INFO Authentication failure, username=rf, address=10.0.0.3, ' u'invalid authentication.\n' u'INFO Authentication attempt, username=rf, address=127.0.0.1\n' u'INFO Authentication failure, username=rf, address=127.0.0.1, ' u'username locked\n' u'INFO Authentication attempt, username=rf, address=127.0.0.1\n' u'INFO Authentication failure, username=rf, address=127.0.0.1, ' u'username locked\n'))
def test_backend_locked_username(self): # Authentication works backend = StrictModelBackend() user = backend.authenticate(username='******', password='******') self.assertEqual(user, self.user) # Lock user for x in xrange(0, dap_settings.FAILED_AUTH_USERNAME_MAX + 1): req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertFalse(form.is_valid()) # Authentication must no longer work for this user user = backend.authenticate(username='******', password='******') self.assertEqual(user, None)
def test_inactive_user(self): self.user.is_active = False self.user.save() # Valid authentication data, but user is inactive req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertFalse(form.is_valid()) self.assertEqual(form.non_field_errors(), [ form.error_messages['inactive']]) self.assertEqual(self.logger.handlers[0].stream.getvalue(), ( u'INFO Authentication attempt, username=rf, address=127.0.0.1\n' u'WARNING Authentication failure, username=rf, address=127.0.0.1, ' u'user inactive.\n'))
def test_address_lockout(self): """ Test too many failed login attempts for one address """ addr = '1.2.3.4' for x in xrange(0, dap_settings.FAILED_AUTH_ADDRESS_MAX): req = self.factory.get(reverse('login')) req.META['REMOTE_ADDR'] = addr form = StrictAuthenticationForm(request=req, data={ 'username': '******' % x, 'password': '******'}) self.assertEqual(form.non_field_errors(), [ form.error_messages['invalid_login'] % { 'username': form.username_field.verbose_name}]) attempts = LoginAttempt.objects.filter(source_address=addr, successful=False, lockout=True) self.assertEqual(attempts.count(), dap_settings.FAILED_AUTH_ADDRESS_MAX) # Another failed authentication triggers lockout req = self.factory.get(reverse('login')) req.META['REMOTE_ADDR'] = addr form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertEqual(form.non_field_errors(), [ form.error_messages['address_locked_out']]) self.assertEqual(attempts.count(), dap_settings.FAILED_AUTH_ADDRESS_MAX + 1) self.assertEqual(self.logger.handlers[0].stream.getvalue(), ( u'INFO Authentication attempt, username=rf0, address=1.2.3.4\n' u'WARNING Authentication failure, username=rf0, address=1.2.3.4, ' u'invalid authentication.\n' u'INFO Authentication attempt, username=rf1, address=1.2.3.4\n' u'WARNING Authentication failure, username=rf1, address=1.2.3.4, ' u'invalid authentication.\n' u'INFO Authentication attempt, username=rf2, address=1.2.3.4\n' u'WARNING Authentication failure, username=rf2, address=1.2.3.4, ' u'invalid authentication.\n' u'INFO Authentication attempt, username=rf, address=1.2.3.4\n' u'WARNING Authentication failure, username=rf, address=1.2.3.4, ' u'address locked\n'))
def test_lock_period(self): for x in xrange(0, dap_settings.FAILED_AUTH_USERNAME_MAX + 1): req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******' }) self.assertFalse(form.is_valid()) # User locked out self.assertEqual(form.non_field_errors(), [form.error_messages['username_locked_out']]) # Alter timestamps as if they happened longer ago period = datetime.timedelta( seconds=dap_settings.FAILED_AUTH_LOCKOUT_PERIOD) expire_at = timezone.now() - period LoginAttempt.objects.all().update(timestamp=expire_at) req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******' }) self.assertTrue(form.is_valid()) # Successful login resets lock count locking_attempts = LoginAttempt.objects.filter(lockout=True) self.assertEqual(locking_attempts.count(), 0)
def test_lock_period(self): pol = AuthenticationLockedUsername() text = unicode(pol.validation_msg) for x in xrange(0, pol.max_failed + 1): req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******' }) self.assertFalse(form.is_valid()) # User locked out self.assertEqual(form.non_field_errors(), [text]) # Alter timestamps as if they happened longer ago period = datetime.timedelta(seconds=pol.lockout_duration) expire_at = timezone.now() - period LoginAttempt.objects.all().update(timestamp=expire_at) req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******' }) self.assertTrue(form.is_valid()) # Successful login resets lock count locking_attempts = LoginAttempt.objects.filter(lockout=True) self.assertEqual(locking_attempts.count(), 0)
def test_expiry(self): pol = AuthenticationDisableExpiredUsers() req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertTrue(form.is_valid()) # Simulate user didn't log in for a long time period = datetime.timedelta(days=pol.inactive_period) expire_at = timezone.now() - period self.user.last_login = expire_at self.user.save() LoginAttempt.objects.all().update(timestamp=expire_at) # Login attempt disabled user req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertFalse(form.is_valid()) self.assertEqual(form.non_field_errors(), [ form.error_messages['invalid_login'] % { 'username': form.username_field.verbose_name }] ) # Check log messages self.assertEqual(self.logger.handlers[0].stream.getvalue(), ( u'INFO Authentication attempt, username=rf, address=127.0.0.1\n' u'INFO Authentication success, username=rf, address=127.0.0.1\n' u'INFO Authentication attempt, username=rf, address=127.0.0.1\n' u'INFO User rf disabled because last login was at %s\n' u'INFO Authentication failure, username=rf, address=127.0.0.1, ' u'user inactive.\n' % expire_at))
def test_unlock(self): """ Resetting lockout data unlocks user """ for x in xrange(0, dap_settings.FAILED_AUTH_USERNAME_MAX + 1): req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******' }) self.assertFalse(form.is_valid()) # User locked out self.assertEqual(form.non_field_errors(), [form.error_messages['username_locked_out']]) # Unlock user or address LoginAttempt.objects.all().update(lockout=False) req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******' }) self.assertTrue(form.is_valid())
def test_unlock(self): """ Resetting lockout data unlocks user """ pol = AuthenticationLockedUsername() text = unicode(pol.validation_msg) for x in xrange(0, pol.max_failed + 1): req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******' }) self.assertFalse(form.is_valid()) # User locked out self.assertEqual(form.non_field_errors(), [text]) # Unlock user or address LoginAttempt.objects.all().update(lockout=False) req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******' }) self.assertTrue(form.is_valid())
def test_backend_locked_username(self): # Authentication works backend = StrictModelBackend() user = backend.authenticate(username='******', password='******') self.assertEqual(user, self.user) # Lock user for x in xrange(0, dap_settings.FAILED_AUTH_USERNAME_MAX + 1): req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******' }) self.assertFalse(form.is_valid()) # Authentication must no longer work for this user user = backend.authenticate(username='******', password='******') self.assertEqual(user, None)
def test_inactive_user(self): self.user.is_active = False self.user.save() # Valid authentication data, but user is inactive req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertFalse(form.is_valid()) self.assertEqual(form.non_field_errors(), [ form.error_messages['invalid_login'] % { 'username': form.username_field.verbose_name }] ) self.assertEqual(self.logger.handlers[0].stream.getvalue(), ( u'INFO Authentication attempt, username=rf, address=127.0.0.1\n' u'INFO Authentication failure, username=rf, address=127.0.0.1, ' u'user inactive.\n'))
def test_unlock(self): """ Resetting lockout data unlocks user """ for x in xrange(0, dap_settings.FAILED_AUTH_USERNAME_MAX + 1): req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertFalse(form.is_valid()) # User locked out self.assertEqual(form.non_field_errors(), [ form.error_messages['username_locked_out']]) # Unlock user or address LoginAttempt.objects.all().update(lockout=False) req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertTrue(form.is_valid())
def test_username_lockout(self): """ Test too many failed login attempts for one username """ pol = AuthenticationLockedUsername() text = unicode(pol.validation_msg) for x in xrange(0, pol.max_failed): self.assertFalse(self.lockout_policy.is_locked('rf')) req = self.factory.get(reverse('login')) req.META['REMOTE_ADDR'] = '10.0.0.%d' % (x + 1) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertEqual(form.non_field_errors(), [ form.error_messages['invalid_login'] % { 'username': form.username_field.verbose_name}] ) attempts = LoginAttempt.objects.filter(username=self.user.username, successful=False, lockout=True) self.assertEqual(attempts.count(), pol.max_failed) self.assertTrue(self.lockout_policy.is_locked('rf')) # Another failed authentication triggers lockout req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertEqual(form.non_field_errors(), [text]) self.assertEqual(attempts.count(), pol.max_failed + 1) # Even valid authentication will no longer work now req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertFalse(form.is_valid()) self.assertEqual(self.logger.handlers[0].stream.getvalue(), ( u'INFO Authentication attempt, username=rf, address=10.0.0.1\n' u'INFO Authentication failure, username=rf, address=10.0.0.1, ' u'invalid authentication.\n' u'INFO Authentication attempt, username=rf, address=10.0.0.2\n' u'INFO Authentication failure, username=rf, address=10.0.0.2, ' u'invalid authentication.\n' u'INFO Authentication attempt, username=rf, address=10.0.0.3\n' u'INFO Authentication failure, username=rf, address=10.0.0.3, ' u'invalid authentication.\n' u'INFO Authentication attempt, username=rf, address=127.0.0.1\n' u'INFO Authentication failure, username=rf, address=127.0.0.1, ' u'username locked\n' u'INFO Authentication attempt, username=rf, address=127.0.0.1\n' u'INFO Authentication failure, username=rf, address=127.0.0.1, ' u'username locked\n'))
def test_unlock(self): """ Resetting lockout data unlocks user """ pol = AuthenticationLockedUsername() text = unicode(pol.validation_msg) for x in xrange(0, pol.max_failed + 1): req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertFalse(form.is_valid()) # User locked out self.assertEqual(form.non_field_errors(), [text]) # Unlock user or address LoginAttempt.objects.all().update(lockout=False) req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertTrue(form.is_valid())
def test_address_lockout(self): """ Test too many failed login attempts for one address """ addr = '1.2.3.4' for x in xrange(0, dap_settings.FAILED_AUTH_ADDRESS_MAX): req = self.factory.get(reverse('login')) req.META['REMOTE_ADDR'] = addr form = StrictAuthenticationForm(request=req, data={ 'username': '******' % x, 'password': '******' }) self.assertEqual(form.non_field_errors(), [ form.error_messages['invalid_login'] % { 'username': form.username_field.verbose_name } ]) attempts = LoginAttempt.objects.filter(source_address=addr, successful=False, lockout=True) self.assertEqual(attempts.count(), dap_settings.FAILED_AUTH_ADDRESS_MAX) # Another failed authentication triggers lockout req = self.factory.get(reverse('login')) req.META['REMOTE_ADDR'] = addr form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******' }) self.assertEqual(form.non_field_errors(), [form.error_messages['address_locked_out']]) self.assertEqual(attempts.count(), dap_settings.FAILED_AUTH_ADDRESS_MAX + 1) self.assertEqual( self.logger.handlers[0].stream.getvalue(), (u'INFO Authentication attempt, username=rf0, address=1.2.3.4\n' u'WARNING Authentication failure, username=rf0, address=1.2.3.4, ' u'invalid authentication.\n' u'INFO Authentication attempt, username=rf1, address=1.2.3.4\n' u'WARNING Authentication failure, username=rf1, address=1.2.3.4, ' u'invalid authentication.\n' u'INFO Authentication attempt, username=rf2, address=1.2.3.4\n' u'WARNING Authentication failure, username=rf2, address=1.2.3.4, ' u'invalid authentication.\n' u'INFO Authentication attempt, username=rf, address=1.2.3.4\n' u'WARNING Authentication failure, username=rf, address=1.2.3.4, ' u'address locked\n'))
def test_username_lockout(self): """ Test too many failed login attempts for one username """ for x in xrange(0, dap_settings.FAILED_AUTH_USERNAME_MAX): req = self.factory.get(reverse('login')) req.META['REMOTE_ADDR'] = '10.0.0.%d' % (x + 1) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertEqual(form.non_field_errors(), [ form.error_messages['invalid_login'] % { 'username': form.username_field.verbose_name}]) attempts = LoginAttempt.objects.filter(username=self.user.username, successful=False, lockout=True) self.assertEqual(attempts.count(), dap_settings.FAILED_AUTH_USERNAME_MAX) # Another failed authentication triggers lockout req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertEqual(form.non_field_errors(), [ form.error_messages['username_locked_out']]) self.assertEqual(attempts.count(), dap_settings.FAILED_AUTH_USERNAME_MAX + 1) # Even valid authentication will no longer work now req = self.factory.get(reverse('login')) form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertFalse(form.is_valid()) self.assertEqual(self.logger.handlers[0].stream.getvalue(), ( u'INFO Authentication attempt, username=rf, address=10.0.0.1\n' u'WARNING Authentication failure, username=rf, address=10.0.0.1, ' u'invalid authentication.\n' u'INFO Authentication attempt, username=rf, address=10.0.0.2\n' u'WARNING Authentication failure, username=rf, address=10.0.0.2, ' u'invalid authentication.\n' u'INFO Authentication attempt, username=rf, address=10.0.0.3\n' u'WARNING Authentication failure, username=rf, address=10.0.0.3, ' u'invalid authentication.\n' u'INFO Authentication attempt, username=rf, address=127.0.0.1\n' u'WARNING Authentication failure, username=rf, address=127.0.0.1, ' u'username locked\n' u'INFO Authentication attempt, username=rf, address=127.0.0.1\n' u'WARNING Authentication failure, username=rf, address=127.0.0.1, ' u'username locked\n'))
def test_address_lockout(self): """ Test too many failed login attempts for one address """ pol = AuthenticationLockedRemoteAddress() text = str(pol.validation_msg) addr = '1.2.3.4' for x in range(0, pol.max_failed): req = self.factory.get(reverse('login')) req.META['REMOTE_ADDR'] = addr form = StrictAuthenticationForm(request=req, data={ 'username': '******' % x, 'password': '******'}) self.assertEqual(form.non_field_errors(), [ form.error_messages['invalid_login'] % { 'username': form.username_field.verbose_name}] ) attempts = LoginAttempt.objects.filter(source_address=addr, successful=False, lockout=True) self.assertEqual(attempts.count(), pol.max_failed) # Another failed authentication triggers lockout req = self.factory.get(reverse('login')) req.META['REMOTE_ADDR'] = addr form = StrictAuthenticationForm(request=req, data={ 'username': '******', 'password': '******'}) self.assertEqual(form.non_field_errors(), [text]) self.assertEqual(attempts.count(), pol.max_failed + 1) self.assertEqual(self.logger.handlers[0].stream.getvalue(), ( 'INFO Authentication attempt, username=rf0, address=1.2.3.4\n' 'INFO Authentication failure, username=rf0, address=1.2.3.4, ' 'invalid authentication.\n' 'INFO Authentication attempt, username=rf1, address=1.2.3.4\n' 'INFO Authentication failure, username=rf1, address=1.2.3.4, ' 'invalid authentication.\n' 'INFO Authentication attempt, username=rf2, address=1.2.3.4\n' 'INFO Authentication failure, username=rf2, address=1.2.3.4, ' 'invalid authentication.\n' 'INFO Authentication attempt, username=rf, address=1.2.3.4\n' 'INFO Authentication failure, username=rf, address=1.2.3.4, ' 'address locked\n'))