the verification password is incorrect one or both passwords weren t given the success case the normalization happens in abstractbaseuser clean and modelform validation calls model clean usernames are not normalized if they are too long to prevent almost identical usernames visually identical but differing by their unicode code points only unicode nfkc normalization should make appear them equal to django baseusercreationform password validation uses all of the form s data to verify that the login form rejects inactive users use an authentication backend that allows them the user submits an invalid username the user is inactive use an authentication backend that rejects inactive users an invalid login doesn t leak the inactive status of a user data username inactive password incorrect form authenticationformnone data self assertfalseform isvalid self assertequal form nonfielderrors form errormessagesinvalidlogin username user meta getfieldusername verbosename def testloginfailedself signalcalls def signalhandlerkwargs signalcalls appendkwargs userloginfailed connectsignalhandler fakerequest object try form authenticationform fakerequest username testclient password incorrect self assertfalseform isvalid self assertissignalcalls0request fakerequest finally userloginfailed disconnectsignalhandler def testinactiveuseri18nself with self settingsusei18ntrue translation override ptbr deactivatetrue the user is inactive data username inactive password password form authenticationformnone data self assertfalseform isvalid self assertequal form nonfielderrors strform errormessagesinactive use an authentication backend that allows inactive users overridesettings authenticationbackends django contrib auth backends allowallusersmodelbackend def testcustomloginallowedpolicyself the user is inactive but our custom form policy allows them to log in data username inactive password password class authenticationformwithinactiveusersokayauthenticationform def confirmloginallowedself user pass form authenticationformwithinactiveusersokaynone data self asserttrueform isvalid raise a validationerror in the form to disallow some logins according to custom logic class pickyauthenticationformauthenticationform def confirmloginallowedself user if user username inactive raise validationerrorthis user is disallowed raise validationerrorsorry nobody s allowed in form pickyauthenticationformnone data self assertfalseform isvalid self assertequalform nonfielderrors this user is disallowed data username testclient password password form pickyauthenticationformnone data self assertfalseform isvalid self assertequalform nonfielderrors sorry nobody s allowed in def testsuccessself the success case data username testclient password password form authenticationformnone data self asserttrueform isvalid self assertequalform nonfielderrors def testunicodeusernameself user objects createuserusername passwordpwd data username password pwd form authenticationformnone data self asserttrueform isvalid self assertequalform nonfielderrors overridesettingsauthusermodelauthtests customemailfield def testusernamefieldmaxlengthmatchesusermodelself self assertequalcustomemailfield meta getfieldusername maxlength 255 data username u 255 password pwd email testexample com customemailfield objects createuserdata form authenticationformnone data self assertequalform fieldsusername maxlength 255 self assertequalform fieldsusername widget attrs getmaxlength 255 self assertequalform errors overridesettingsauthusermodelauthtests integerusernameuser def testusernamefieldmaxlengthdefaultsto254self self assertisnoneintegerusernameuser meta getfieldusername maxlength data username 0123456 password password integerusernameuser objects createuserdata form authenticationformnone data self assertequalform fieldsusername maxlength 254 self assertequalform fieldsusername widget attrs getmaxlength 254 self assertequalform errors def testusernamefieldlabelself class customauthenticationformauthenticationform username charfieldlabelname maxlength75 form customauthenticationform self assertequalformusername label name def testusernamefieldlabelnotsetself class customauthenticationformauthenticationform username charfield form customauthenticationform usernamefield user meta getfielduser usernamefield self assertequal form fieldsusername label capfirstusernamefield verbosename def testusernamefieldautocapitalizenoneself form authenticationform self assertequal form fieldsusername widget attrs getautocapitalize none def testusernamefieldlabelemptystringself class customauthenticationformauthenticationform username charfieldlabel form customauthenticationform self assertequalform fieldsusername label def testpasswordwhitespacenotstrippedself data username testuser password pass form authenticationformnone data form isvalid not necessary to have valid credentails for the test self assertequalform cleaneddatapassword datapassword overridesettingsauthusermodelauthtests integerusernameuser def testintegerusernameself class customauthenticationformauthenticationform username integerfield user integerusernameuser objects createuserusername0 passwordpwd data username 0 password pwd form customauthenticationformnone data self asserttrueform isvalid self assertequalform cleaneddatausername datausername self assertequalform cleaneddatapassword datapassword self assertequalform errors self assertequalform usercache user def testgetinvalidloginerrorself error authenticationform getinvalidloginerror self assertisinstanceerror validationerror self assertequal error message please enter a correct usernames and password note that both fields may be casesensitive self assertequalerror code invalidlogin self assertequalerror params username username def testhtmlautocompleteattributesself form authenticationform tests username username password currentpassword for fieldname autocomplete in tests with self subtestfieldnamefieldname autocompleteautocomplete self assertequal form fieldsfieldname widget attrsautocomplete autocomplete def testnopasswordself data username username form authenticationformnone data self assertisform isvalid false self assertequal formpassword errors field defaulterrormessagesrequired class setpasswordformtesttestdatamixin testcase def testpasswordverificationself the two new passwords do not match user user objects getusernametestclient data newpassword1 abc123 newpassword2 abc form setpasswordformuser data self assertfalseform isvalid self assertequal formnewpassword2 errors strform errormessagespasswordmismatch mock patchdjango contrib auth passwordvalidation passwordchanged def testsuccessself passwordchanged user user objects getusernametestclient data newpassword1 abc123 newpassword2 abc123 form setpasswordformuser data self asserttrueform isvalid form savecommitfalse self assertequalpasswordchanged callcount 0 form save self assertequalpasswordchanged callcount 1 overridesettings authpasswordvalidators name django contrib auth passwordvalidation userattributesimilarityvalidator name django contrib auth passwordvalidation minimumlengthvalidator options minlength 12 def testvalidatespasswordself user user objects getusernametestclient data newpassword1 testclient newpassword2 testclient form setpasswordformuser data self assertfalseform isvalid self assertequallenformnewpassword2 errors 2 self assertin the password is too similar to the username formnewpassword2 errors self assertin this password is too short it must contain at least 12 characters formnewpassword2 errors def testnopasswordself user user objects getusernametestclient data newpassword1 newpassword form setpasswordformuser data self assertisform isvalid false self assertequal formnewpassword2 errors field defaulterrormessagesrequired form setpasswordformuser self assertisform isvalid false self assertequal formnewpassword1 errors field defaulterrormessagesrequired self assertequal formnewpassword2 errors field defaulterrormessagesrequired def testpasswordwhitespacenotstrippedself user user objects getusernametestclient data newpassword1 password newpassword2 password form setpasswordformuser data self asserttrueform isvalid self assertequalform cleaneddatanewpassword1 datanewpassword1 self assertequalform cleaneddatanewpassword2 datanewpassword2 overridesettings authpasswordvalidators name django contrib auth passwordvalidation userattributesimilarityvalidator name django contrib auth passwordvalidation minimumlengthvalidator options minlength 12 def testhelptexttranslationself frenchhelptexts votre mot de passe ne peut pas trop ressembler vos autres informations personnelles votre mot de passe doit contenir au minimum 12 caractres form setpasswordformself u1 with translation overridefr html form asp for frenchtext in frenchhelptexts self assertinfrenchtext html def testhtmlautocompleteattributesself form setpasswordformself u1 tests newpassword1 newpassword newpassword2 newpassword for fieldname autocomplete in tests with self subtestfieldnamefieldname autocompleteautocomplete self assertequal form fieldsfieldname widget attrsautocomplete autocomplete class passwordchangeformtesttestdatamixin testcase def testincorrectpasswordself user user objects getusernametestclient data oldpassword test newpassword1 abc123 newpassword2 abc123 form passwordchangeformuser data self assertfalseform isvalid self assertequal formoldpassword errors strform errormessagespasswordincorrect def testpasswordverificationself the two new passwords do not match user user objects getusernametestclient data oldpassword password newpassword1 abc123 newpassword2 abc form passwordchangeformuser data self assertfalseform isvalid self assertequal formnewpassword2 errors strform errormessagespasswordmismatch mock patchdjango contrib auth passwordvalidation passwordchanged def testsuccessself passwordchanged the success case user user objects getusernametestclient data oldpassword password newpassword1 abc123 newpassword2 abc123 form passwordchangeformuser data self asserttrueform isvalid form savecommitfalse self assertequalpasswordchanged callcount 0 form save self assertequalpasswordchanged callcount 1 def testfieldorderself regression test check the order of fields user user objects getusernametestclient self assertequal listpasswordchangeformuser fields oldpassword newpassword1 newpassword2 def testpasswordwhitespacenotstrippedself user user objects getusernametestclient user setpassword oldpassword data oldpassword oldpassword newpassword1 pass newpassword2 pass form passwordchangeformuser data self asserttrueform isvalid self assertequalform cleaneddataoldpassword dataoldpassword self assertequalform cleaneddatanewpassword1 datanewpassword1 self assertequalform cleaneddatanewpassword2 datanewpassword2 def testhtmlautocompleteattributesself user user objects getusernametestclient form passwordchangeformuser self assertequal form fieldsoldpassword widget attrsautocomplete currentpassword class userchangeformtesttestdatamixin testcase def testusernamevalidityself user user objects getusernametestclient data username not valid form userchangeformdata instanceuser self assertfalseform isvalid validator next v for v in user meta getfieldusername validators if v code invalid self assertequalformusername errors strvalidator message def testbug14242self a regression test introduce by adding an optimization for the userchangeform class myuserformuserchangeform def initself args kwargs super initargs kwargs self fields groups helptext these groups give users different permissions class metauserchangeform meta fields groups just check we can create it myuserform def testunusablepasswordself user user objects getusernameemptypassword user setunusablepassword user save form userchangeforminstanceuser self assertinno password set form astable def testbug17944emptypasswordself user user objects getusernameemptypassword form userchangeforminstanceuser self assertinno password set form astable def testbug17944unmanageablepasswordself user user objects getusernameunmanageablepassword form userchangeforminstanceuser self assertin invalid password format or unknown hashing algorithm form astable def testbug17944unknownpasswordalgorithmself user user objects getusernameunknownpassword form userchangeforminstanceuser self assertin invalid password format or unknown hashing algorithm form astable def testbug19133self the change form does not return the password value use the form to construct the post data user user objects getusernametestclient formfordata userchangeforminstanceuser postdata formfordata initial the password field should be readonly so anything posted here should be ignored the form will be valid and give back the initial value for the password field postdatapassword new password form userchangeforminstanceuser datapostdata self asserttrueform isvalid original hashed password contains self assertin form cleaneddatapassword def testbug19349boundpasswordfieldself user user objects getusernametestclient form userchangeformdata instanceuser when rendering the bound password field readonlypasswordhashwidget needs the initial value to render correctly self assertequalform initialpassword formpassword value overridesettingsrooturlconfauthtests urlsadmin def testlinktopasswordresetinhelptextviatofieldself user user objects getusernametestclient form userchangeformdata instanceuser passwordhelptext form fieldspassword helptext matches re search a href passwordhelptext url to userchangeform in admin via tofield instead of pk adminuserchangeurl reverse fadmin user meta applabeluser meta modelnamechange argsuser username joinedurl urllib parse urljoinadminuserchangeurl matches group1 pwchangeurl reverse fadmin user meta applabeluser meta modelnamepasswordchange argsuser pk self assertequaljoinedurl pwchangeurl def testcustomformself class customuserchangeformuserchangeform class metauserchangeform meta model extensionuser fields username password dateofbirth user user objects getusernametestclient data username testclient password testclient dateofbirth 19980224 form customuserchangeformdata instanceuser self asserttrueform isvalid form save self assertequalform cleaneddatausername testclient self assertequalform cleaneddatadateofbirth datetime date1998 2 24 def testpasswordexcludedself class userchangeformwithoutpassworduserchangeform password none class meta model user exclude password form userchangeformwithoutpassword self assertnotinpassword form fields def testusernamefieldautocapitalizenoneself form userchangeform self assertequal form fieldsusername widget attrs getautocapitalize none overridesettingstemplatesauthtemplates class passwordresetformtesttestdatamixin testcase classmethod def setupclasscls super setupclass this cleanup is necessary because contrib sites cache makes tests interfere with each other see 11505 site objects clearcache def createdummyuserself username jsmith email jsmithexample com user user objects createuserusername email test123 return user username email def testinvalidemailself data email not valid form passwordresetformdata self assertfalseform isvalid self assertequalformemail errors enter a valid email address def testuseremailunicodecollisionself user objects createusermike123 mikeexample org test123 user objects createusermike456 mkeexample org test123 data email mkeexample org form passwordresetformdata self asserttrueform isvalid form save self assertequallenmail outbox 1 self assertequalmail outbox0 to mkeexample org def testuseremaildomainunicodecollisionself user objects createusermike123 mikeixample org test123 user objects createusermike456 mikexample org test123 data email mikexample org form passwordresetformdata self asserttrueform isvalid form save self assertequallenmail outbox 1 self assertequalmail outbox0 to mikexample org def testuseremailunicodecollisionnonexistentself user objects createusermike123 mikeexample org test123 data email mkeexample org form passwordresetformdata self asserttrueform isvalid form save self assertequallenmail outbox 0 def testuseremaildomainunicodecollisionnonexistentself user objects createusermike123 mikeixample org test123 data email mikexample org form passwordresetformdata self asserttrueform isvalid form save self assertequallenmail outbox 0 def testnonexistentemailself data email foobar com form passwordresetformdata self asserttrueform isvalid self assertequallenmail outbox 0 def testcleaneddataself user username email self createdummyuser data email email form passwordresetformdata self asserttrueform isvalid form savedomainoverrideexample com self assertequalform cleaneddataemail email self assertequallenmail outbox 1 def testcustomemailsubjectself data email testclientexample com form passwordresetformdata self asserttrueform isvalid since we re not providing a request object we must provide a domainoverride to prevent the save operation from failing in the potential case where contrib sites is not installed refs 16412 form savedomainoverrideexample com self assertequallenmail outbox 1 self assertequalmail outbox0 subject custom password reset on example com def testcustomemailconstructorself data email testclientexample com class customemailpasswordresetformpasswordresetform def sendmail self subjecttemplatename emailtemplatename context fromemail toemail htmlemailtemplatenamenone emailmultialternatives forgot your password sorry to hear you forgot your password none toemail sitemonitorexample com headersreplyto webmasterexample com alternatives really sorry to hear you forgot your password texthtml send form customemailpasswordresetformdata self asserttrueform isvalid since we re not providing a request object we must provide a domainoverride to prevent the save operation from failing in the potential case where contrib sites is not installed refs 16412 form savedomainoverrideexample com self assertequallenmail outbox 1 self assertequalmail outbox0 subject forgot your password self assertequalmail outbox0 bcc sitemonitorexample com self assertequalmail outbox0 contentsubtype plain def testpreserveusernamecaseself user user objects createuserformstest2 testexample com test self assertequaluser email testexample com user user objects createuserformstest3 test test self assertequaluser email test def testinactiveuserself user username email self createdummyuser user isactive false user save form passwordresetformemail email self asserttrueform isvalid form save self assertequallenmail outbox 0 def testunusablepasswordself user user objects createusertestuser testexample com test data email testexample com form passwordresetformdata self asserttrueform isvalid user setunusablepassword user save form passwordresetformdata the form itself is valid but no email is sent self asserttrueform isvalid form save self assertequallenmail outbox 0 def testsaveplaintextemailself user username email self createdummyuser form passwordresetformemail email self asserttrueform isvalid form save self assertequallenmail outbox 1 message mail outbox0 message self assertfalsemessage ismultipart self assertequalmessage getcontenttype textplain self assertequalmessage getsubject custom password reset on example com self assertequallenmail outbox0 alternatives 0 self assertequalmessage getallto email self asserttrue re matchrhttp example comresetw message getpayload def testsavehtmlemailtemplatenameself user username email self createdummyuser form passwordresetformemail email self asserttrueform isvalid form save htmlemailtemplatenameregistrationhtmlpasswordresetemail html self assertequallenmail outbox 1 self assertequallenmail outbox0 alternatives 1 message mail outbox0 message self assertequalmessage getsubject custom password reset on example com self assertequallenmessage getpayload 2 self asserttruemessage ismultipart self assertequalmessage getpayload0 getcontenttype textplain self assertequalmessage getpayload1 getcontenttype texthtml self assertequalmessage getallto email self asserttrue re match rhttp example comresetw message getpayload0 getpayload self asserttrue re match r htmla hrefhttp example comresetwlinkahtml message getpayload1 getpayload overridesettingsauthusermodelauthtests customemailfield def testcustomemailfieldself email testmail com customemailfield objects createusertest name test password email form passwordresetformemail email self asserttrueform isvalid form save self assertequalform cleaneddataemail email self assertequallenmail outbox 1 self assertequalmail outbox0 to email def testhtmlautocompleteattributesself form passwordresetform self assertequalform fieldsemail widget attrsautocomplete email class readonlypasswordhashtestsimpletestcase def testbug19349renderwithnonevalueself rendering the widget with value set to none mustn t raise an exception widget readonlypasswordhashwidget html widget rendernamepassword valuenone attrs self assertinno password set html overridesettings passwordhashersdjango contrib auth hashers pbkdf2passwordhasher def testrenderself widget readonlypasswordhashwidget value pbkdf2sha256100000a6pucb1qsfcdwmckn9hqidj48nve5x0fem6a9yioqqcl83m2z5u dm0 self asserthtmlequal widget rendername value id idpassword div ididpassword strongalgorithmstrong bdipbkdf2sha256bdi strongiterationsstrong bdi100000bdi strongsaltstrong bdia6pucbbdi stronghashstrong bdiwmckn9bdi div def testreadonlyfieldhaschangedself field readonlypasswordhashfield self assertisfield disabled true self assertfalsefield haschangedaaa bbb def testlabelself class testformforms form hashfield readonlypasswordhashfield boundfield testformhashfield self assertisnoneboundfield field widget idforlabelid self assertequalboundfield labeltag labelhash field label class adminpasswordchangeformtesttestdatamixin testcase mock patchdjango contrib auth passwordvalidation passwordchanged def testsuccessself passwordchanged user user objects getusernametestclient data password1 test123 password2 test123 form adminpasswordchangeformuser data self asserttrueform isvalid form savecommitfalse self assertequalpasswordchanged callcount 0 form save self assertequalpasswordchanged callcount 1 self assertequalform changeddata password def testpasswordwhitespacenotstrippedself user user objects getusernametestclient data password1 pass password2 pass form adminpasswordchangeformuser data self asserttrueform isvalid self assertequalform cleaneddatapassword1 datapassword1 self assertequalform cleaneddatapassword2 datapassword2 self assertequalform changeddata password def testnonmatchingpasswordsself user user objects getusernametestclient data password1 password1 password2 password2 form adminpasswordchangeformuser data self assertequal form errorspassword2 form errormessagespasswordmismatch self assertequalform changeddata password def testmissingpasswordsself user user objects getusernametestclient data password1 password2 form adminpasswordchangeformuser data requirederror field defaulterrormessagesrequired self assertequalform errorspassword1 requirederror self assertequalform errorspassword2 requirederror self assertequalform changeddata def testonepasswordself user user objects getusernametestclient form1 adminpasswordchangeformuser password1 password2 test requirederror field defaulterrormessagesrequired self assertequalform1 errorspassword1 requirederror self assertnotinpassword2 form1 errors self assertequalform1 changeddata form2 adminpasswordchangeformuser password1 test password2 self assertequalform2 errorspassword2 requirederror self assertnotinpassword1 form2 errors self assertequalform2 changeddata def testhtmlautocompleteattributesself user user objects getusernametestclient form adminpasswordchangeformuser tests password1 newpassword password2 newpassword for fieldname autocomplete in tests with self subtestfieldnamefieldname autocompleteautocomplete self assertequal form fieldsfieldname widget attrsautocomplete autocomplete the verification password is incorrect one or both passwords weren t given the success case the normalization happens in abstractbaseuser clean and modelform validation calls model clean u 2126 ohm sign u 03a9 greek capital letter omega usernames are not normalized if they are too long to prevent almost identical usernames visually identical but differing by their unicode code points only unicode nfkc normalization should make appear them equal to django u 03a9 greek capital letter omega u 2126 ohm sign without username_field baseusercreationform password validation uses all of the form s data to verify that the login form rejects inactive users use an authentication backend that allows them the user submits an invalid username the user is inactive use an authentication backend that rejects inactive users an invalid login doesn t leak the inactive status of a user the user is inactive use an authentication backend that allows inactive users the user is inactive but our custom form policy allows them to log in raise a validationerror in the form to disallow some logins according to custom logic the success case not necessary to have valid credentails for the test the two new passwords do not match the two new passwords do not match the success case regression test check the order of fields a regression test introduce by adding an optimization for the userchangeform just check we can create it use the form to construct the post data the password field should be readonly so anything posted here should be ignored the form will be valid and give back the initial value for the password field original hashed password contains when rendering the bound password field readonlypasswordhashwidget needs the initial value to render correctly url to userchangeform in admin via to_field instead of pk this cleanup is necessary because contrib sites cache makes tests interfere with each other see 11505 create a user and return a tuple user_object username email test nonexistent email address this should not fail because it would expose information about registered users since we re not providing a request object we must provide a domain_override to prevent the save operation from failing in the potential case where contrib sites is not installed refs 16412 since we re not providing a request object we must provide a domain_override to prevent the save operation from failing in the potential case where contrib sites is not installed refs 16412 preserve the case of the user name before the in the email address when creating a user 5605 inactive user cannot receive password reset email the form itself is valid but no email is sent test the passwordresetform save method with no html_email_template_name parameter passed in test to ensure original behavior is unchanged after the parameter was added test the passwordresetform save method with html_email_template_name parameter specified test to ensure that a multipart email is sent with both text plain and text html parts rendering the widget with value set to none mustn t raise an exception readonlypasswordhashwidget doesn t contain a for attribute in the label because it doesn t have any labelable elements
import datetime
import re
import urllib.parse
from unittest import mock

