SA-CORE-2020-004 by samuel.mortenson, DorTumarkin, greggles, xjm, larowlan, webchick, pwolanin, dawehner, mcdruid, alexpott, dsnopek
(cherry picked from commit 3999b8f658
)
merge-requests/2/head
parent
ceee045fa5
commit
357efb6c33
|
@ -19,6 +19,7 @@ use Drupal\Core\Security\TrustedCallbackInterface;
|
|||
use Drupal\Core\Theme\ThemeManagerInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\FileBag;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
|
@ -957,8 +958,16 @@ class FormBuilder implements FormBuilderInterface, FormValidatorInterface, FormS
|
|||
// This value is checked in self::handleInputElement().
|
||||
$form_state->setInvalidToken(TRUE);
|
||||
|
||||
// Ignore all submitted values.
|
||||
$form_state->setUserInput([]);
|
||||
|
||||
$request = $this->requestStack->getCurrentRequest();
|
||||
// Do not trust any POST data.
|
||||
$request->request = new ParameterBag();
|
||||
// Make sure file uploads do not get processed.
|
||||
$this->requestStack->getCurrentRequest()->files = new FileBag();
|
||||
$request->files = new FileBag();
|
||||
// Ensure PHP globals reflect these changes.
|
||||
$request->overrideGlobals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,10 +124,8 @@ class FormValidator implements FormValidatorInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function setInvalidTokenError(FormStateInterface $form_state) {
|
||||
$url = $this->requestStack->getCurrentRequest()->getRequestUri();
|
||||
|
||||
// Setting this error will cause the form to fail validation.
|
||||
$form_state->setErrorByName('form_token', $this->t('The form has become outdated. Copy any unsaved work in the form below and then <a href=":link">reload this page</a>.', [':link' => $url]));
|
||||
$form_state->setErrorByName('form_token', $this->t('The form has become outdated. Press the back button, copy any unsaved work in the form, and then reload the page.'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -50,7 +50,7 @@ class FileManagedFileElementTest extends FileFieldTestBase {
|
|||
$file_field_name => \Drupal::service('file_system')->realpath($test_file->getFileUri()),
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertText('The form has become outdated. Copy any unsaved work in the form below');
|
||||
$this->assertText('The form has become outdated.');
|
||||
$last_fid = $this->getLastFileId();
|
||||
$this->assertEqual($last_fid_prior, $last_fid, 'File was not saved when uploaded with an invalid form token.');
|
||||
|
||||
|
|
|
@ -251,21 +251,27 @@ class FormTest extends BrowserTestBase {
|
|||
$this->assertSession()
|
||||
->elementExists('css', 'input[name="form_token"]')
|
||||
->setValue('invalid token');
|
||||
$random_string = $this->randomString();
|
||||
$edit = [
|
||||
'textfield' => $this->randomString(),
|
||||
'textfield' => $random_string,
|
||||
'checkboxes[bar]' => TRUE,
|
||||
'select' => 'bar',
|
||||
'radios' => 'foo',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, 'Submit');
|
||||
$this->assertFieldByXpath('//div[contains(@class, "error")]', NULL, 'Error message is displayed with invalid token even when required fields are filled.');
|
||||
$this->assertText('The form has become outdated. Copy any unsaved work in the form below');
|
||||
// Verify that input elements retained the posted values.
|
||||
$this->assertFieldByName('textfield', $edit['textfield']);
|
||||
|
||||
$assert = $this->assertSession();
|
||||
$element = $assert->fieldExists('textfield');
|
||||
$this->assertEmpty($element->getValue());
|
||||
$assert->responseNotContains($random_string);
|
||||
$this->assertText('The form has become outdated.');
|
||||
// Ensure that we don't use the posted values.
|
||||
$this->assertFieldByName('textfield', '');
|
||||
$this->assertNoFieldChecked('edit-checkboxes-foo');
|
||||
$this->assertFieldChecked('edit-checkboxes-bar');
|
||||
$this->assertOptionSelected('edit-select', 'bar');
|
||||
$this->assertFieldChecked('edit-radios-foo');
|
||||
$this->assertNoFieldChecked('edit-checkboxes-bar');
|
||||
$this->assertOptionSelected('edit-select', '');
|
||||
$this->assertNoFieldChecked('edit-radios-foo');
|
||||
|
||||
// Check another form that has a textarea input.
|
||||
$this->drupalGet(Url::fromRoute('form_test.required'));
|
||||
|
@ -278,9 +284,9 @@ class FormTest extends BrowserTestBase {
|
|||
];
|
||||
$this->drupalPostForm(NULL, $edit, 'Submit');
|
||||
$this->assertFieldByXpath('//div[contains(@class, "error")]', NULL, 'Error message is displayed with invalid token even when required fields are filled.');
|
||||
$this->assertText('The form has become outdated. Copy any unsaved work in the form below');
|
||||
$this->assertFieldByName('textfield', $edit['textfield']);
|
||||
$this->assertFieldByName('textarea', $edit['textarea']);
|
||||
$this->assertText('The form has become outdated.');
|
||||
$this->assertFieldByName('textfield', '');
|
||||
$this->assertFieldByName('textarea', '');
|
||||
|
||||
// Check another form that has a number input.
|
||||
$this->drupalGet(Url::fromRoute('form_test.number'));
|
||||
|
@ -288,12 +294,14 @@ class FormTest extends BrowserTestBase {
|
|||
->elementExists('css', 'input[name="form_token"]')
|
||||
->setValue('invalid token');
|
||||
$edit = [
|
||||
'integer_step' => mt_rand(1, 100),
|
||||
// We choose a random value which is higher than the default value,
|
||||
// so we don't accidentally generate the default value.
|
||||
'integer_step' => mt_rand(6, 100),
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, 'Submit');
|
||||
$this->assertFieldByXpath('//div[contains(@class, "error")]', NULL, 'Error message is displayed with invalid token even when required fields are filled.');
|
||||
$this->assertText('The form has become outdated. Copy any unsaved work in the form below');
|
||||
$this->assertFieldByName('integer_step', $edit['integer_step']);
|
||||
$this->assertText('The form has become outdated.');
|
||||
$this->assertFieldByName('integer_step', 5);
|
||||
|
||||
// Check a form with a Url field
|
||||
$this->drupalGet(Url::fromRoute('form_test.url'));
|
||||
|
@ -305,8 +313,8 @@ class FormTest extends BrowserTestBase {
|
|||
];
|
||||
$this->drupalPostForm(NULL, $edit, 'Submit');
|
||||
$this->assertFieldByXpath('//div[contains(@class, "error")]', NULL, 'Error message is displayed with invalid token even when required fields are filled.');
|
||||
$this->assertText('The form has become outdated. Copy any unsaved work in the form below');
|
||||
$this->assertFieldByName('url', $edit['url']);
|
||||
$this->assertText('The form has become outdated.');
|
||||
$this->assertFieldByName('url', '');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -74,7 +74,7 @@ class ValidationTest extends BrowserTestBase {
|
|||
$this->drupalPostForm(NULL, ['name' => 'validate'], 'Save');
|
||||
$this->assertNoFieldByName('name', '#value changed by #validate', 'Form element #value was not altered.');
|
||||
$this->assertNoText('Name value: value changed by setValueForElement() in #validate', 'Form element value in $form_state was not altered.');
|
||||
$this->assertText('The form has become outdated. Copy any unsaved work in the form below');
|
||||
$this->assertText('The form has become outdated.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -832,12 +832,30 @@ class FormBuilderTest extends FormTestBase {
|
|||
$expected_form = $form_id();
|
||||
$form_arg = $this->getMockForm($form_id, $expected_form);
|
||||
|
||||
// Set up some request data so we can be sure it is removed when a token is
|
||||
// invalid.
|
||||
$this->request->request->set('foo', 'bar');
|
||||
$_POST['foo'] = 'bar';
|
||||
|
||||
$form_state = new FormState();
|
||||
$input['form_id'] = $form_id;
|
||||
$input['form_token'] = $form_token;
|
||||
$input['test'] = 'example-value';
|
||||
$form_state->setUserInput($input);
|
||||
$this->simulateFormSubmission($form_id, $form_arg, $form_state, FALSE);
|
||||
$form = $this->simulateFormSubmission($form_id, $form_arg, $form_state, FALSE);
|
||||
$this->assertSame($expected, $form_state->hasInvalidToken());
|
||||
if ($expected) {
|
||||
$this->assertEmpty($form['test']['#value']);
|
||||
$this->assertEmpty($form_state->getValue('test'));
|
||||
$this->assertEmpty($_POST);
|
||||
$this->assertEmpty(iterator_to_array($this->request->request->getIterator()));
|
||||
}
|
||||
else {
|
||||
$this->assertEquals('example-value', $form['test']['#value']);
|
||||
$this->assertEquals('example-value', $form_state->getValue('test'));
|
||||
$this->assertEquals('bar', $_POST['foo']);
|
||||
$this->assertEquals('bar', $this->request->request->get('foo'));
|
||||
}
|
||||
}
|
||||
|
||||
public function providerTestInvalidToken() {
|
||||
|
|
|
@ -173,7 +173,7 @@ abstract class FormTestBase extends UnitTestCase {
|
|||
->getMock();
|
||||
$this->account = $this->createMock('Drupal\Core\Session\AccountInterface');
|
||||
$this->themeManager = $this->createMock('Drupal\Core\Theme\ThemeManagerInterface');
|
||||
$this->request = new Request();
|
||||
$this->request = Request::createFromGlobals();
|
||||
$this->eventDispatcher = $this->createMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
|
||||
$this->requestStack = new RequestStack();
|
||||
$this->requestStack->push($this->request);
|
||||
|
|
|
@ -131,7 +131,7 @@ class FormValidatorTest extends UnitTestCase {
|
|||
->getMock();
|
||||
$form_state->expects($this->once())
|
||||
->method('setErrorByName')
|
||||
->with('form_token', 'The form has become outdated. Copy any unsaved work in the form below and then <a href="/test/example?foo=bar">reload this page</a>.');
|
||||
->with('form_token', 'The form has become outdated. Press the back button, copy any unsaved work in the form, and then reload the page.');
|
||||
$form_state->setValue('form_token', 'some_random_token');
|
||||
$form_validator->validateForm('test_form_id', $form, $form_state);
|
||||
$this->assertTrue($form_state->isValidationComplete());
|
||||
|
|
Loading…
Reference in New Issue