forked from jazzband/django-axes
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbackends.py
62 lines (47 loc) · 2.74 KB
/
backends.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
from django.contrib.auth.backends import ModelBackend
from axes.exceptions import (
AxesBackendPermissionDenied,
AxesBackendRequestParameterRequired,
)
from axes.handlers.proxy import AxesProxyHandler
from axes.helpers import get_credentials, get_lockout_message, toggleable
class AxesBackend(ModelBackend):
"""
Authentication backend class that forbids login attempts for locked out users.
Use this class as the first item of ``AUTHENTICATION_BACKENDS`` to
prevent locked out users from being logged in by the Django authentication flow.
.. note:: This backend does not log your user in. It monitors login attempts.
Authentication is handled by the following backends that are configured in ``AUTHENTICATION_BACKENDS``.
"""
@toggleable
def authenticate(
self, request, username: str = None, password: str = None, **kwargs: dict
):
"""
Checks user lockout status and raises an exception if user is not allowed to log in.
This method interrupts the login flow and inserts error message directly to the
``response_context`` attribute that is supplied as a keyword argument.
:keyword response_context: kwarg that will be have its ``error`` attribute updated with context.
:raises AxesBackendRequestParameterRequired: if request parameter is not passed.
:raises AxesBackendPermissionDenied: if user is already locked out.
"""
if request is None:
raise AxesBackendRequestParameterRequired(
"AxesBackend requires a request as an argument to authenticate"
)
credentials = get_credentials(username=username, password=password, **kwargs)
if AxesProxyHandler.is_allowed(request, credentials):
return
# Locked out, don't try to authenticate, just update response_context and return.
# Its a bit weird to pass a context and expect a response value but its nice to get a "why" back.
error_msg = get_lockout_message()
response_context = kwargs.get("response_context", {})
response_context["error"] = error_msg
# Raise an error that stops the authentication flows at django.contrib.auth.authenticate.
# This error stops bubbling up at the authenticate call which catches backend PermissionDenied errors.
# After this error is caught by authenticate it emits a signal indicating user login failed,
# which is processed by axes.signals.log_user_login_failed which logs and flags the failed request.
# The axes.middleware.AxesMiddleware further processes the flagged request into a readable response.
raise AxesBackendPermissionDenied(
"AxesBackend detected that the given user is locked out"
)