From d43879a117cda4c98601bfff86183ebfa81e4c96 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Thu, 14 Jan 2021 10:30:46 +0100 Subject: [PATCH 1/3] use honeypot field to detect robots on registration form (#50108) --- src/authentic2/forms/honeypot.py | 38 +++++++++++++++++++ src/authentic2/forms/registration.py | 3 +- .../templates/authentic2/honeypot_input.html | 1 + tests/test_registration.py | 13 +++++++ 4 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 src/authentic2/forms/honeypot.py create mode 100644 src/authentic2/templates/authentic2/honeypot_input.html diff --git a/src/authentic2/forms/honeypot.py b/src/authentic2/forms/honeypot.py new file mode 100644 index 00000000..be2530ba --- /dev/null +++ b/src/authentic2/forms/honeypot.py @@ -0,0 +1,38 @@ +# authentic2 - versatile identity manager +# Copyright (C) 2010-2019 Entr'ouvert +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +from django.core.exceptions import ValidationError +from django.forms import Form, CheckboxInput, BooleanField +from django.utils.html import mark_safe +from django.utils.translation import gettext as _ + + +class HoneypotInput(CheckboxInput): + template_name = 'authentic2/honeypot_input.html' + + +class HoneypotForm(Form): + robotcheck = BooleanField(widget=HoneypotInput, required=False) + + def clean(self): + if self.cleaned_data.get('robotcheck'): + raise ValidationError( + mark_safe( + _('Your registration request is refused. Indeed your browser checked \ +an hidden anti-robot checkbox on the registration form. A browser extension may produce \ +this behaviour, in this case disable the extension and try agin.'))) + return super().clean() diff --git a/src/authentic2/forms/registration.py b/src/authentic2/forms/registration.py index 6b9e7588..90e215f3 100644 --- a/src/authentic2/forms/registration.py +++ b/src/authentic2/forms/registration.py @@ -28,12 +28,13 @@ from authentic2.a2_rbac.models import OrganizationalUnit from .. import app_settings, models from . import profile as profile_forms +from .honeypot import HoneypotForm from .fields import ValidatedEmailField User = get_user_model() -class RegistrationForm(Form): +class RegistrationForm(HoneypotForm): error_css_class = 'form-field-error' required_css_class = 'form-field-required' diff --git a/src/authentic2/templates/authentic2/honeypot_input.html b/src/authentic2/templates/authentic2/honeypot_input.html new file mode 100644 index 00000000..7aeb63a0 --- /dev/null +++ b/src/authentic2/templates/authentic2/honeypot_input.html @@ -0,0 +1 @@ +{% load i18n %} diff --git a/tests/test_registration.py b/tests/test_registration.py index 13645ee2..b209301f 100644 --- a/tests/test_registration.py +++ b/tests/test_registration.py @@ -819,3 +819,16 @@ 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', + }) + assert len(mailoutbox) == 0 + assert 'Your registration request is refused' in response -- 2.29.2