Improve documentation

This commit is contained in:
Aleksi Häkli 2019-05-01 18:28:29 +03:00
parent fb2bd57c33
commit 0a90a7d075
No known key found for this signature in database
GPG key ID: 3E7146964D726BBE
14 changed files with 140 additions and 66 deletions

View file

@ -13,13 +13,13 @@ class AxesBackend(ModelBackend):
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 and delegates login to the
backends that are configured after it in the ``AUTHENTICATION_BACKENDS`` list.
.. 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``.
"""
def authenticate(self, request: AxesHttpRequest, username: str = None, password: str = None, **kwargs: dict):
"""
Checks user lockout status and raise a PermissionDenied if user is not allowed to log in.
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.
@ -57,4 +57,6 @@ class AxesBackend(ModelBackend):
class AxesModelBackend(AxesBackend):
"""
Backwards compatibility class for version 4 to version 5 migration.
See the ``AxesBackend`` class documentation and implementation.
"""

View file

@ -9,12 +9,14 @@ from axes.request import AxesHttpRequest
class AxesHandler: # pylint: disable=unused-argument
"""
Virtual handler API definition for subclassing handlers that can be used with the ``AxesProxyHandler``.
Handler API definition for implementations that are used by the ``AxesProxyHandler``.
If you wish to implement your own handler class just override the methods you wish to specialize
and define the class to be used with ``settings.AXES_HANDLER = 'path.to.YourClass'``.
If you wish to specialize your own handler class, override the necessary methods
and configure the class for use by setting ``settings.AXES_HANDLER = 'module.path.to.YourClass'``.
The default implementation that is actually used by Axes is the ``axes.handlers.database.AxesDatabaseHandler``.
The default implementation that is actually used by Axes is ``axes.handlers.database.AxesDatabaseHandler``.
.. note:: This is a virtual class and **can not be used without specialization**.
"""
def is_allowed(self, request: AxesHttpRequest, credentials: dict = None) -> bool:
@ -23,7 +25,7 @@ class AxesHandler: # pylint: disable=unused-argument
This method is abstract and other backends can specialize it as needed, but the default implementation
checks if the user has attempted to authenticate into the site too many times through the
Django authentication backends and returns ``False``if user exceeds the configured Axes thresholds.
Django authentication backends and returns ``False`` if user exceeds the configured Axes thresholds.
This checker can implement arbitrary checks such as IP whitelisting or blacklisting,
request frequency checking, failed attempt monitoring or similar functions.

View file

@ -16,16 +16,26 @@ from axes.request import AxesHttpRequest
class AxesMiddleware:
"""
Middleware that maps lockout signals into readable HTTP 403 Forbidden responses.
Middleware that calculates necessary HTTP request attributes for attempt monitoring
and maps lockout signals into readable HTTP 403 Forbidden responses.
Without this middleware the backend returns HTTP 403 errors with the
``django.views.defaults.permission_denied`` view that renders the ``403.html``
template from the root template directory if found.
This middleware uses the ``axes.helpers.get_lockout_response`` handler
for returning a context aware lockout message to the end user.
By default Django server returns ``PermissionDenied`` exceptions as HTTP 403 errors
with the ``django.views.defaults.permission_denied`` view that renders
the ``403.html`` template from the root template directory if found.
To customize the error rendering, you can subclass this middleware
This middleware recognizes the specialized attempt monitoring and lockout exceptions
and uses the ``axes.helpers.get_lockout_response`` handler for returning
customizable and context aware lockout message to the end user.
To customize the error handling behaviour further, you can subclass this middleware
and change the ``process_exception`` handler to your own liking.
Please see the following configuration flags before customizing this handler:
- ``AXES_LOCKOUT_TEMPLATE``,
- ``AXES_LOCKOUT_URL``,
- ``AXES_COOLOFF_MESSAGE``, and
- ``AXES_PERMALOCK_MESSAGE``.
"""
def __init__(self, get_response: Callable):
@ -37,9 +47,11 @@ class AxesMiddleware:
def update_request(self, request: HttpRequest):
"""
Update given Django ``HttpRequest`` with necessary attributes
before passing it on the ``get_response`` for further
Django middleware and view processing.
Construct an ``AxesHttpRequest`` from the given ``HttpRequest``
by updating the request with necessary attempt tracking attributes.
This method is called by the middleware class ``__call__`` method
when iterating over the middleware stack.
"""
request.axes_attempt_time = now()
@ -50,9 +62,11 @@ class AxesMiddleware:
def process_exception(self, request: AxesHttpRequest, exception): # pylint: disable=inconsistent-return-statements
"""
Exception handler that processes exceptions raised by the Axes signal handler when request fails with login.
Handle exceptions raised by the Axes signal handler class when requests fail checks.
Only ``axes.exceptions.AxesSignalPermissionDenied`` exception is handled by this middleware.
Note that only ``AxesSignalPermissionDenied`` is handled by this middleware class.
:return: Configured ``HttpResponse`` for failed authentication attempts and lockouts.
"""
if isinstance(exception, AxesSignalPermissionDenied):