from django.contrib.auth.forms import (
    AdminPasswordChangeForm,
    AuthenticationForm,
    BaseUserCreationForm,
    PasswordChangeForm,
    PasswordResetForm,
    ReadOnlyPasswordHashField,
    ReadOnlyPasswordHashWidget,
    SetPasswordForm,
    UserChangeForm,
    UserCreationForm,
    UsernameField,
)
from django.contrib.auth.models import User
from django.contrib.auth.signals import user_login_failed
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.urls import reverse
from django.utils import translation
from django.utils.text import capfirst
from django.utils.translation import gettext as _

from .models.custom_user import (
    CustomUser,
    CustomUserWithoutIsActiveField,
    ExtensionUser,
)
from .models.with_custom_email_field import CustomEmailField
from .models.with_integer_username import IntegerUsernameUser
from .models.with_many_to_many import CustomUserWithM2M, Organization
from .settings import AUTH_TEMPLATES


class TestDataMixin:
    @classmethod
    def setUpTestData(cls):
        cls.u1 = User.objects.create_user(
            username="testclient", password="password", email="testclient@example.com"
        )
        cls.u2 = User.objects.create_user(
            username="inactive", password="password", is_active=False
        )
        cls.u3 = User.objects.create_user(username="staff", password="password")
        cls.u4 = User.objects.create(username="empty_password", password="")
        cls.u5 = User.objects.create(username="unmanageable_password", password="$")
        cls.u6 = User.objects.create(username="unknown_password", password="foo$bar")


