mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	Fixed #36140 -- Allowed BaseUserCreationForm to define non required password fields.
Regression in e626716c28.
Thanks buffgecko12 for the report and Sarah Boyce for the review.
			
			
This commit is contained in:
		| @@ -1,8 +1,10 @@ | ||||
| import datetime | ||||
| import re | ||||
| import sys | ||||
| import urllib.parse | ||||
| from unittest import mock | ||||
|  | ||||
| from django import forms | ||||
| from django.contrib.auth.forms import ( | ||||
|     AdminPasswordChangeForm, | ||||
|     AdminUserCreationForm, | ||||
| @@ -13,6 +15,7 @@ from django.contrib.auth.forms import ( | ||||
|     ReadOnlyPasswordHashField, | ||||
|     ReadOnlyPasswordHashWidget, | ||||
|     SetPasswordForm, | ||||
|     SetPasswordMixin, | ||||
|     UserChangeForm, | ||||
|     UserCreationForm, | ||||
|     UsernameField, | ||||
| @@ -24,13 +27,14 @@ from django.contrib.sites.models import Site | ||||
| from django.core import mail | ||||
| from django.core.exceptions import ValidationError | ||||
| from django.core.mail import EmailMultiAlternatives | ||||
| from django.forms import forms | ||||
| from django.forms.fields import CharField, Field, IntegerField | ||||
| from django.test import SimpleTestCase, TestCase, override_settings | ||||
| from django.test import RequestFactory, SimpleTestCase, TestCase, override_settings | ||||
| from django.urls import reverse | ||||
| from django.utils import translation | ||||
| from django.utils.text import capfirst | ||||
| from django.utils.translation import gettext as _ | ||||
| from django.views.debug import technical_500_response | ||||
| from django.views.decorators.debug import sensitive_variables | ||||
|  | ||||
| from .models.custom_user import ( | ||||
|     CustomUser, | ||||
| @@ -412,6 +416,19 @@ class CustomUserCreationFormTest(TestDataMixin, TestCase): | ||||
|         user = form.save(commit=True) | ||||
|         self.assertSequenceEqual(user.orgs.all(), [organization]) | ||||
|  | ||||
|     def test_custom_form_with_non_required_password(self): | ||||
|         class CustomUserCreationForm(BaseUserCreationForm): | ||||
|             password1 = forms.CharField(required=False) | ||||
|             password2 = forms.CharField(required=False) | ||||
|             another_field = forms.CharField(required=True) | ||||
|  | ||||
|         data = { | ||||
|             "username": "testclientnew", | ||||
|             "another_field": "Content", | ||||
|         } | ||||
|         form = CustomUserCreationForm(data) | ||||
|         self.assertIs(form.is_valid(), True, form.errors) | ||||
|  | ||||
|  | ||||
| class UserCreationFormTest(BaseUserCreationFormTest): | ||||
|  | ||||
| @@ -1671,3 +1688,50 @@ class AdminUserCreationFormTest(BaseUserCreationFormTest): | ||||
|         u = form.save() | ||||
|         self.assertEqual(u.username, data["username"]) | ||||
|         self.assertFalse(u.has_usable_password()) | ||||
|  | ||||
|  | ||||
| class SensitiveVariablesTest(TestDataMixin, TestCase): | ||||
|     @sensitive_variables("data") | ||||
|     def test_passwords_marked_as_sensitive_in_admin_forms(self): | ||||
|         data = { | ||||
|             "password1": "passwordsensitive", | ||||
|             "password2": "sensitivepassword", | ||||
|             "usable_password": "true", | ||||
|         } | ||||
|         forms = [ | ||||
|             AdminUserCreationForm({**data, "username": "newusername"}), | ||||
|             AdminPasswordChangeForm(self.u1, data), | ||||
|         ] | ||||
|  | ||||
|         password1_fragment = """ | ||||
|          <td>password1</td> | ||||
|          <td class="code"><pre>'********************'</pre></td> | ||||
|          """ | ||||
|         password2_fragment = """ | ||||
|          <td>password2</td> | ||||
|          <td class="code"><pre>'********************'</pre></td> | ||||
|         """ | ||||
|         error = ValueError("Forced error") | ||||
|         for form in forms: | ||||
|             with self.subTest(form=form): | ||||
|                 with mock.patch.object( | ||||
|                     SetPasswordMixin, "validate_passwords", side_effect=error | ||||
|                 ): | ||||
|                     try: | ||||
|                         form.is_valid() | ||||
|                     except ValueError: | ||||
|                         exc_info = sys.exc_info() | ||||
|                     else: | ||||
|                         self.fail("Form validation should have failed.") | ||||
|  | ||||
|                 response = technical_500_response(RequestFactory().get("/"), *exc_info) | ||||
|  | ||||
|                 self.assertNotContains(response, "sensitivepassword", status_code=500) | ||||
|                 self.assertNotContains(response, "passwordsensitive", status_code=500) | ||||
|                 self.assertContains(response, str(error), status_code=500) | ||||
|                 self.assertContains( | ||||
|                     response, password1_fragment, html=True, status_code=500 | ||||
|                 ) | ||||
|                 self.assertContains( | ||||
|                     response, password2_fragment, html=True, status_code=500 | ||||
|                 ) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user