View file

@ -5,7 +5,30 @@ from django.http import HttpRequest
class AxesHttpRequest(HttpRequest):
"""
Type definition for the HTTP request Axes uses.
Extended Django ``HttpRequest`` with custom Axes attributes.
This request is constructed by the ``AxesMiddleware`` class
where the custom attributes are inserted into the request.
.. note:: The ``str`` type variables have a maximum length of 255
characters and they are calculated in the middleware layer.
If the HTTP request attributes can not be resolved
they are assigned default value of ``<unknown>``.
:var axes_attempt_time: Timestamp of the request on the server side.
:vartype axes_attempt_time: datetime
:var axes_ip_address: Request IP address as resolved by django-axes and django-ipware configurations.
:vartype axes_ip_address: str
:var axes_user_agent: Request agent from ``request.META['HTTP_USER_AGENT']``.
:vartype axes_user_agent: str
:var axes_path_info: Request path from ``request.META['PATH_INFO']``.
:vartype axes_path_info: str
:var axes_http_accept: Request ``Accept`` header from ``request.META['HTTP_ACCEPT']``.
:vartype axes_http_accept: str
"""
axes_attempt_time: datetime

View file

@ -1,7 +1,7 @@
.. _requirements:
1. Requirements
===============
Requirements
============
Axes requires a supported Django version and runs on Python and PyPy versions 3.5 and above.

View file

@ -1,7 +1,7 @@
.. _installation:
2. Installation
===============
Installation
============
Axes is easy to install from the PyPI package::
@ -56,7 +56,7 @@ After installing the package, the project settings need to be configured.
Axes is now functional with the default settings and is saving user attempts
into your database and locking users out if they exceed the maximum attempts.
You should use the ``python manage.py check`` command to verify the correct configuration in both
You should use the ``python manage.py check`` command to verify the correct configuration in
development, staging, and production environments. It is probably best to use this step as part
of your regular CI workflows to verify that your project is not misconfigured.

View file

@ -1,7 +1,7 @@
.. _usage:
3. Usage
========
Usage
=====
Once Axes is is installed and configured, you can login and logout
of your application via the ``django.contrib.auth`` views.
@ -31,4 +31,4 @@ In your code, you can use the ``axes.utils.reset`` function.
Please note that if you give both ``username`` and ``ip`` arguments to ``reset``
that attempts that have both the set IP and username are reset.
The effective behaviour of ``reset`` is to ``and`` the terms instead of ``or``ing them.
The effective behaviour of ``reset`` is to ``and`` the terms instead of ``or`` ing them.

View file

@ -1,7 +1,7 @@
.. _configuration:
4. Configuration
================
Configuration
=============
Minimal Axes configuration is done with just ``settings.py`` updates.
@ -46,7 +46,7 @@ The following ``settings.py`` options are available for customizing Axes behavio
user is locked out. Template receives ``cooloff_time`` and ``failure_limit`` as
context variables. Default: ``None``
* ``AXES_LOCKOUT_URL``: If set, specifies a URL to redirect to on lockout. If
both AXES_LOCKOUT_TEMPLATE and AXES_LOCKOUT_URL are set, the template will
both ``AXES_LOCKOUT_TEMPLATE`` and ``AXES_LOCKOUT_URL`` are set, the template will
be used. Default: ``None``
* ``AXES_VERBOSE``: If ``True``, you'll see slightly more logging for Axes.
Default: ``True``
@ -100,10 +100,10 @@ following settings to suit your set up to correctly resolve client IP addresses:
Configuring handlers
--------------------
Axes uses and provides handlers for processing signals and events
Axes uses handlers for processing signals and events
from Django authentication and login attempts.
The following handlers are offered by default and can be configured
The following handlers are implemented by Axes and can be configured
with the ``AXES_HANDLER`` setting in project configuration:
- ``axes.handlers.database.AxesDatabaseHandler``
@ -126,6 +126,12 @@ with the ``AXES_HANDLER`` setting in project configuration:
and is meant to be used on e.g. local development setups
and testing deployments where login monitoring is not wanted.
To switch to cache based attempt tracking you can do the following::
AXES_HANDLER = 'axes.handlers.cache.AxesCacheHandler'
See the cache configuration section for suitable cache backends.
Configuring caches
------------------
@ -140,8 +146,10 @@ resets made in the command line might not remove lock-outs that are in a sepate
processes in-memory cache such as the web server serving your login or admin page.
To circumvent this problem, please use somethings else than
``django.core.cache.backends.locmem.LocMemCache`` as your
cache backend in Django cache ``BACKEND`` setting.
``django.core.cache.backends.dummy.DummyCache``,
``django.core.cache.backends.locmem.LocMemCache``, or
``django.core.cache.backends.filebased.FileBasedCache``
as your cache backend in Django cache ``BACKEND`` setting.
If changing the ``'default'`` cache is not an option, you can add a cache
specifically for use with Axes. This is a two step process. First you need to

View file

@ -1,9 +1,20 @@
.. customization:
5. Customization
================
Customization
=============
Axes can be customized and extended by using the correct signals.
Axes has multiple options for customization including customizing the
attempt tracking and lockout handling logic and lockout response formatting.
There are public APIs and the whole Axes tracking system is pluggable.
You can swap the authentication backend, attempt tracker, failure handlers,
database or cache backends and error formatters as you see fit.
Check the API reference section for further inspiration on
implementing custom authentication backends, middleware, and handlers.
Axes uses the stock Django signals for login monitoring and
can be customized and extended by using them correctly.
Axes listens to the following signals from ``django.contrib.auth.signals`` to log access attempts:
@ -15,6 +26,7 @@ You can also use Axes with your own auth module, but you'll need
to ensure that it sends the correct signals in order for Axes to
log the access attempts.
Customizing authentication views
--------------------------------
@ -140,4 +152,4 @@ into ``my_namespace-username``:
NOTE: You still have to make these modifications yourself before calling
authenticate. If you want to re-use the same function for consistency, that's
fine, but Axes does not inject these changes into the authentication flow
for you.
for you.

View file

@ -1,7 +1,7 @@
.. _integration:
6. Integration
==============
Integration
===========
Axes is intended to be pluggable and usable with 3rd party authentication solutions.
@ -9,7 +9,7 @@ This document describes the integration with some commonly used 3rd party packag
such as Django Allauth and Django REST Framework.
Integrating with Django Allauth
Integration with Django Allauth
-------------------------------
Axes relies on having login information stored under ``AXES_USERNAME_FORM_FIELD`` key
@ -64,7 +64,7 @@ You also need to decorate ``dispatch()`` and ``form_invalid()`` methods of the A
]
Integrating with Django REST Framework
Integration with Django REST Framework
--------------------------------------
Modern versions of Django REST Framework after 3.7.0 work normally with Axes.
@ -108,7 +108,7 @@ require the request object to be passed for authentication.
return (user, None)
Integrating with Django Simple Captcha
Integration with Django Simple Captcha
--------------------------------------
Axes supports Captcha with the Django Simple Captcha package in the following manner.

View file

@ -1,7 +1,7 @@
.. _architecture:
7. Architecture
================
Architecture
============
Axes is based on the existing Django authentication backend
architecture and framework for recognizing users and aims to be

View file

@ -1,17 +1,22 @@
.. _reference:
8. API reference
================
API reference
=============
Axes offers extendable APIs that you can customize to your liking.
You can specialize the following base classes or alternatively implement
your own classes based on top of the following base implementations.
Axes offers extensible APIs that you can customize to your liking.
You can specialize the following base classes or alternatively use
third party modules as long as they implement the following APIs.
.. automodule:: axes.handlers.base
:members:
.. automodule:: axes.backends
:members:
:show-inheritance:
.. automodule:: axes.middleware
:members:
.. automodule:: axes.handlers.base
.. automodule:: axes.request
:members:
:show-inheritance:

View file

@ -1,24 +1,27 @@
.. _development:
9. Development
==============
Development
===========
You can contribute to this project forking it from GitHub and sending pull requests.
First `fork <https://help.github.com/en/articles/fork-a-repo>`_ the
`repository <https://github.com/jazzband/django-axes>`_ and then clone it::
Setting up a development environment
------------------------------------
$ git clone git@github.com:<you>/django-axes.git
Fork and clone the repository, initialize a virtual environment and install the requirements::
Initialize a virtual environment for development purposes::
$ git clone git@github.com:<fork>/django-axes.git
$ cd django-axes
$ mkdir ~/.virtualenvs
$ mkdir -p ~/.virtualenvs
$ python3 -m venv ~/.virtualenvs/django-axes
$ source ~/.virtualenvs/bin/activate
$ source ~/.virtualenvs/django-axes/bin/activate
Then install the necessary requirements::
$ cd django-axes
$ pip install -r requirements.txt
Unit tests that are in the `axes/tests` folder can be run easily with the ``axes.tests.settings`` configuration::
Unit tests are located in the ``axes/tests`` folder and can be easily run with the pytest tool::
$ pytest
@ -30,10 +33,14 @@ Mypy runs static typing checks to verify the source code type annotations and co
$ mypy .
Before committing, you can run all the tests against all supported Django versions with tox::
Before committing, you can run all the above tests against all supported Python and Django versions with tox::
$ tox
Tox runs the same tests that are run by Travis, and your code should be good to go if it passes.
Tox runs the same test set that is run by Travis, and your code should be good to go if it passes.
After you have made your changes, open a pull request on GitHub for getting your code upstreamed.
If you wish to limit the testing to specific environment(s), you can parametrize the tox run::
$ tox -e py37-django21
After you have pushed your changes, open a pull request on GitHub for getting your code upstreamed.

View file

@ -8,6 +8,7 @@ Contents
.. toctree::
:maxdepth: 2
:numbered:
1_requirements
2_installation