mirror of
https://github.com/jazzband/django-defender.git
synced 2026-03-16 22:10:32 +00:00
fixed unit tests
This commit is contained in:
parent
6786499ba1
commit
2ee602b9dd
4 changed files with 29 additions and 35 deletions
|
|
@ -1,7 +1,7 @@
|
|||
import logging
|
||||
import socket
|
||||
|
||||
from redis import StrictRedis
|
||||
import redis
|
||||
from django.conf import settings
|
||||
from django.http import HttpResponse
|
||||
from django.http import HttpResponseRedirect
|
||||
|
|
@ -50,7 +50,7 @@ VERBOSE = getattr(settings, 'DEFENDER_VERBOSE', True)
|
|||
ERROR_MESSAGE = ugettext_lazy("Please enter a correct username and password. "
|
||||
"Note that both fields are case-sensitive.")
|
||||
|
||||
redis_server = StrictRedis(
|
||||
redis_server = redis.StrictRedis(
|
||||
host=REDIS_HOST, port=REDIS_PORT, db=REDIS_DB, password=REDIS_PASSWORD)
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
|
@ -175,13 +175,13 @@ def get_user_attempts(request):
|
|||
def block_ip(ip):
|
||||
""" given the ip, block it"""
|
||||
key = get_ip_blocked_cache_key(ip)
|
||||
redis_server.set(key, COOLOFF_TIME)
|
||||
redis_server.set(key, 'blocked', COOLOFF_TIME)
|
||||
|
||||
|
||||
def block_username(username):
|
||||
""" given the username block it. """
|
||||
key = get_username_blocked_cache_key(username)
|
||||
redis_server.set(key, COOLOFF_TIME)
|
||||
redis_server.set(key, 'blocked', COOLOFF_TIME)
|
||||
|
||||
|
||||
def record_failed_attempt(ip, username):
|
||||
|
|
@ -239,6 +239,7 @@ def is_already_locked(request):
|
|||
|
||||
# ip blocked?
|
||||
ip_blocked = redis_server.get(get_ip_blocked_cache_key(ip_address))
|
||||
|
||||
if not ip_blocked:
|
||||
ip_blocked = False
|
||||
|
||||
|
|
@ -261,7 +262,7 @@ def check_request(request, login_unsuccessful):
|
|||
result = record_failed_attempt(ip_address, username)
|
||||
else:
|
||||
# user logged in -- forget the failed attempts
|
||||
reset_failed_attempts(ip_address, username)
|
||||
reset_failed_attempts(ip=ip_address, username=username)
|
||||
|
||||
return result
|
||||
|
||||
|
|
|
|||
|
|
@ -29,5 +29,4 @@ class AccessAttempt(models.Model):
|
|||
)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
ordering = ['-attempt_time']
|
||||
|
|
|
|||
|
|
@ -40,6 +40,5 @@ SECRET_KEY = 'too-secret-for-test'
|
|||
|
||||
LOGIN_REDIRECT_URL = '/admin'
|
||||
|
||||
AXES_LOGIN_FAILURE_LIMIT = 10
|
||||
from datetime import timedelta
|
||||
AXES_COOLOFF_TIME = timedelta(seconds=2)
|
||||
DEFENDER_LOGIN_FAILURE_LIMIT = 10
|
||||
DEFENDER_COOLOFF_TIME = 2
|
||||
|
|
|
|||
|
|
@ -13,11 +13,12 @@ from defender.decorators import (
|
|||
COOLOFF_TIME, FAILURE_LIMIT, reset_failed_attempts)
|
||||
|
||||
|
||||
redis_client = mockredis.mock_strict_redis_client()
|
||||
|
||||
# Django >= 1.7 compatibility
|
||||
try:
|
||||
ADMIN_LOGIN_URL = reverse('admin:login')
|
||||
LOGIN_FORM_KEY = '<form action="/admin/login/" method="post" \
|
||||
id="login-form">'
|
||||
LOGIN_FORM_KEY = '<form action="/admin/" method="post" id="login-form">'
|
||||
except NoReverseMatch:
|
||||
ADMIN_LOGIN_URL = reverse('admin:index')
|
||||
LOGIN_FORM_KEY = 'this_is_the_login_form'
|
||||
|
|
@ -29,23 +30,13 @@ class AccessAttemptTest(TestCase):
|
|||
VALID_USERNAME = 'valid'
|
||||
LOCKED_MESSAGE = 'Account locked: too many login attempts.'
|
||||
|
||||
@patch('redis.StrictRedis', mockredis.mock_strict_redis_client)
|
||||
def the_test(self):
|
||||
from redis import StrictRedis
|
||||
print(StrictRedis)
|
||||
|
||||
def the_test2(self):
|
||||
from redis import StrictRedis
|
||||
dir(StrictRedis)
|
||||
print(StrictRedis)
|
||||
|
||||
def _get_random_str(self):
|
||||
""" Returns a random str """
|
||||
chars = string.ascii_uppercase + string.digits
|
||||
|
||||
return ''.join(random.choice(chars) for x in range(20))
|
||||
|
||||
@patch('redis.StrictRedis', mockredis.mock_strict_redis_client)
|
||||
@patch('defender.decorators.redis_server', redis_client)
|
||||
def _login(self, is_valid=False, user_agent='test-browser'):
|
||||
"""Login a user. A valid credential is used when is_valid is True,
|
||||
otherwise it will use a random string to make a failed login.
|
||||
|
|
@ -55,11 +46,12 @@ class AccessAttemptTest(TestCase):
|
|||
response = self.client.post(ADMIN_LOGIN_URL, {
|
||||
'username': username,
|
||||
'password': username,
|
||||
'this_is_the_login_form': 1,
|
||||
LOGIN_FORM_KEY: 1,
|
||||
}, HTTP_USER_AGENT=user_agent)
|
||||
|
||||
return response
|
||||
|
||||
@patch('defender.decorators.redis_server', redis_client)
|
||||
def setUp(self):
|
||||
"""Create a valid user for login
|
||||
"""
|
||||
|
|
@ -69,7 +61,11 @@ class AccessAttemptTest(TestCase):
|
|||
password=self.VALID_USERNAME,
|
||||
)
|
||||
|
||||
@patch('redis.StrictRedis', mockredis.mock_strict_redis_client)
|
||||
def tearDown(self):
|
||||
""" clean up the db """
|
||||
redis_client.flushdb()
|
||||
|
||||
@patch('defender.decorators.redis_server', redis_client)
|
||||
def test_failure_limit_once(self):
|
||||
"""Tests the login lock trying to login one more time
|
||||
than failure limit
|
||||
|
|
@ -84,7 +80,7 @@ class AccessAttemptTest(TestCase):
|
|||
response = self._login()
|
||||
self.assertContains(response, self.LOCKED_MESSAGE)
|
||||
|
||||
@patch('redis.StrictRedis', mockredis.mock_strict_redis_client)
|
||||
@patch('defender.decorators.redis_server', redis_client)
|
||||
def test_failure_limit_many(self):
|
||||
"""Tests the login lock trying to login a lot of times more
|
||||
than failure limit
|
||||
|
|
@ -101,34 +97,33 @@ class AccessAttemptTest(TestCase):
|
|||
response = self._login()
|
||||
self.assertContains(response, self.LOCKED_MESSAGE)
|
||||
|
||||
@patch('redis.StrictRedis', mockredis.mock_strict_redis_client)
|
||||
@patch('defender.decorators.redis_server', redis_client)
|
||||
def test_valid_login(self):
|
||||
"""Tests a valid login for a real username
|
||||
"""
|
||||
response = self._login(is_valid=True)
|
||||
self.assertNotContains(response, LOGIN_FORM_KEY, status_code=302)
|
||||
|
||||
@patch('redis.StrictRedis', mockredis.mock_strict_redis_client)
|
||||
@patch('defender.decorators.redis_server', redis_client)
|
||||
def test_cooling_off(self):
|
||||
"""Tests if the cooling time allows a user to login
|
||||
"""
|
||||
self.test_failure_limit_once()
|
||||
|
||||
# Wait for the cooling off period
|
||||
time.sleep(COOLOFF_TIME.total_seconds())
|
||||
|
||||
time.sleep(COOLOFF_TIME)
|
||||
# mock redis require that we expire on our own
|
||||
redis_client.do_expire()
|
||||
# It should be possible to login again, make sure it is.
|
||||
self.test_valid_login()
|
||||
|
||||
@patch('redis.StrictRedis', mockredis.mock_strict_redis_client)
|
||||
@patch('defender.decorators.redis_server', redis_client)
|
||||
def test_cooling_off_for_trusted_user(self):
|
||||
"""Test the cooling time for a trusted user
|
||||
"""
|
||||
|
||||
# Try the cooling off time
|
||||
self.test_cooling_off()
|
||||
|
||||
@patch('redis.StrictRedis', mockredis.mock_strict_redis_client)
|
||||
@patch('defender.decorators.redis_server', redis_client)
|
||||
def test_long_user_agent_valid(self):
|
||||
"""Tests if can handle a long user agent
|
||||
"""
|
||||
|
|
@ -136,7 +131,7 @@ class AccessAttemptTest(TestCase):
|
|||
response = self._login(is_valid=True, user_agent=long_user_agent)
|
||||
self.assertNotContains(response, LOGIN_FORM_KEY, status_code=302)
|
||||
|
||||
@patch('redis.StrictRedis', mockredis.mock_strict_redis_client)
|
||||
@patch('defender.decorators.redis_server', redis_client)
|
||||
def test_long_user_agent_not_valid(self):
|
||||
"""Tests if can handle a long user agent with failure
|
||||
"""
|
||||
|
|
@ -146,7 +141,7 @@ class AccessAttemptTest(TestCase):
|
|||
|
||||
self.assertContains(response, self.LOCKED_MESSAGE)
|
||||
|
||||
@patch('redis.StrictRedis', mockredis.mock_strict_redis_client)
|
||||
@patch('defender.decorators.redis_server', redis_client)
|
||||
def test_reset_ip(self):
|
||||
"""Tests if can reset an ip address
|
||||
"""
|
||||
|
|
|
|||
Loading…
Reference in a new issue