mirror of
https://github.com/jazzband/django-axes.git
synced 2026-03-16 22:30:23 +00:00
Fixed a problem with what seems to be several levels of recursion causing many AccessAttempt objects to be created even though only one failed login attempt took place (for example). It seems to be working anyway...
--HG-- extra : convert_revision : svn%3A6515f4ec-ab5a-11dd-8fd9-859366ca643a/trunk%403
This commit is contained in:
parent
404f02b85c
commit
8dd2141605
2 changed files with 64 additions and 8 deletions
|
|
@ -1,4 +1,30 @@
|
|||
VERSION = (0, 1, 0, 'pre')
|
||||
VERSION = (0, 1, 1, 'alpha')
|
||||
|
||||
def get_version():
|
||||
return '%s.%s.%s-%s' % VERSION
|
||||
return '%s.%s.%s-%s' % VERSION
|
||||
|
||||
try:
|
||||
from django.conf import settings
|
||||
import logging, os
|
||||
|
||||
LOGFILE = os.path.join(settings.DIRNAME, 'axes.log')
|
||||
logging.basicConfig(level=logging.DEBUG,
|
||||
format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
|
||||
datefmt='%a, %d %b %Y %H:%M:%S',
|
||||
filename=LOGFILE,
|
||||
filemode='w')
|
||||
|
||||
fileLog = logging.FileHandler(LOGFILE, 'w')
|
||||
fileLog.setLevel(logging.DEBUG)
|
||||
|
||||
# set a format which is simpler for console use
|
||||
formatter = logging.Formatter('%(asctime)s %(name)-12s: %(levelname)-8s %(message)s')
|
||||
|
||||
# tell the handler to use this format
|
||||
fileLog.setFormatter(formatter)
|
||||
|
||||
# add the handler to the root logger
|
||||
logging.getLogger('').addHandler(fileLog)
|
||||
except:
|
||||
# if we have any problems, we most likely don't have a settings module loaded
|
||||
pass
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
from axes.models import AccessAttempt
|
||||
from django.conf import settings
|
||||
from axes.models import AccessAttempt
|
||||
import axes
|
||||
import logging
|
||||
|
||||
# see if the user has overridden the failure limit
|
||||
if hasattr(settings, 'LOGIN_FAILURE_LIMIT'):
|
||||
|
|
@ -16,21 +18,38 @@ else:
|
|||
def query2str(items):
|
||||
return '\n'.join(['%s=%s' % (k, v) for k,v in items])
|
||||
|
||||
log = logging.getLogger('axes.watch_login')
|
||||
log.info('BEGIN LOG')
|
||||
log.info('Using django-axes ' + axes.get_version())
|
||||
|
||||
def watch_login(func, failures):
|
||||
"""
|
||||
Used to decorate the django.contrib.admin.site.login method.
|
||||
"""
|
||||
|
||||
def new(*args, **kwargs):
|
||||
request = args[0]
|
||||
def decorated_login(request, *args, **kwargs):
|
||||
# share some useful information
|
||||
if func.__name__ != 'decorated_login':
|
||||
log.info('Calling decorated function: %s' % func)
|
||||
if args: log.info('args: %s' % args)
|
||||
if kwargs: log.info('kwargs: %s' % kwargs)
|
||||
|
||||
# call the login function
|
||||
response = func(*args, **kwargs)
|
||||
response = func(request, *args, **kwargs)
|
||||
|
||||
if func.__name__ == 'decorated_login':
|
||||
# if we're dealing with this function itself, don't bother checking
|
||||
# for invalid login attempts. I suppose there's a bunch of
|
||||
# recursion going on here that used to cause one failed login
|
||||
# attempt to generate 10+ failed access attempt records (with 3
|
||||
# failed attempts each supposedly)
|
||||
return response
|
||||
|
||||
# only check when there's been an HTTP POST
|
||||
if request.method == 'POST':
|
||||
# see if the login was successful
|
||||
if not response.has_header('location') and response.status_code != 302:
|
||||
if response and not response.has_header('location') and response.status_code != 302:
|
||||
log.debug('Failure dict (begin): %s' % failures)
|
||||
ip = request.META.get('REMOTE_ADDR', '')
|
||||
ua = request.META.get('HTTP_USER_AGENT', '<unknown>')
|
||||
|
||||
|
|
@ -39,15 +58,23 @@ def watch_login(func, failures):
|
|||
# make sure we have an item for this key
|
||||
try:
|
||||
failures[key]
|
||||
log.debug('Key %s exists' % key)
|
||||
except KeyError:
|
||||
log.debug('Creating key %s' % key)
|
||||
failures[key] = 0
|
||||
|
||||
# add a failed attempt for this user
|
||||
failures[key] += 1
|
||||
|
||||
log.info('Adding a failure for %s; %i failure(s)' % (key, failures[key]))
|
||||
#log.debug('Request: %s' % request)
|
||||
|
||||
# if we reach or surpass the failure limit, create an
|
||||
# AccessAttempt record
|
||||
if failures[key] >= FAILURE_LIMIT:
|
||||
log.info('=================================')
|
||||
log.info('Creating access attempt record...')
|
||||
log.info('=================================')
|
||||
attempt = AccessAttempt.objects.create(
|
||||
user_agent=ua,
|
||||
ip_address=ip,
|
||||
|
|
@ -61,5 +88,8 @@ def watch_login(func, failures):
|
|||
if FAILURE_RESET:
|
||||
del(failures[key])
|
||||
|
||||
log.debug('Failure dict (end): %s' % failures)
|
||||
log.info('-' * 79)
|
||||
|
||||
return response
|
||||
return new
|
||||
return decorated_login
|
||||
Loading…
Reference in a new issue