class BaseUserCreationFormTest(TestDataMixin, TestCase):
    def test_user_already_exists(self):
        data = {
            "username": "testclient",
            "password1": "test123",
            "password2": "test123",
        }
        form = BaseUserCreationForm(data)
        self.assertFalse(form.is_valid())
        self.assertEqual(
            form["username"].errors,
            [str(User._meta.get_field("username").error_messages["unique"])],
        )

    def test_invalid_data(self):
        data = {
            "username": "jsmith!",
            "password1": "test123",
            "password2": "test123",
        }
        form = BaseUserCreationForm(data)
        self.assertFalse(form.is_valid())
        validator = next(
            v
            for v in User._meta.get_field("username").validators
            if v.code == "invalid"
        )
        self.assertEqual(form["username"].errors, [str(validator.message)])

    def test_password_verification(self):
        
        data = {
            "username": "jsmith",
            "password1": "test123",
            "password2": "test",
        }
        form = BaseUserCreationForm(data)
        self.assertFalse(form.is_valid())
        self.assertEqual(
            form["password2"].errors, [str(form.error_messages["password_mismatch"])]
        )

    def test_both_passwords(self):
        
        data = {"username": "jsmith"}
        form = BaseUserCreationForm(data)
        required_error = [str(Field.default_error_messages["required"])]
        self.assertFalse(form.is_valid())
        self.assertEqual(form["password1"].errors, required_error)
        self.assertEqual(form["password2"].errors, required_error)

        data["password2"] = "test123"
        form = UserCreationForm(data)
        self.assertFalse(form.is_valid())
        self.assertEqual(form["password1"].errors, required_error)
        self.assertEqual(form["password2"].errors, [])

    @mock.patch("django.contrib.auth.password_validation.password_changed")
    def test_success(self, password_changed):
        
        data = {
            "username": "jsmith@example.com",
            "password1": "test123",
            "password2": "test123",
        }
        form = BaseUserCreationForm(data)
        self.assertTrue(form.is_valid())
        form.save(commit=False)
        self.assertEqual(password_changed.call_count, 0)
        u = form.save()
        self.assertEqual(password_changed.call_count, 1)
        self.assertEqual(repr(u), "<User: jsmith@example.com>")

    def test_unicode_username(self):
        data = {
            "username": "宝",
            "password1": "test123",
            "password2": "test123",
        }
        form = BaseUserCreationForm(data)
        self.assertTrue(form.is_valid())
        u = form.save()
        self.assertEqual(u.username, "宝")

    def test_normalize_username(self):
        
        
        ohm_username = "testΩ"  
        data = {
            "username": ohm_username,
            "password1": "pwd2",
            "password2": "pwd2",
        }
        form = BaseUserCreationForm(data)
        self.assertTrue(form.is_valid())
        user = form.save()
        self.assertNotEqual(user.username, ohm_username)
        self.assertEqual(user.username, "testΩ")  

    def test_invalid_username_no_normalize(self):
        field = UsernameField(max_length=254)
        
        self.assertEqual(field.to_python("½" * 255), "½" * 255)
        self.assertEqual(field.to_python("ﬀ" * 254), "ff" * 254)

    def test_duplicate_normalized_unicode(self):
        
        omega_username = "iamtheΩ"  
        ohm_username = "iamtheΩ"  
        self.assertNotEqual(omega_username, ohm_username)
        User.objects.create_user(username=omega_username, password="pwd")
        data = {
            "username": ohm_username,
            "password1": "pwd2",
            "password2": "pwd2",
        }
        form = BaseUserCreationForm(data)
        self.assertFalse(form.is_valid())
        self.assertEqual(
            form.errors["username"], ["A user with that username already exists."]
        )

    @override_settings(
        AUTH_PASSWORD_VALIDATORS=[
            {
                "NAME": (
                    "django.contrib.auth.password_validation."
                    "UserAttributeSimilarityValidator"
                )
            },
            {
                "NAME": (
                    "django.contrib.auth.password_validation.MinimumLengthValidator"
                ),
                "OPTIONS": {
                    "min_length": 12,
                },
            },
        ]
    )
    def test_validates_password(self):
        data = {
            "username": "testclient",
            "password1": "testclient",
            "password2": "testclient",
        }
        form = BaseUserCreationForm(data)
        self.assertFalse(form.is_valid())
        self.assertEqual(len(form["password2"].errors), 2)
        self.assertIn(
            "The password is too similar to the username.", form["password2"].errors
        )
        self.assertIn(
            "This password is too short. It must contain at least 12 characters.",
            form["password2"].errors,
        )

    def test_custom_form(self):
        class CustomUserCreationForm(BaseUserCreationForm):
            class Meta(BaseUserCreationForm.Meta):
                model = ExtensionUser
                fields = UserCreationForm.Meta.fields + ("date_of_birth",)

        data = {
            "username": "testclient",
            "password1": "testclient",
            "password2": "testclient",
            "date_of_birth": "1988-02-24",
        }
        form = CustomUserCreationForm(data)
        self.assertTrue(form.is_valid())

    def test_custom_form_with_different_username_field(self):
        class CustomUserCreationForm(BaseUserCreationForm):
            class Meta(BaseUserCreationForm.Meta):
                model = CustomUser
                fields = ("email", "date_of_birth")

        data = {
            "email": "test@client222.com",
            "password1": "testclient",
            "password2": "testclient",
            "date_of_birth": "1988-02-24",
        }
        form = CustomUserCreationForm(data)
        self.assertTrue(form.is_valid())

    def test_custom_form_hidden_username_field(self):
        class CustomUserCreationForm(BaseUserCreationForm):
            class Meta(BaseUserCreationForm.Meta):
                model = CustomUserWithoutIsActiveField
                fields = ("email",)  

        data = {
            "email": "testclient@example.com",
            "password1": "testclient",
            "password2": "testclient",
        }
        form = CustomUserCreationForm(data)
        self.assertTrue(form.is_valid())

    def test_custom_form_saves_many_to_many_field(self):
        class CustomUserCreationForm(BaseUserCreationForm):
            class Meta(BaseUserCreationForm.Meta):
                model = CustomUserWithM2M
                fields = UserCreationForm.Meta.fields + ("orgs",)

        organization = Organization.objects.create(name="organization 1")

        data = {
            "username": "testclient@example.com",
            "password1": "testclient",
            "password2": "testclient",
            "orgs": [str(organization.pk)],
        }
        form = CustomUserCreationForm(data)
        self.assertIs(form.is_valid(), True)
        user = form.save(commit=True)
        self.assertSequenceEqual(user.orgs.all(), [organization])

    def test_password_whitespace_not_stripped(self):
        data = {
            "username": "testuser",
            "password1": "   testpassword   ",
            "password2": "   testpassword   ",
        }
        form = BaseUserCreationForm(data)
        self.assertTrue(form.is_valid())
        self.assertEqual(form.cleaned_data["password1"], data["password1"])
        self.assertEqual(form.cleaned_data["password2"], data["password2"])

    @override_settings(
        AUTH_PASSWORD_VALIDATORS=[
            {
                "NAME": (
                    "django.contrib.auth.password_validation."
                    "UserAttributeSimilarityValidator"
                )
            },
        ]
    )
    def test_password_help_text(self):
        form = BaseUserCreationForm()
        self.assertEqual(
            form.fields["password1"].help_text,
            "<ul><li>"
            "Your password can’t be too similar to your other personal information."
            "</li></ul>",
        )

    @override_settings(
        AUTH_PASSWORD_VALIDATORS=[
            {
                "NAME": (
                    "django.contrib.auth.password_validation."
                    "UserAttributeSimilarityValidator"
                )
            },
        ]
    )
    def test_user_create_form_validates_password_with_all_data(self):
        

        class CustomUserCreationForm(BaseUserCreationForm):
            class Meta(BaseUserCreationForm.Meta):
                model = User
                fields = ("username", "email", "first_name", "last_name")

        form = CustomUserCreationForm(
            {
                "username": "testuser",
                "password1": "testpassword",
                "password2": "testpassword",
                "first_name": "testpassword",
                "last_name": "lastname",
            }
        )
        self.assertFalse(form.is_valid())
        self.assertEqual(
            form.errors["password2"],
            ["The password is too similar to the first name."],
        )

    def test_username_field_autocapitalize_none(self):
        form = BaseUserCreationForm()
        self.assertEqual(
            form.fields["username"].widget.attrs.get("autocapitalize"), "none"
        )

    def test_html_autocomplete_attributes(self):
        form = BaseUserCreationForm()
        tests = (
            ("username", "username"),
            ("password1", "new-password"),
            ("password2", "new-password"),
        )
        for field_name, autocomplete in tests:
            with self.subTest(field_name=field_name, autocomplete=autocomplete):
                self.assertEqual(
                    form.fields[field_name].widget.attrs["autocomplete"], autocomplete
                )


