Opened 2 weeks ago

Closed 11 days ago

Last modified 10 days ago

#36140 closed Bug (fixed)

UserCreationForm doesn't allow empty password even if password fields are specified as "not required"

Reported by: buffgecko12 Owned by: Natalia Bidart
Component: contrib.auth Version: 5.1
Severity: Release blocker Keywords: form usercreationform validation
Cc: buffgecko12, Fabian Braun, Antoliny Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by buffgecko12)

There was a change made to UserCreationForm (django.contrib.auth.forms) in Django 5.1 which seems to require a password to be provided even if the password1 / password2 fields are explicitly marked as required = False. It looks like the validate_passwords() method is still being called even if the fields are marked as required = False.

Please see this issue for the details:

https://stackoverflow.com/questions/79387857/django-5-1-usercreationform-wont-allow-empty-passwords


I tried responding to your comment but the webpage won't let me submit my reply -- it says my submission is probably spam. Here's my response to your comment:

I would love to work on it, but I don't want to hold up the release. Please go ahead.

Change History (24)

comment:1 by Natalia Bidart, 2 weeks ago

Cc: Fabian Braun added
Component: Formscontrib.auth
Easy pickings: unset
Severity: NormalRelease blocker
Triage Stage: UnreviewedAccepted

Hello buffgecko12, thank you for your report. I think you are correct, this is a bug introduced in e626716c28b6286f8cf0f8174077f3d2244f3eb3 that should be addressed. Would you like to work on a PR?

comment:2 by buffgecko12, 2 weeks ago

Hi Natalia!! This is exciting, I have never modified the Django code before.

Do I just clone the Django Git repository, create / push my own branch to it, and submit a pull request?

https://github.com/django/django.git

What is the general procedure?

Chris

comment:3 by Antoliny, 2 weeks ago

I think these documents will be helpful for you.
Writing your first contribution for Django
Submitting contributions

comment:4 by buffgecko12, 2 weeks ago

Thank you. Is there a timeline for when this bug needs to be fixed and a PR submitted? Just to gauge if I am able to take this on or not.

in reply to:  4 comment:5 by Antoliny, 2 weeks ago

Replying to buffgecko12:

Thank you. Is there a timeline for when this bug needs to be fixed and a PR submitted? Just to gauge if I am able to take this on or not.

I'm not sure about the deadline. However, since this bug is a release blocker, I assume it might be a priority. (This is just my guess.)

comment:6 by Antoliny, 2 weeks ago

Cc: Antoliny added

comment:7 by Antoliny, 2 weeks ago

I looked into this issue.
I think this issue occurs because when usable_password key is not present in cleaned_data, the usable_password variable is set to True, causing the validation to be performed.

  • django/contrib/auth/forms.py

    diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py
    index cd177fa5b6..caddd6a672 100644
    a b class SetUnusablePasswordMixin:  
    200200        **kwargs,
    201201    ):
    202202        usable_password = (
    203             self.cleaned_data.pop(usable_password_field_name, None) != "false"
     203            (self.cleaned_data.get("password2", "") != "")
     204            or (self.cleaned_data.pop(usable_password_field_name, "false") != "false")
    204205        )
    205206        self.cleaned_data["set_usable_password"] = usable_password

I modified the default value as above and adjusted the usable_password assignment value based on the presence of password2. I'm not sure if this is the best solution, but I hope it helps you.

comment:8 by Antoliny, 2 weeks ago

