From 8206af081e239598cfd15d165d4d8ab9849ee23c Mon Sep 17 00:00:00 2001 From: Martin Morgenstern Date: Wed, 10 Mar 2021 18:43:23 +0100 Subject: [PATCH] Filter sensitive POST parameters in error reports --- src/django_registration/views.py | 3 ++ tests/test_views.py | 74 +++++++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/src/django_registration/views.py b/src/django_registration/views.py index d0c7cf28..41cba222 100644 --- a/src/django_registration/views.py +++ b/src/django_registration/views.py @@ -7,7 +7,9 @@ from django.core.exceptions import ImproperlyConfigured from django.http import HttpResponseRedirect from django.urls import reverse_lazy +from django.utils.decorators import method_decorator from django.utils.encoding import force_str +from django.views.decorators.debug import sensitive_post_parameters from django.views.generic.base import TemplateView from django.views.generic.edit import FormView @@ -40,6 +42,7 @@ class RegistrationView(FormView): success_url = None template_name = "django_registration/registration_form.html" + @method_decorator(sensitive_post_parameters()) def dispatch(self, *args, **kwargs): """ Check that user signup is allowed before even bothering to diff --git a/tests/test_views.py b/tests/test_views.py index df0dd9ba..34f7fed9 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -3,10 +3,14 @@ """ +import logging +import sys + from django.contrib.auth import get_user_model -from django.core import signing +from django.contrib.auth.models import AnonymousUser +from django.core import mail, signing from django.core.exceptions import ImproperlyConfigured -from django.test import override_settings +from django.test import RequestFactory, override_settings from django.urls import reverse from django_registration import forms @@ -86,3 +90,69 @@ def test_user_mismatch_breaks_view(self): ) with self.assertRaisesMessage(ImproperlyConfigured, message): view.get_form() + + +class RegistrationError(Exception): + """ + Distinct exception class to simulate an unhandled error in the below + tests. + + """ + + +class BuggyRegistrationView(base_views.RegistrationView): + """ + Registration view that simulates an unhandled exception. + + """ + + def registration_allowed(self): + raise RegistrationError("catch me if you can") + + +buggy_view = BuggyRegistrationView.as_view() + + +@override_settings(ADMINS=[("Admin", "admin@localhost")]) +class SensitiveParameterFilterTests(RegistrationTestCase): + """ + Test filtering of sensitive POST parameters in error reports for the + registration view. + + """ + + logger = logging.getLogger("django") + factory = RequestFactory() + + def test_sensitive_post_parameters_are_filtered(self): + """ + When an unexpected exception occurs during a POST request to the + registration view, the default email report to ADMINS must not + contain the submitted passwords. + + """ + request = self.factory.post("/raise/", data=self.valid_data) + request.user = AnonymousUser() + # we cannot use self.assertRaises(...) here because of sys.exc_info() + try: + buggy_view(request) + self.fail("expected exception not thrown") + except RegistrationError as error: + self.assertEqual(str(error), "catch me if you can") + # based on code in Django (tests/view_tests/views.py) + self.logger.error( + "Internal Server Error: %s" % request.path, + exc_info=sys.exc_info(), + extra={"status_code": 500, "request": request}, + ) + self.assertEqual(len(mail.outbox), 1) + email = mail.outbox[0] + self.assertIn("RegistrationError at /raise/", email.body) + self.assertIn("catch me if you can", email.body) + self.assertIn("No GET data", email.body) + self.assertNotIn("No POST data", email.body) + self.assertIn("password1", email.body) + self.assertIn("password2", email.body) + self.assertNotIn(self.valid_data["password1"], email.body) + self.assertNotIn(self.valid_data["password2"], email.body) + self.assertNotIn(self.valid_data["email"], email.body)