From 2d23cc027f17d3f7e5314eecec486d3f85593212 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Thu, 14 Jan 2021 10:30:46 +0100 Subject: [PATCH] add a honeypot middleware (#50108) Forms must be instrumented by adding a 'robotcheck' input, then a request.is_robot boolean signals if the request is possibly from a spam robot. --- src/authentic2/middleware.py | 9 +++++++++ src/authentic2/settings.py | 1 + .../login_password_registration_form.html | 1 + src/authentic2/views.py | 2 ++ tests/test_registration.py | 14 ++++++++++++++ 5 files changed, 27 insertions(+) diff --git a/src/authentic2/middleware.py b/src/authentic2/middleware.py index e5aeb4f0..fb8785e1 100644 --- a/src/authentic2/middleware.py +++ b/src/authentic2/middleware.py @@ -227,3 +227,12 @@ def null_character_middleware(get_response): return get_response(request) return middleware + + +def honeypot_middleware(get_response): + def middleware(request): + request.is_robot = 'robotcheck' in request.POST + if request.is_robot: + messages.warning(request, _('We think you are robot, so we did nothing. If you are not a robot, please contact your administrator.')) + return get_response(request) + return middleware diff --git a/src/authentic2/settings.py b/src/authentic2/settings.py index cce65c88..249c85f4 100644 --- a/src/authentic2/settings.py +++ b/src/authentic2/settings.py @@ -102,6 +102,7 @@ MIDDLEWARE = ( 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'authentic2.middleware.journal_middleware', + 'authentic2.middleware.honeypot_middleware', ) DATABASES['default']['ATOMIC_REQUESTS'] = True diff --git a/src/authentic2/templates/authentic2/login_password_registration_form.html b/src/authentic2/templates/authentic2/login_password_registration_form.html index e7384af5..99ef959c 100644 --- a/src/authentic2/templates/authentic2/login_password_registration_form.html +++ b/src/authentic2/templates/authentic2/login_password_registration_form.html @@ -4,6 +4,7 @@
{% csrf_token %} {{ form|with_template }} +
{% endblock %} diff --git a/src/authentic2/views.py b/src/authentic2/views.py index 26133d84..a26487c8 100644 --- a/src/authentic2/views.py +++ b/src/authentic2/views.py @@ -829,6 +829,8 @@ class BaseRegistrationView(FormView): return super(BaseRegistrationView, self).dispatch(request, *args, **kwargs) def form_valid(self, form): + if self.request.is_robot: + return utils.redirect(self.request, 'registration_complete', params={REDIRECT_FIELD_NAME: self.next_url}) email = form.cleaned_data.pop('email') # if an email has already been sent, warn once before allowing resend diff --git a/tests/test_registration.py b/tests/test_registration.py index 13645ee2..6a350198 100644 --- a/tests/test_registration.py +++ b/tests/test_registration.py @@ -819,3 +819,17 @@ def test_registration_email_not_verified_required_and_unrequired_attributes(app, assert user.attributes.preferred_color == 'bleu' assert user.email == 'john.doe2@example.com' assert user.email_verified is True + + +def test_honeypot(app, db, settings, mailoutbox): + settings.DEFAULT_FROM_EMAIL = 'show only addr ' + + response = app.get(utils.make_url('registration_register')) + response = app.post(utils.make_url('registration_register'), params={ + 'email': 'testbot@entrouvert.com', + 'csrfmiddlewaretoken': response.context['csrf_token'], + 'robotcheck': 'a', + }) + response = response.follow() + assert len(mailoutbox) == 0 + assert len(response.pyquery('li.warning')) -- 2.29.2