mirror of
https://github.com/jazzband/django-axes.git
synced 2026-03-16 22:30:23 +00:00
The old architecture used exceptions in the signal handler which prevented transactions from running smoothly and signal handlers from running after Axes handlers. The new architecture changes the request approach to request flagging and moves the exception handling into the middleware call method. This allows users to more flexibly run their own signal handlers and optionally use the Axes middleware if they want to do so. Fixes #440 Fixes #442
97 lines
3.4 KiB
Python
97 lines
3.4 KiB
Python
from logging import getLogger
|
|
|
|
from django.utils.module_loading import import_string
|
|
from django.utils.timezone import now
|
|
|
|
from axes.conf import settings
|
|
from axes.handlers.base import AxesHandler
|
|
from axes.helpers import (
|
|
get_client_ip_address,
|
|
get_client_user_agent,
|
|
get_client_path_info,
|
|
get_client_http_accept,
|
|
toggleable,
|
|
)
|
|
|
|
log = getLogger(settings.AXES_LOGGER)
|
|
|
|
|
|
class AxesProxyHandler(AxesHandler):
|
|
"""
|
|
Proxy interface for configurable Axes signal handler class.
|
|
|
|
If you wish to implement a custom version of this handler,
|
|
you can override the settings.AXES_HANDLER configuration string
|
|
with a class that implements a compatible interface and methods.
|
|
|
|
Defaults to using axes.handlers.proxy.AxesProxyHandler if not overridden.
|
|
Refer to axes.handlers.proxy.AxesProxyHandler for default implementation.
|
|
"""
|
|
|
|
implementation = None # type: AxesHandler
|
|
|
|
@classmethod
|
|
def get_implementation(cls, force: bool = False) -> AxesHandler:
|
|
"""
|
|
Fetch and initialize configured handler implementation and memoize it to avoid reinitialization.
|
|
|
|
This method is re-entrant and can be called multiple times from e.g. Django application loader.
|
|
"""
|
|
|
|
if force or not cls.implementation:
|
|
cls.implementation = import_string(settings.AXES_HANDLER)()
|
|
return cls.implementation
|
|
|
|
@staticmethod
|
|
def update_request(request):
|
|
"""
|
|
Update request attributes before passing them into the selected handler class.
|
|
"""
|
|
|
|
if request is None:
|
|
log.error('AXES: AxesProxyHandler.update_request can not set request attributes to a None request')
|
|
return
|
|
|
|
request.axes_locked_out = False
|
|
request.axes_attempt_time = now()
|
|
request.axes_ip_address = get_client_ip_address(request)
|
|
request.axes_user_agent = get_client_user_agent(request)
|
|
request.axes_path_info = get_client_path_info(request)
|
|
request.axes_http_accept = get_client_http_accept(request)
|
|
|
|
@classmethod
|
|
def is_locked(cls, request, credentials: dict = None) -> bool:
|
|
cls.update_request(request)
|
|
return cls.get_implementation().is_locked(request, credentials)
|
|
|
|
@classmethod
|
|
def is_allowed(cls, request, credentials: dict = None) -> bool:
|
|
cls.update_request(request)
|
|
return cls.get_implementation().is_allowed(request, credentials)
|
|
|
|
@classmethod
|
|
@toggleable
|
|
def user_login_failed(cls, sender, credentials: dict, request=None, **kwargs):
|
|
cls.update_request(request)
|
|
return cls.get_implementation().user_login_failed(sender, credentials, request, **kwargs)
|
|
|
|
@classmethod
|
|
@toggleable
|
|
def user_logged_in(cls, sender, request, user, **kwargs):
|
|
cls.update_request(request)
|
|
return cls.get_implementation().user_logged_in(sender, request, user, **kwargs)
|
|
|
|
@classmethod
|
|
@toggleable
|
|
def user_logged_out(cls, sender, request, user, **kwargs):
|
|
cls.update_request(request)
|
|
return cls.get_implementation().user_logged_out(sender, request, user, **kwargs)
|
|
|
|
@classmethod
|
|
@toggleable
|
|
def post_save_access_attempt(cls, instance, **kwargs):
|
|
return cls.get_implementation().post_save_access_attempt(instance, **kwargs)
|
|
|
|
@classmethod
|
|
def post_delete_access_attempt(cls, instance, **kwargs):
|
|
return cls.get_implementation().post_delete_access_attempt(instance, **kwargs)
|