Commit 444bda0b authored by Luke Plant's avatar Luke Plant
Browse files

[1.2.X] Fixed #15075 - No longer possible to alter the form_list in FormWizard.process_step

Thanks to niels, stas for the report, and stas for the patch.

Backport of [15196] from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@15197 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 924bad82
Loading
Loading
Loading
Loading
+28 −1
Original line number Diff line number Diff line
@@ -146,6 +146,9 @@ class WizardPageOneForm(forms.Form):
class WizardPageTwoForm(forms.Form):
    field = forms.CharField()

class WizardPageTwoAlternativeForm(forms.Form):
    field = forms.CharField()

class WizardPageThreeForm(forms.Form):
    field = forms.CharField()

@@ -194,7 +197,8 @@ class WizardTests(TestCase):

    def test_14498(self):
        """
        Regression test for ticket #14498.
        Regression test for ticket #14498.  All previous steps' forms should be
        validated.
        """
        that = self
        reached = [False]
@@ -237,3 +241,26 @@ class WizardTests(TestCase):
                "wizard_step": "1"}
        wizard(DummyRequest(POST=data))
        self.assertTrue(reached[0])

    def test_15075(self):
        """
        Regression test for ticket #15075.  Allow modifying wizard's form_list
        in process_step.
        """
        that = self

        class WizardWithProcessStep(WizardClass):
            def process_step(self, request, form, step):
                if step == 0:
                    self.form_list[1] = WizardPageTwoAlternativeForm
                if step == 1:
                    that.assertTrue(isinstance(form, WizardPageTwoAlternativeForm))

        wizard = WizardWithProcessStep([WizardPageOneForm,
                                        WizardPageTwoForm,
                                        WizardPageThreeForm])
        data = {"0-field": "test",
                "1-field": "test2",
                "hash_0": "2fdbefd4c0cad51509478fbacddf8b13",
                "wizard_step": "1"}
        wizard(DummyRequest(POST=data))
+33 −30
Original line number Diff line number Diff line
@@ -68,35 +68,30 @@ class FormWizard(object):
        if current_step >= self.num_steps():
            raise Http404('Step %s does not exist' % current_step)

        # Process the current step. If it's valid, go to the next step or call
        # done(), depending on whether any steps remain.
        if request.method == 'POST':
            form = self.get_form(current_step, request.POST)
        else:
            form = self.get_form(current_step)
        # Validate and process all the previous forms before instantiating the
        # current step's form in case self.process_step makes changes to
        # self.form_list.

        if form.is_valid():
            # Validate all the forms. If any of them fail validation, that
            # must mean the validator relied on some other input, such as
            # an external Web site.

            # It is also possible that validation might fail under certain
            # attack situations: an attacker might be able to bypass previous
            # stages, and generate correct security hashes for all the
            # skipped stages by virtue of:
        # If any of them fails validation, that must mean the validator relied
        # on some other input, such as an external Web site.

        # It is also possible that alidation might fail under certain attack
        # situations: an attacker might be able to bypass previous stages, and
        # generate correct security hashes for all the skipped stages by virtue
        # of:
        #  1) having filled out an identical form which doesn't have the
        #     validation (and does something different at the end),
            #  2) or having filled out a previous version of the same form
            #     which had some validation missing,
            #  3) or previously having filled out the form when they had
            #     more privileges than they do now.
        #  2) or having filled out a previous version of the same form which
        #     had some validation missing,
        #  3) or previously having filled out the form when they had more
        #     privileges than they do now.
        #
            # Since the hashes only take into account values, and not other
            # other validation the form might do, we must re-do validation
            # now for security reasons.
            previous_form_list = [self.get_form(i, request.POST) for i in range(current_step)]

            for i, f in enumerate(previous_form_list):
        # Since the hashes only take into account values, and not other other
        # validation the form might do, we must re-do validation now for
        # security reasons.
        previous_form_list = []
        for i in range(current_step):
            f = self.get_form(i, request.POST)
            if request.POST.get("hash_%d" % i, '') != self.security_hash(request, f):
                return self.render_hash_failure(request, i)

@@ -104,8 +99,16 @@ class FormWizard(object):
                return self.render_revalidation_failure(request, i, f)
            else:
                self.process_step(request, f, i)
                previous_form_list.append(f)

            # Now progress to processing this step:
        # Process the current step. If it's valid, go to the next step or call
        # done(), depending on whether any steps remain.
        if request.method == 'POST':
            form = self.get_form(current_step, request.POST)
        else:
            form = self.get_form(current_step)

        if form.is_valid():
            self.process_step(request, form, current_step)
            next_step = current_step + 1