class UserCreationFormTest(TestDataMixin, TestCase):
    def test_case_insensitive_username(self):
        data = {
            "username": "TeStClIeNt",
            "password1": "test123",
            "password2": "test123",
        }
        form = UserCreationForm(data)
        self.assertFalse(form.is_valid())
        self.assertEqual(
            form["username"].errors,
            ["A user with that username already exists."],
        )

    @override_settings(AUTH_USER_MODEL="auth_tests.ExtensionUser")
    def test_case_insensitive_username_custom_user_and_error_message(self):
        class CustomUserCreationForm(UserCreationForm):
            class Meta(UserCreationForm.Meta):
                model = ExtensionUser
                fields = UserCreationForm.Meta.fields + ("date_of_birth",)
                error_messages = {
                    "username": {"unique": "This username has already been taken."}
                }

        ExtensionUser.objects.create_user(
            username="testclient",
            password="password",
            email="testclient@example.com",
            date_of_birth=datetime.date(1984, 3, 5),
        )
        data = {
            "username": "TeStClIeNt",
            "password1": "test123",
            "password2": "test123",
            "date_of_birth": "1980-01-01",
        }
        form = CustomUserCreationForm(data)
        self.assertIs(form.is_valid(), False)
        self.assertEqual(
            form["username"].errors,
            ["This username has already been taken."],
        )




@override_settings(
    AUTHENTICATION_BACKENDS=["django.contrib.auth.backends.AllowAllUsersModelBackend"]
)
class AuthenticationFormTest(TestDataMixin, TestCase):
    def test_invalid_username(self):
        

        data = {
            "username": "jsmith_does_not_exist",
            "password": "test123",
        }
        form = AuthenticationForm(None, data)
        self.assertFalse(form.is_valid())
        self.assertEqual(
            form.non_field_errors(),
            [
                form.error_messages["invalid_login"]
                % {"username": User._meta.get_field("username").verbose_name}
            ],
        )

    def test_inactive_user(self):
        
        data = {
            "username": "inactive",
            "password": "password",
        }
        form = AuthenticationForm(None, data)
        self.assertFalse(form.is_valid())
        self.assertEqual(
            form.non_field_errors(), [str(form.error_messages["inactive"])]
        )

    
    @override_settings(
        AUTHENTICATION_BACKENDS=["django.contrib.auth.backends.ModelBackend"]
    )
    def test_inactive_user_incorrect_password(self):
        
        data = {
            "username": "inactive",
            "password": "incorrect",
        }
        form = AuthenticationForm(None, data)
        self.assertFalse(form.is_valid())
        self.assertEqual(
            form.non_field_errors(),
            [
                form.error_messages["invalid_login"]
                % {"username": User._meta.get_field("username").verbose_name}
            ],
        )

    def test_login_failed(self):
        signal_calls = []

        def signal_handler(**kwargs):
            signal_calls.append(kwargs)

        user_login_failed.connect(signal_handler)
        fake_request = object()
        try:
            form = AuthenticationForm(
                fake_request,
                {
                    "username": "testclient",
                    "password": "incorrect",
                },
            )
            self.assertFalse(form.is_valid())
            self.assertIs(signal_calls[0]["request"], fake_request)
        finally:
            user_login_failed.disconnect(signal_handler)

    def test_inactive_user_i18n(self):
        with self.settings(USE_I18N=True), translation.override(
            "pt-br", deactivate=True
        ):
            
            data = {
                "username": "inactive",
                "password": "password",
            }
            form = AuthenticationForm(None, data)
            self.assertFalse(form.is_valid())
            self.assertEqual(
                form.non_field_errors(), [str(form.error_messages["inactive"])]
            )

    
    @override_settings(
        AUTHENTICATION_BACKENDS=[
            "django.contrib.auth.backends.AllowAllUsersModelBackend"
        ]
    )
    def test_custom_login_allowed_policy(self):
        
        data = {
            "username": "inactive",
            "password": "password",
        }

        class AuthenticationFormWithInactiveUsersOkay(AuthenticationForm):
            def confirm_login_allowed(self, user):
                pass

        form = AuthenticationFormWithInactiveUsersOkay(None, data)
        self.assertTrue(form.is_valid())

        
        
        class PickyAuthenticationForm(AuthenticationForm):
            def confirm_login_allowed(self, user):
                if user.username == "inactive":
                    raise ValidationError("This user is disallowed.")
                raise ValidationError("Sorry, nobody's allowed in.")

        form = PickyAuthenticationForm(None, data)
        self.assertFalse(form.is_valid())
        self.assertEqual(form.non_field_errors(), ["This user is disallowed."])

        data = {
            "username": "testclient",
            "password": "password",
        }
        form = PickyAuthenticationForm(None, data)
        self.assertFalse(form.is_valid())
        self.assertEqual(form.non_field_errors(), ["Sorry, nobody's allowed in."])

    def test_success(self):
        
        data = {
            "username": "testclient",
            "password": "password",
        }
        form = AuthenticationForm(None, data)
        self.assertTrue(form.is_valid())
        self.assertEqual(form.non_field_errors(), [])

    def test_unicode_username(self):
        User.objects.create_user(username="Σαρα", password="pwd")
        data = {
            "username": "Σαρα",
            "password": "pwd",
        }
        form = AuthenticationForm(None, data)
        self.assertTrue(form.is_valid())
        self.assertEqual(form.non_field_errors(), [])

    @override_settings(AUTH_USER_MODEL="auth_tests.CustomEmailField")
    def test_username_field_max_length_matches_user_model(self):
        self.assertEqual(CustomEmailField._meta.get_field("username").max_length, 255)
        data = {
            "username": "u" * 255,
            "password": "pwd",
            "email": "test@example.com",
        }
        CustomEmailField.objects.create_user(**data)
        form = AuthenticationForm(None, data)
        self.assertEqual(form.fields["username"].max_length, 255)
        self.assertEqual(form.fields["username"].widget.attrs.get("maxlength"), 255)
        self.assertEqual(form.errors, {})

    @override_settings(AUTH_USER_MODEL="auth_tests.IntegerUsernameUser")
    def test_username_field_max_length_defaults_to_254(self):
        self.assertIsNone(IntegerUsernameUser._meta.get_field("username").max_length)
        data = {
            "username": "0123456",
            "password": "password",
        }
        IntegerUsernameUser.objects.create_user(**data)
        form = AuthenticationForm(None, data)
        self.assertEqual(form.fields["username"].max_length, 254)
        self.assertEqual(form.fields["username"].widget.attrs.get("maxlength"), 254)
        self.assertEqual(form.errors, {})

    def test_username_field_label(self):
        class CustomAuthenticationForm(AuthenticationForm):
            username = CharField(label="Name", max_length=75)

        form = CustomAuthenticationForm()
        self.assertEqual(form["username"].label, "Name")

    def test_username_field_label_not_set(self):
        class CustomAuthenticationForm(AuthenticationForm):
            username = CharField()

        form = CustomAuthenticationForm()
        username_field = User._meta.get_field(User.USERNAME_FIELD)
        self.assertEqual(
            form.fields["username"].label, capfirst(username_field.verbose_name)
        )

    def test_username_field_autocapitalize_none(self):
        form = AuthenticationForm()
        self.assertEqual(
            form.fields["username"].widget.attrs.get("autocapitalize"), "none"
        )

    def test_username_field_label_empty_string(self):
        class CustomAuthenticationForm(AuthenticationForm):
            username = CharField(label="")

        form = CustomAuthenticationForm()
        self.assertEqual(form.fields["username"].label, "")

    def test_password_whitespace_not_stripped(self):
        data = {
            "username": "testuser",
            "password": " pass ",
        }
        form = AuthenticationForm(None, data)
        form.is_valid()  
        self.assertEqual(form.cleaned_data["password"], data["password"])

    @override_settings(AUTH_USER_MODEL="auth_tests.IntegerUsernameUser")
    def test_integer_username(self):
        class CustomAuthenticationForm(AuthenticationForm):
            username = IntegerField()

        user = IntegerUsernameUser.objects.create_user(username=0, password="pwd")
        data = {
            "username": 0,
            "password": "pwd",
        }
        form = CustomAuthenticationForm(None, data)
        self.assertTrue(form.is_valid())
        self.assertEqual(form.cleaned_data["username"], data["username"])
        self.assertEqual(form.cleaned_data["password"], data["password"])
        self.assertEqual(form.errors, {})
        self.assertEqual(form.user_cache, user)

    def test_get_invalid_login_error(self):
        error = AuthenticationForm().get_invalid_login_error()
        self.assertIsInstance(error, ValidationError)
        self.assertEqual(
            error.message,
            "Please enter a correct %(username)s and password. Note that both "
            "fields may be case-sensitive.",
        )
        self.assertEqual(error.code, "invalid_login")
        self.assertEqual(error.params, {"username": "username"})

    def test_html_autocomplete_attributes(self):
        form = AuthenticationForm()
        tests = (
            ("username", "username"),
            ("password", "current-password"),
        )
        for field_name, autocomplete in tests:
            with self.subTest(field_name=field_name, autocomplete=autocomplete):
                self.assertEqual(
                    form.fields[field_name].widget.attrs["autocomplete"], autocomplete
                )

    def test_no_password(self):
        data = {"username": "username"}
        form = AuthenticationForm(None, data)
        self.assertIs(form.is_valid(), False)
        self.assertEqual(
            form["password"].errors, [Field.default_error_messages["required"]]
        )


class SetPasswordFormTest(TestDataMixin, TestCase):
    def test_password_verification(self):
        
        user = User.objects.get(username="testclient")
        data = {
            "new_password1": "abc123",
            "new_password2": "abc",
        }
        form = SetPasswordForm(user, data)
        self.assertFalse(form.is_valid())
        self.assertEqual(
            form["new_password2"].errors,
            [str(form.error_messages["password_mismatch"])],
        )

    @mock.patch("django.contrib.auth.password_validation.password_changed")
    def test_success(self, password_changed):
        user = User.objects.get(username="testclient")
        data = {
            "new_password1": "abc123",
            "new_password2": "abc123",
        }
        form = SetPasswordForm(user, data)
        self.assertTrue(form.is_valid())
        form.save(commit=False)
        self.assertEqual(password_changed.call_count, 0)
        form.save()
        self.assertEqual(password_changed.call_count, 1)

    @override_settings(
        AUTH_PASSWORD_VALIDATORS=[
            {
                "NAME": (
                    "django.contrib.auth.password_validation."
                    "UserAttributeSimilarityValidator"
                )
            },
            {
                "NAME": (
                    "django.contrib.auth.password_validation.MinimumLengthValidator"
                ),
                "OPTIONS": {
                    "min_length": 12,
                },
            },
        ]
    )
    def test_validates_password(self):
        user = User.objects.get(username="testclient")
        data = {
            "new_password1": "testclient",
            "new_password2": "testclient",
        }
        form = SetPasswordForm(user, data)
        self.assertFalse(form.is_valid())
        self.assertEqual(len(form["new_password2"].errors), 2)
        self.assertIn(
            "The password is too similar to the username.", form["new_password2"].errors
        )
        self.assertIn(
            "This password is too short. It must contain at least 12 characters.",
            form["new_password2"].errors,
        )

    def test_no_password(self):
        user = User.objects.get(username="testclient")
        data = {"new_password1": "new-password"}
        form = SetPasswordForm(user, data)
        self.assertIs(form.is_valid(), False)
        self.assertEqual(
            form["new_password2"].errors, [Field.default_error_messages["required"]]
        )
        form = SetPasswordForm(user, {})
        self.assertIs(form.is_valid(), False)
        self.assertEqual(
            form["new_password1"].errors, [Field.default_error_messages["required"]]
        )
        self.assertEqual(
            form["new_password2"].errors, [Field.default_error_messages["required"]]
        )

    def test_password_whitespace_not_stripped(self):
        user = User.objects.get(username="testclient")
        data = {
            "new_password1": "   password   ",
            "new_password2": "   password   ",
        }
        form = SetPasswordForm(user, data)
        self.assertTrue(form.is_valid())
        self.assertEqual(form.cleaned_data["new_password1"], data["new_password1"])
        self.assertEqual(form.cleaned_data["new_password2"], data["new_password2"])

    @override_settings(
        AUTH_PASSWORD_VALIDATORS=[
            {
                "NAME": (
                    "django.contrib.auth.password_validation."
                    "UserAttributeSimilarityValidator"
                )
            },
            {
                "NAME": (
                    "django.contrib.auth.password_validation.MinimumLengthValidator"
                ),
                "OPTIONS": {
                    "min_length": 12,
                },
            },
        ]
    )
    def test_help_text_translation(self):
        french_help_texts = [
            "Votre mot de passe ne peut pas trop ressembler à vos autres informations "
            "personnelles.",
            "Votre mot de passe doit contenir au minimum 12 caractères.",
        ]
        form = SetPasswordForm(self.u1)
        with translation.override("fr"):
            html = form.as_p()
            for french_text in french_help_texts:
                self.assertIn(french_text, html)

    def test_html_autocomplete_attributes(self):
        form = SetPasswordForm(self.u1)
        tests = (
            ("new_password1", "new-password"),
            ("new_password2", "new-password"),
        )
        for field_name, autocomplete in tests:
            with self.subTest(field_name=field_name, autocomplete=autocomplete):
                self.assertEqual(
                    form.fields[field_name].widget.attrs["autocomplete"], autocomplete
                )


class PasswordChangeFormTest(TestDataMixin, TestCase):
    def test_incorrect_password(self):
        user = User.objects.get(username="testclient")
        data = {
            "old_password": "test",
            "new_password1": "abc123",
            "new_password2": "abc123",
        }
        form = PasswordChangeForm(user, data)
        self.assertFalse(form.is_valid())
        self.assertEqual(
            form["old_password"].errors,
            [str(form.error_messages["password_incorrect"])],
        )

    def test_password_verification(self):
        
        user = User.objects.get(username="testclient")
        data = {
            "old_password": "password",
            "new_password1": "abc123",
            "new_password2": "abc",
        }
        form = PasswordChangeForm(user, data)
        self.assertFalse(form.is_valid())
        self.assertEqual(
            form["new_password2"].errors,
            [str(form.error_messages["password_mismatch"])],
        )

    @mock.patch("django.contrib.auth.password_validation.password_changed")
    def test_success(self, password_changed):
        
        user = User.objects.get(username="testclient")
        data = {
            "old_password": "password",
            "new_password1": "abc123",
            "new_password2": "abc123",
        }
        form = PasswordChangeForm(user, data)
        self.assertTrue(form.is_valid())
        form.save(commit=False)
        self.assertEqual(password_changed.call_count, 0)
        form.save()
        self.assertEqual(password_changed.call_count, 1)

    def test_field_order(self):
        
        user = User.objects.get(username="testclient")
        self.assertEqual(
            list(PasswordChangeForm(user, {}).fields),
            ["old_password", "new_password1", "new_password2"],
        )

    def test_password_whitespace_not_stripped(self):
        user = User.objects.get(username="testclient")
        user.set_password("   oldpassword   ")
        data = {
            "old_password": "   oldpassword   ",
            "new_password1": " pass ",
            "new_password2": " pass ",
        }
        form = PasswordChangeForm(user, data)
        self.assertTrue(form.is_valid())
        self.assertEqual(form.cleaned_data["old_password"], data["old_password"])
        self.assertEqual(form.cleaned_data["new_password1"], data["new_password1"])
        self.assertEqual(form.cleaned_data["new_password2"], data["new_password2"])

    def test_html_autocomplete_attributes(self):
        user = User.objects.get(username="testclient")
        form = PasswordChangeForm(user)
        self.assertEqual(
            form.fields["old_password"].widget.attrs["autocomplete"], "current-password"
        )