This issue is related to passwords, I believe it should be designed as defensively as possible.
Unless there is a clear intention from the user (such as having usable_password set to None in the author's form), usable_password should remain True. This aspect is not covered in the above changes.

if hasattr(self, "usable_password") and self.usable_password == None:
    ...

I think there might be another condition needed as well.

comment:9 by Gregory Mariani, 2 weeks ago

test in test_forms.UserCreationFormTest could be something like that:

    def test_empty_passwords_with_required_false(self):
        class CustomUserCreationForm(UserCreationForm):
            password1 = CharField(required=False)
            password2 = CharField(required=False)

            class Meta(UserCreationForm.Meta):
                model = ExtensionUser

        form_data = {
            "username": "testuser",
            # 'password1' & 'password2' are not given
        }
        form = CustomUserCreationForm(data=form_data)
        self.assertTrue(form.is_valid())
        self.assertNotIn("password1", form.errors)
        self.assertNotIn("password2", form.errors)
Last edited 2 weeks ago by Gregory Mariani (previous) (diff)

in reply to:  4 comment:10 by Natalia Bidart, 2 weeks ago

Replying to buffgecko12:

Thank you. Is there a timeline for when this bug needs to be fixed and a PR submitted? Just to gauge if I am able to take this on or not.

As Antoliny says, this is a release blocker so we should have a solution ready by next week, when we have planned the next patch release for Django 5.1.

It's completely fine if you don't have time, me or someone else would grab this since it's a priority to get solved. Let me know so I start working on this!

comment:11 by buffgecko12, 2 weeks ago

Description: modified (diff)

comment:12 by Antoliny, 2 weeks ago

If it's okay, can I work on this ticket?
Nessita, if you want to work on it, please feel free to do so. I'd be happy to follow your lead!

Last edited 2 weeks ago by Antoliny (previous) (diff)

in reply to:  12 ; comment:13 by Natalia Bidart, 2 weeks ago

Replying to Antoliny:

If it's okay, can I work on this ticket?
Nessita, if you want to work on it, please feel free to do so. I'd be happy to follow your lead!

I'm taking a look to have an idea of the fix but you I would love if you work on this. Otherwise I could use another pair of eyes for what I'll propose. Right now I'm inclined to change the required=False in create_usable_password_field to be required=True and then tweak the checks in AdminPasswordChangeForm and AdminUserCreationForm. With that, which would be an "isolated" refactoring, there would be a second commit considering the required in password validation.

What do you think?

in reply to:  13 comment:14 by Antoliny, 2 weeks ago

Replying to Natalia Bidart:

Replying to Antoliny:

If it's okay, can I work on this ticket?
Nessita, if you want to work on it, please feel free to do so. I'd be happy to follow your lead!

I'm taking a look to have an idea of the fix but you I would love if you work on this. Otherwise I could use another pair of eyes for what I'll propose. Right now I'm inclined to change the required=False in create_usable_password_field to be required=True and then tweak the checks in AdminPasswordChangeForm and AdminUserCreationForm. With that, which would be an "isolated" refactoring, there would be a second commit considering the required in password validation.

What do you think?

I think it's a good approach. By changing required to True, the user will be able to clearly express their intent regarding the unusable_password.

comment:15 by Natalia Bidart, 2 weeks ago

Owner: set to Natalia Bidart
Status: newassigned

comment:16 by Natalia Bidart, 2 weeks ago

Has patch: set

comment:17 by Natalia Bidart, 13 days ago

@buffgecko12, could you please confirm if the proposed solution in this PR solves your issue?

comment:18 by Sarah Boyce, 12 days ago

Triage Stage: AcceptedReady for checkin

comment:19 by buffgecko12, 12 days ago

Yes, from a visual inspection it looks good.

How do I test the fix in my application? Do I just copy the new django/contrib/auth/forms.py file into my django directory?

I already have code in my application to work around the bug, so I'd need a little time to update the code and test as well.

in reply to:  19 comment:20 by Natalia Bidart, 11 days ago

Replying to buffgecko12:

Yes, from a visual inspection it looks good.

How do I test the fix in my application? Do I just copy the new django/contrib/auth/forms.py file into my django directory?

You can use a virtual env with Django installed via pip install -e, see further docs in this link.

comment:21 by GitHub <noreply@…>, 11 days ago

Resolution: fixed
Status: assignedclosed

In d15454a:

Fixed #36140 -- Allowed BaseUserCreationForm to define non required password fields.

Regression in e626716c28b6286f8cf0f8174077f3d2244f3eb3.

Thanks buffgecko12 for the report and Sarah Boyce for the review.

comment:22 by Natalia <124304+nessita@…>, 11 days ago

In affad13:

[5.2.x] Fixed #36140 -- Allowed BaseUserCreationForm to define non required password fields.

Regression in e626716c28b6286f8cf0f8174077f3d2244f3eb3.

Thanks buffgecko12 for the report and Sarah Boyce for the review.

Backport of d15454a6e84a595ffc8dc1b926282f484f782a8f from main.

comment:23 by Natalia <124304+nessita@…>, 11 days ago

In 8552eef:

[5.1.x] Fixed #36140 -- Allowed BaseUserCreationForm to define non required password fields.

Regression in e626716c28b6286f8cf0f8174077f3d2244f3eb3.

Thanks buffgecko12 for the report and Sarah Boyce for the review.

Backport of d15454a6e84a595ffc8dc1b926282f484f782a8f from main.

comment:24 by GitHub <noreply@…>, 10 days ago

In 328d54f:

[5.1.x] Refs #36140 -- Added missing import in django/contrib/auth/forms.py.

Follow up to 8552eef95e400d5bad3261b28ad2500b57070d57.

Note: See TracTickets for help on using tickets.
Back to Top