Commit 30fceb5f authored by catch's avatar catch

Issue #2559011 by Wim Leers: Ensure form tokens are marked max-age=0

parent 5d896a2e
......@@ -688,18 +688,24 @@ public function prepareForm($form_id, &$form, FormStateInterface &$form_state) {
if ($form_state->isProgrammed() || (isset($form['#token']) && $form['#token'] === FALSE)) {
unset($form['#token']);
}
elseif ($user && $user->isAuthenticated()) {
// Generate a public token based on the form id.
$form['#token'] = $form_id;
$form['form_token'] = array(
'#id' => Html::getUniqueId('edit-' . $form_id . '-form-token'),
'#type' => 'token',
'#default_value' => $this->csrfToken->get($form['#token']),
// Form processing and validation requires this value, so ensure the
// submitted form value appears literally, regardless of custom #tree
// and #parents being set elsewhere.
'#parents' => array('form_token'),
);
else {
$form['#cache']['contexts'][] = 'user.roles:authenticated';
if ($user && $user->isAuthenticated()) {
// Generate a public token based on the form id.
$form['#token'] = $form_id;
$form['form_token'] = array(
'#id' => Html::getUniqueId('edit-' . $form_id . '-form-token'),
'#type' => 'token',
'#default_value' => $this->csrfToken->get($form['#token']),
// Form processing and validation requires this value, so ensure the
// submitted form value appears literally, regardless of custom #tree
// and #parents being set elsewhere.
'#parents' => array('form_token'),
'#cache' => [
'max-age' => 0,
],
);
}
}
if (isset($form_id)) {
......
......@@ -30,6 +30,17 @@ class BlockContentTranslationUITest extends ContentTranslationUITestBase {
'block_content'
);
/**
* {@inheritdoc}
*/
protected $defaultCacheContexts = [
'languages:language_interface',
'theme',
'url.query_args:_wrapper_format',
'user.permissions',
'user.roles:authenticated',
];
/**
* Overrides \Drupal\simpletest\WebTestBase::setUp().
*/
......
......@@ -26,6 +26,17 @@ class ContentTestTranslationUITest extends ContentTranslationUITestBase {
*/
public static $modules = array('language', 'content_translation', 'entity_test');
/**
* {@inheritdoc}
*/
protected $defaultCacheContexts = [
'languages:language_interface',
'theme',
'url.query_args:_wrapper_format',
'user.permissions',
'user.roles:authenticated',
];
/**
* Overrides \Drupal\simpletest\WebTestBase::setUp().
*/
......
......@@ -207,6 +207,7 @@ public function testExposedSortAndItemsPerPage() {
'entity_test_view_grants',
'theme',
'url.query_args',
'user.roles:authenticated',
'languages:language_content'
];
......
......@@ -18,6 +18,7 @@
use Drupal\Core\Form\FormState;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
......@@ -767,6 +768,65 @@ public function providerTestInvalidToken() {
return $data;
}
/**
* @covers ::prepareForm
*
* @dataProvider providerTestFormTokenCacheability
*/
function testFormTokenCacheability($token, $is_authenticated, $expected_form_cacheability, $expected_token_cacheability) {
$user = $this->prophesize(AccountProxyInterface::class);
$user->isAuthenticated()
->willReturn($is_authenticated);
$this->container->set('current_user', $user->reveal());
\Drupal::setContainer($this->container);
$form_id = 'test_form_id';
$form = $form_id();
if (isset($token)) {
$form['#token'] = $token;
}
$form_arg = $this->getMock('Drupal\Core\Form\FormInterface');
$form_arg->expects($this->once())
->method('getFormId')
->will($this->returnValue($form_id));
$form_arg->expects($this->once())
->method('buildForm')
->will($this->returnValue($form));
$form_state = new FormState();
$built_form = $this->formBuilder->buildForm($form_arg, $form_state);
if (!isset($expected_form_cacheability)) {
$this->assertFalse(isset($built_form['#cache']));
}
else {
$this->assertTrue(isset($built_form['#cache']));
$this->assertEquals($expected_form_cacheability, $built_form['#cache']);
}
if (!isset($expected_token_cacheability)) {
$this->assertFalse(isset($built_form['form_token']));
}
else {
$this->assertTrue(isset($built_form['form_token']));
$this->assertEquals($expected_token_cacheability, $built_form['form_token']['#cache']);
}
}
/**
* Data provider for testFormTokenCacheability.
*
* @return array
*/
function providerTestFormTokenCacheability() {
return [
'token:none,authenticated:true' => [NULL, TRUE, ['contexts' => ['user.roles:authenticated']], ['max-age' => 0]],
'token:false,authenticated:true' => [FALSE, TRUE, NULL, NULL],
'token:none,authenticated:false' => [NULL, FALSE, ['contexts' => ['user.roles:authenticated']], NULL],
'token:false,authenticated:false' => [FALSE, FALSE, NULL, NULL],
];
}
}
class TestForm implements FormInterface {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment