mirror of
https://github.com/jazzband/django-defender.git
synced 2026-03-16 22:10:32 +00:00
Example djangorestframework auth method
- sample authentication method described in README piggyback: - typo in lockout.html
This commit is contained in:
parent
46ea25c8f0
commit
079c897203
2 changed files with 84 additions and 1 deletions
83
README.md
83
README.md
|
|
@ -71,6 +71,7 @@ Features
|
|||
- list of blocked usernames and ip's
|
||||
- ability to unblock people
|
||||
- list of recent login attempts
|
||||
- Can be easly adapted to custom authentication method.
|
||||
|
||||
Long term goals
|
||||
===============
|
||||
|
|
@ -340,6 +341,88 @@ long to keep the access attempt records in the database before the management
|
|||
command cleans them up.
|
||||
[Default: ``24``]
|
||||
|
||||
Adapting to other authentication method
|
||||
--------------------
|
||||
|
||||
`defender` can be used for authentication other than `Django authentication system`.
|
||||
E.g. if `django-rest-framework` authentication has to be protected from brute force attack,custom authentication method can be implemented.
|
||||
|
||||
There's sample `BasicAuthenticationDefender` class based on `djangorestframework.BasicAuthentication`:
|
||||
|
||||
```python
|
||||
import base64
|
||||
import binascii
|
||||
|
||||
from defender import utils
|
||||
from defender import config
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from rest_framework import HTTP_HEADER_ENCODING, exceptions
|
||||
|
||||
from rest_framework.authentication import (
|
||||
BasicAuthentication,
|
||||
get_authorization_header,
|
||||
)
|
||||
|
||||
|
||||
class BasicAuthenticationDefender(BasicAuthentication):
|
||||
|
||||
def get_username_from_request(self, request):
|
||||
auth = get_authorization_header(request).split()
|
||||
return base64.b64decode(auth[1]).decode(HTTP_HEADER_ENCODING).partition(':')[0]
|
||||
|
||||
def authenticate(self, request):
|
||||
auth = get_authorization_header(request).split()
|
||||
|
||||
if not auth or auth[0].lower() != b'basic':
|
||||
return None
|
||||
|
||||
if len(auth) == 1:
|
||||
msg = _('Invalid basic header. No credentials provided.')
|
||||
raise exceptions.AuthenticationFailed(msg)
|
||||
elif len(auth) > 2:
|
||||
msg = _('Invalid basic header. Credentials string should not contain spaces.')
|
||||
raise exceptions.AuthenticationFailed(msg)
|
||||
|
||||
if utils.is_already_locked(request, get_username=self.get_username_from_request):
|
||||
detail = "You have attempted to login {failure_limit} times, with no success." \
|
||||
"Your account is locked for {cooloff_time_seconds} seconds" \
|
||||
"".format(
|
||||
failure_limit=config.FAILURE_LIMIT,
|
||||
cooloff_time_seconds=config.COOLOFF_TIME
|
||||
)
|
||||
raise exceptions.AuthenticationFailed(_(detail))
|
||||
|
||||
try:
|
||||
auth_parts = base64.b64decode(auth[1]).decode(HTTP_HEADER_ENCODING).partition(':')
|
||||
except (TypeError, UnicodeDecodeError, binascii.Error):
|
||||
msg = _('Invalid basic header. Credentials not correctly base64 encoded.')
|
||||
raise exceptions.AuthenticationFailed(msg)
|
||||
|
||||
userid, password = auth_parts[0], auth_parts[2]
|
||||
login_unsuccessful = False
|
||||
login_exception = None
|
||||
try:
|
||||
response = self.authenticate_credentials(userid, password)
|
||||
except exceptions.AuthenticationFailed as e:
|
||||
login_unsuccessful = True
|
||||
login_exception = e
|
||||
|
||||
utils.add_login_attempt_to_db(request,
|
||||
login_valid=not login_unsuccessful,
|
||||
get_username=self.get_username_from_request)
|
||||
|
||||
user_not_blocked = utils.check_request(request,
|
||||
login_unsuccessful=login_unsuccessful,
|
||||
get_username=self.get_username_from_request)
|
||||
if user_not_blocked and not login_unsuccessful:
|
||||
return response
|
||||
|
||||
raise login_exception
|
||||
|
||||
```
|
||||
|
||||
To make it works add `BasicAuthenticationDefender` to `DEFAULT_AUTHENTICATION_CLASSES` in your `settings.py`.
|
||||
|
||||
Running Tests
|
||||
=============
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<html>
|
||||
<body>
|
||||
<h1>Locked out</h1>
|
||||
<p>Your have attempted to login {{failure_limit}} times, with no success.
|
||||
<p>You have attempted to login {{failure_limit}} times, with no success.
|
||||
Your account is locked for {{cooloff_time_seconds}} seconds</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
Loading…
Reference in a new issue