class UserChangeFormTest(TestDataMixin, TestCase):
    def test_username_validity(self):
        user = User.objects.get(username="testclient")
        data = {"username": "not valid"}
        form = UserChangeForm(data, instance=user)
        self.assertFalse(form.is_valid())
        validator = next(
            v
            for v in User._meta.get_field("username").validators
            if v.code == "invalid"
        )
        self.assertEqual(form["username"].errors, [str(validator.message)])

    def test_bug_14242(self):
        
        

        class MyUserForm(UserChangeForm):
            def __init__(self, *args, **kwargs):
                super().__init__(*args, **kwargs)
                self.fields[
                    "groups"
                ].help_text = "These groups give users different permissions"

            class Meta(UserChangeForm.Meta):
                fields = ("groups",)

        
        MyUserForm({})

    def test_unusable_password(self):
        user = User.objects.get(username="empty_password")
        user.set_unusable_password()
        user.save()
        form = UserChangeForm(instance=user)
        self.assertIn(_("No password set."), form.as_table())

    def test_bug_17944_empty_password(self):
        user = User.objects.get(username="empty_password")
        form = UserChangeForm(instance=user)
        self.assertIn(_("No password set."), form.as_table())

    def test_bug_17944_unmanageable_password(self):
        user = User.objects.get(username="unmanageable_password")
        form = UserChangeForm(instance=user)
        self.assertIn(
            _("Invalid password format or unknown hashing algorithm."), form.as_table()
        )

    def test_bug_17944_unknown_password_algorithm(self):
        user = User.objects.get(username="unknown_password")
        form = UserChangeForm(instance=user)
        self.assertIn(
            _("Invalid password format or unknown hashing algorithm."), form.as_table()
        )

    def test_bug_19133(self):
        "The change form does not return the password value"
        
        user = User.objects.get(username="testclient")
        form_for_data = UserChangeForm(instance=user)
        post_data = form_for_data.initial

        
        
        
        
        post_data["password"] = "new password"
        form = UserChangeForm(instance=user, data=post_data)

        self.assertTrue(form.is_valid())
        
        self.assertIn("$", form.cleaned_data["password"])

    def test_bug_19349_bound_password_field(self):
        user = User.objects.get(username="testclient")
        form = UserChangeForm(data={}, instance=user)
        
        
        
        self.assertEqual(form.initial["password"], form["password"].value())

    @override_settings(ROOT_URLCONF="auth_tests.urls_admin")
    def test_link_to_password_reset_in_helptext_via_to_field(self):
        user = User.objects.get(username="testclient")
        form = UserChangeForm(data={}, instance=user)
        password_help_text = form.fields["password"].help_text
        matches = re.search('<a href="(.*?)">', password_help_text)

        
        admin_user_change_url = reverse(
            f"admin:{user._meta.app_label}_{user._meta.model_name}_change",
            args=(user.username,),
        )
        joined_url = urllib.parse.urljoin(admin_user_change_url, matches.group(1))

        pw_change_url = reverse(
            f"admin:{user._meta.app_label}_{user._meta.model_name}_password_change",
            args=(user.pk,),
        )
        self.assertEqual(joined_url, pw_change_url)

    def test_custom_form(self):
        class CustomUserChangeForm(UserChangeForm):
            class Meta(UserChangeForm.Meta):
                model = ExtensionUser
                fields = (
                    "username",
                    "password",
                    "date_of_birth",
                )

        user = User.objects.get(username="testclient")
        data = {
            "username": "testclient",
            "password": "testclient",
            "date_of_birth": "1998-02-24",
        }
        form = CustomUserChangeForm(data, instance=user)
        self.assertTrue(form.is_valid())
        form.save()
        self.assertEqual(form.cleaned_data["username"], "testclient")
        self.assertEqual(form.cleaned_data["date_of_birth"], datetime.date(1998, 2, 24))

    def test_password_excluded(self):
        class UserChangeFormWithoutPassword(UserChangeForm):
            password = None

            class Meta:
                model = User
                exclude = ["password"]

        form = UserChangeFormWithoutPassword()
        self.assertNotIn("password", form.fields)

    def test_username_field_autocapitalize_none(self):
        form = UserChangeForm()
        self.assertEqual(
            form.fields["username"].widget.attrs.get("autocapitalize"), "none"
        )


