another different approach

This commit is contained in:
djmore4 2022-10-12 16:01:22 -04:00 committed by Ken Cochrane
parent be523281ab
commit 7121db4b0f
3 changed files with 17 additions and 43 deletions

View file

@ -58,4 +58,4 @@ def get_approx_account_lockouts_from_login_attempts(ip_address=None, username=No
# TODO: Maybe we should throw an exception here instead of returning 0?
return 0
return min(AccessAttempt.objects.filter(q).count() // failure_limit, len(config.LOCKOUT_COOLOFF_TIMES) - 1)
return AccessAttempt.objects.filter(q).count() // failure_limit

View file

@ -11,6 +11,7 @@ from django.test.client import RequestFactory
from redis.client import Redis
from django.urls import reverse
from . import data
from . import utils
from . import config
from .signals import (
@ -436,7 +437,7 @@ class AccessAttemptTest(DefenderTestCase):
self.assertTemplateUsed(response, "defender/lockout.html")
@patch("defender.config.COOLOFF_TIME", 0)
@patch("defender.config.LOCKOUT_COOLOFF_TIMES", 0)
@patch("defender.config.LOCKOUT_COOLOFF_TIMES", [0])
def test_failed_login_no_cooloff(self):
""" failed login no cooloff """
for i in range(0, config.FAILURE_LIMIT):
@ -958,62 +959,35 @@ class AccessAttemptTest(DefenderTestCase):
@patch("defender.config.LOCKOUT_COOLOFF_TIMES", [3, 6])
def test_lockout_cooloff_correctly_scales_with_ip_when_set(self):
self.test_ip_failure_limit()
time.sleep(config.LOCKOUT_COOLOFF_TIMES[0])
self.assertEqual(data.get_approx_account_lockouts_from_login_attempts(ip_address="127.0.0.1"), 1)
if config.MOCK_REDIS:
# mock redis require that we expire on our own
get_redis_connection().do_expire() # pragma: no cover
self.assertFalse(utils.is_source_ip_already_locked("127.0.0.1"))
self.test_ip_failure_limit()
time.sleep(config.LOCKOUT_COOLOFF_TIMES[0])
self.assertTrue(utils.is_source_ip_already_locked("127.0.0.1"))
utils.reset_failed_attempts(ip_address="127.0.0.1")
self.test_ip_failure_limit()
self.assertEqual(data.get_approx_account_lockouts_from_login_attempts(ip_address="127.0.0.1"), 2)
if config.MOCK_REDIS:
# mock redis require that we expire on our own
get_redis_connection().do_expire() # pragma: no cover
time.sleep(config.LOCKOUT_COOLOFF_TIMES[1])
self.test_valid_login()
@patch("defender.config.LOCKOUT_COOLOFF_TIMES", [3, 6])
def test_lockout_cooloff_correctly_scales_with_username_when_set(self):
self.test_username_failure_limit()
time.sleep(config.LOCKOUT_COOLOFF_TIMES[0])
self.assertEqual(data.get_approx_account_lockouts_from_login_attempts(username=VALID_USERNAME), 1)
if config.MOCK_REDIS:
# mock redis require that we expire on our own
get_redis_connection().do_expire() # pragma: no cover
self.assertFalse(utils.is_user_already_locked(VALID_USERNAME))
self.test_username_failure_limit()
time.sleep(config.LOCKOUT_COOLOFF_TIMES[0])
self.assertTrue(utils.is_user_already_locked(VALID_USERNAME))
utils.reset_failed_attempts(username=VALID_USERNAME)
@patch("defender.config.LOCKOUT_COOLOFF_TIMES", [3, 6])
def test_lockout_correctly_releases_after_scaling_with_ip(self):
self.test_ip_failure_limit()
time.sleep(config.LOCKOUT_COOLOFF_TIMES[0])
if config.MOCK_REDIS:
# mock redis require that we expire on our own
get_redis_connection().do_expire() # pragma: no cover
self.assertFalse(utils.is_source_ip_already_locked("127.0.0.1"))
self.test_ip_failure_limit()
time.sleep(config.LOCKOUT_COOLOFF_TIMES[1])
if config.MOCK_REDIS:
# mock redis require that we expire on our own
get_redis_connection().do_expire() # pragma: no cover
self.assertFalse(utils.is_source_ip_already_locked("127.0.0.1"))
utils.reset_failed_attempts(ip_address="127.0.0.1")
@patch("defender.config.LOCKOUT_COOLOFF_TIMES", [3, 6])
def test_lockout_correctly_releases_after_scaling_with_username(self):
self.test_username_failure_limit()
time.sleep(config.LOCKOUT_COOLOFF_TIMES[0])
self.assertEqual(data.get_approx_account_lockouts_from_login_attempts(username=VALID_USERNAME), 2)
if config.MOCK_REDIS:
# mock redis require that we expire on our own
get_redis_connection().do_expire() # pragma: no cover
self.assertFalse(utils.is_user_already_locked(VALID_USERNAME))
self.test_username_failure_limit()
time.sleep(config.LOCKOUT_COOLOFF_TIMES[1])
if config.MOCK_REDIS:
# mock redis require that we expire on our own
get_redis_connection().do_expire() # pragma: no cover
self.assertFalse(utils.is_user_already_locked(VALID_USERNAME))
utils.reset_failed_attempts(username=VALID_USERNAME)
self.test_valid_login()
class SignalTest(DefenderTestCase):

View file

@ -206,10 +206,10 @@ def get_user_attempts(request, get_username=get_username_from_request, username=
return max(ip_count, username_count)
def get_lockout_cooloff_time(ip_address=None, username=None):
index = min(
index = max(0, min(
len(config.LOCKOUT_COOLOFF_TIMES) - 1,
get_approx_account_lockouts_from_login_attempts(ip_address, username)
)
get_approx_account_lockouts_from_login_attempts(ip_address, username) - 1
))
return config.LOCKOUT_COOLOFF_TIMES[index]