@override_settings(TEMPLATES=AUTH_TEMPLATES)
class PasswordResetFormTest(TestDataMixin, TestCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        
        
        Site.objects.clear_cache()

    def create_dummy_user(self):
        
        username = "jsmith"
        email = "jsmith@example.com"
        user = User.objects.create_user(username, email, "test123")
        return (user, username, email)

    def test_invalid_email(self):
        data = {"email": "not valid"}
        form = PasswordResetForm(data)
        self.assertFalse(form.is_valid())
        self.assertEqual(form["email"].errors, [_("Enter a valid email address.")])

    def test_user_email_unicode_collision(self):
        User.objects.create_user("mike123", "mike@example.org", "test123")
        User.objects.create_user("mike456", "mıke@example.org", "test123")
        data = {"email": "mıke@example.org"}
        form = PasswordResetForm(data)
        self.assertTrue(form.is_valid())
        form.save()
        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(mail.outbox[0].to, ["mıke@example.org"])

    def test_user_email_domain_unicode_collision(self):
        User.objects.create_user("mike123", "mike@ixample.org", "test123")
        User.objects.create_user("mike456", "mike@ıxample.org", "test123")
        data = {"email": "mike@ıxample.org"}
        form = PasswordResetForm(data)
        self.assertTrue(form.is_valid())
        form.save()
        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(mail.outbox[0].to, ["mike@ıxample.org"])

    def test_user_email_unicode_collision_nonexistent(self):
        User.objects.create_user("mike123", "mike@example.org", "test123")
        data = {"email": "mıke@example.org"}
        form = PasswordResetForm(data)
        self.assertTrue(form.is_valid())
        form.save()
        self.assertEqual(len(mail.outbox), 0)

    def test_user_email_domain_unicode_collision_nonexistent(self):
        User.objects.create_user("mike123", "mike@ixample.org", "test123")
        data = {"email": "mike@ıxample.org"}
        form = PasswordResetForm(data)
        self.assertTrue(form.is_valid())
        form.save()
        self.assertEqual(len(mail.outbox), 0)

    def test_nonexistent_email(self):
        
        data = {"email": "foo@bar.com"}
        form = PasswordResetForm(data)
        self.assertTrue(form.is_valid())
        self.assertEqual(len(mail.outbox), 0)

    def test_cleaned_data(self):
        (user, username, email) = self.create_dummy_user()
        data = {"email": email}
        form = PasswordResetForm(data)
        self.assertTrue(form.is_valid())
        form.save(domain_override="example.com")
        self.assertEqual(form.cleaned_data["email"], email)
        self.assertEqual(len(mail.outbox), 1)

    def test_custom_email_subject(self):
        data = {"email": "testclient@example.com"}
        form = PasswordResetForm(data)
        self.assertTrue(form.is_valid())
        
        
        
        form.save(domain_override="example.com")
        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(mail.outbox[0].subject, "Custom password reset on example.com")

    def test_custom_email_constructor(self):
        data = {"email": "testclient@example.com"}

        class CustomEmailPasswordResetForm(PasswordResetForm):
            def send_mail(
                self,
                subject_template_name,
                email_template_name,
                context,
                from_email,
                to_email,
                html_email_template_name=None,
            ):
                EmailMultiAlternatives(
                    "Forgot your password?",
                    "Sorry to hear you forgot your password.",
                    None,
                    [to_email],
                    ["site_monitor@example.com"],
                    headers={"Reply-To": "webmaster@example.com"},
                    alternatives=[
                        ("Really sorry to hear you forgot your password.", "text/html")
                    ],
                ).send()

        form = CustomEmailPasswordResetForm(data)
        self.assertTrue(form.is_valid())
        
        
        
        form.save(domain_override="example.com")
        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(mail.outbox[0].subject, "Forgot your password?")
        self.assertEqual(mail.outbox[0].bcc, ["site_monitor@example.com"])
        self.assertEqual(mail.outbox[0].content_subtype, "plain")

    def test_preserve_username_case(self):
        
        user = User.objects.create_user("forms_test2", "tesT@EXAMple.com", "test")
        self.assertEqual(user.email, "tesT@example.com")
        user = User.objects.create_user("forms_test3", "tesT", "test")
        self.assertEqual(user.email, "tesT")

    def test_inactive_user(self):
        
        (user, username, email) = self.create_dummy_user()
        user.is_active = False
        user.save()
        form = PasswordResetForm({"email": email})
        self.assertTrue(form.is_valid())
        form.save()
        self.assertEqual(len(mail.outbox), 0)

    def test_unusable_password(self):
        user = User.objects.create_user("testuser", "test@example.com", "test")
        data = {"email": "test@example.com"}
        form = PasswordResetForm(data)
        self.assertTrue(form.is_valid())
        user.set_unusable_password()
        user.save()
        form = PasswordResetForm(data)
        
        self.assertTrue(form.is_valid())
        form.save()
        self.assertEqual(len(mail.outbox), 0)

    def test_save_plaintext_email(self):
        
        (user, username, email) = self.create_dummy_user()
        form = PasswordResetForm({"email": email})
        self.assertTrue(form.is_valid())
        form.save()
        self.assertEqual(len(mail.outbox), 1)
        message = mail.outbox[0].message()
        self.assertFalse(message.is_multipart())
        self.assertEqual(message.get_content_type(), "text/plain")
        self.assertEqual(message.get("subject"), "Custom password reset on example.com")
        self.assertEqual(len(mail.outbox[0].alternatives), 0)
        self.assertEqual(message.get_all("to"), [email])
        self.assertTrue(
            re.match(r"^http://example.com/reset/[\w+/-]", message.get_payload())
        )

    def test_save_html_email_template_name(self):
        
        (user, username, email) = self.create_dummy_user()
        form = PasswordResetForm({"email": email})
        self.assertTrue(form.is_valid())
        form.save(
            html_email_template_name="registration/html_password_reset_email.html"
        )
        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(len(mail.outbox[0].alternatives), 1)
        message = mail.outbox[0].message()
        self.assertEqual(message.get("subject"), "Custom password reset on example.com")
        self.assertEqual(len(message.get_payload()), 2)
        self.assertTrue(message.is_multipart())
        self.assertEqual(message.get_payload(0).get_content_type(), "text/plain")
        self.assertEqual(message.get_payload(1).get_content_type(), "text/html")
        self.assertEqual(message.get_all("to"), [email])
        self.assertTrue(
            re.match(
                r"^http://example.com/reset/[\w/-]+",
                message.get_payload(0).get_payload(),
            )
        )
        self.assertTrue(
            re.match(
                r'^<html><a href="http://example.com/reset/[\w/-]+/">Link</a></html>$',
                message.get_payload(1).get_payload(),
            )
        )

    @override_settings(AUTH_USER_MODEL="auth_tests.CustomEmailField")
    def test_custom_email_field(self):
        email = "test@mail.com"
        CustomEmailField.objects.create_user("test name", "test password", email)
        form = PasswordResetForm({"email": email})
        self.assertTrue(form.is_valid())
        form.save()
        self.assertEqual(form.cleaned_data["email"], email)
        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(mail.outbox[0].to, [email])

    def test_html_autocomplete_attributes(self):
        form = PasswordResetForm()
        self.assertEqual(form.fields["email"].widget.attrs["autocomplete"], "email")


class ReadOnlyPasswordHashTest(SimpleTestCase):
    def test_bug_19349_render_with_none_value(self):
        
        
        widget = ReadOnlyPasswordHashWidget()
        html = widget.render(name="password", value=None, attrs={})
        self.assertIn(_("No password set."), html)

    @override_settings(
        PASSWORD_HASHERS=["django.contrib.auth.hashers.PBKDF2PasswordHasher"]
    )
    def test_render(self):
        widget = ReadOnlyPasswordHashWidget()
        value = (
            "pbkdf2_sha256$100000$a6Pucb1qSFcD$WmCkn9Hqidj48NVe5x0FEM6A9YiOqQcl/83m2Z5u"
            "dm0="
        )
        self.assertHTMLEqual(
            widget.render("name", value, {"id": "id_password"}),
            '<div id="id_password">'
            "    <strong>algorithm</strong>: <bdi>pbkdf2_sha256</bdi>"
            "    <strong>iterations</strong>: <bdi>100000</bdi>"
            "    <strong>salt</strong>: <bdi>a6Pucb******</bdi>"
            "    <strong>hash</strong>: "
            "       <bdi>WmCkn9**************************************</bdi>"
            "</div>",
        )

    def test_readonly_field_has_changed(self):
        field = ReadOnlyPasswordHashField()
        self.assertIs(field.disabled, True)
        self.assertFalse(field.has_changed("aaa", "bbb"))

    def test_label(self):
        

        class TestForm(forms.Form):
            hash_field = ReadOnlyPasswordHashField()

        bound_field = TestForm()["hash_field"]
        self.assertIsNone(bound_field.field.widget.id_for_label("id"))
        self.assertEqual(bound_field.label_tag(), "<label>Hash field:</label>")


class AdminPasswordChangeFormTest(TestDataMixin, TestCase):
    @mock.patch("django.contrib.auth.password_validation.password_changed")
    def test_success(self, password_changed):
        user = User.objects.get(username="testclient")
        data = {
            "password1": "test123",
            "password2": "test123",
        }
        form = AdminPasswordChangeForm(user, data)
        self.assertTrue(form.is_valid())
        form.save(commit=False)
        self.assertEqual(password_changed.call_count, 0)
        form.save()
        self.assertEqual(password_changed.call_count, 1)
        self.assertEqual(form.changed_data, ["password"])

    def test_password_whitespace_not_stripped(self):
        user = User.objects.get(username="testclient")
        data = {
            "password1": " pass ",
            "password2": " pass ",
        }
        form = AdminPasswordChangeForm(user, data)
        self.assertTrue(form.is_valid())
        self.assertEqual(form.cleaned_data["password1"], data["password1"])
        self.assertEqual(form.cleaned_data["password2"], data["password2"])
        self.assertEqual(form.changed_data, ["password"])

    def test_non_matching_passwords(self):
        user = User.objects.get(username="testclient")
        data = {"password1": "password1", "password2": "password2"}
        form = AdminPasswordChangeForm(user, data)
        self.assertEqual(
            form.errors["password2"], [form.error_messages["password_mismatch"]]
        )
        self.assertEqual(form.changed_data, ["password"])

    def test_missing_passwords(self):
        user = User.objects.get(username="testclient")
        data = {"password1": "", "password2": ""}
        form = AdminPasswordChangeForm(user, data)
        required_error = [Field.default_error_messages["required"]]
        self.assertEqual(form.errors["password1"], required_error)
        self.assertEqual(form.errors["password2"], required_error)
        self.assertEqual(form.changed_data, [])

    def test_one_password(self):
        user = User.objects.get(username="testclient")
        form1 = AdminPasswordChangeForm(user, {"password1": "", "password2": "test"})
        required_error = [Field.default_error_messages["required"]]
        self.assertEqual(form1.errors["password1"], required_error)
        self.assertNotIn("password2", form1.errors)
        self.assertEqual(form1.changed_data, [])
        form2 = AdminPasswordChangeForm(user, {"password1": "test", "password2": ""})
        self.assertEqual(form2.errors["password2"], required_error)
        self.assertNotIn("password1", form2.errors)
        self.assertEqual(form2.changed_data, [])

    def test_html_autocomplete_attributes(self):
        user = User.objects.get(username="testclient")
        form = AdminPasswordChangeForm(user)
        tests = (
            ("password1", "new-password"),
            ("password2", "new-password"),
        )
        for field_name, autocomplete in tests:
            with self.subTest(field_name=field_name, autocomplete=autocomplete):
                self.assertEqual(
                    form.fields[field_name].widget.attrs["autocomplete"], autocomplete
                )