summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorxjm2016-11-16 18:45:27 (GMT)
committerxjm2016-11-16 19:22:21 (GMT)
commitabb650ffd41579861a45e57b914ab87e39ea6585 (patch)
treeb3a805a0bec888abe7421bbd968c9e30f73ca6b6
parent24eb0704ad804839be00e1a38e3e06059b85e747 (diff)
SA-CORE-2016-005 by larowlan, xjm, David_Rothstein, Dave Reid, Crell, cilefen, alexpott, mlhess, catch, pwolanin, YesCT, dawehner, quicksketch, Heine, znerol, charlotte.b, jnicola, ezraw
(cherry picked from commit c5da97f9e7e8f145541c5422e3ccde6a8b5ae680)
-rw-r--r--core/lib/Drupal/Core/Database/Query/Select.php17
-rw-r--r--core/lib/Drupal/Core/Render/Element/MachineName.php6
-rw-r--r--core/misc/machine-name.js3
-rw-r--r--core/modules/system/src/MachineNameController.php26
-rw-r--r--core/modules/system/system.install16
-rw-r--r--core/modules/system/tests/src/Unit/Transliteration/MachineNameControllerTest.php48
-rw-r--r--core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php2
-rw-r--r--core/modules/taxonomy/src/Plugin/views/relationship/NodeTermData.php2
-rw-r--r--core/modules/taxonomy/src/TermStorage.php8
-rw-r--r--core/modules/taxonomy/src/TermViewsData.php2
-rw-r--r--core/modules/taxonomy/src/Tests/TaxonomyQueryAlterTest.php119
-rw-r--r--core/modules/taxonomy/taxonomy.module2
-rw-r--r--core/modules/taxonomy/tests/modules/taxonomy_test/taxonomy_test.info.yml8
-rw-r--r--core/modules/taxonomy/tests/modules/taxonomy_test/taxonomy_test.module38
-rw-r--r--core/modules/user/src/Form/UserPasswordForm.php1
-rw-r--r--core/modules/user/src/Tests/UserPasswordResetTest.php3
-rw-r--r--core/tests/Drupal/Tests/Core/Render/Element/MachineNameTest.php8
17 files changed, 295 insertions, 14 deletions
diff --git a/core/lib/Drupal/Core/Database/Query/Select.php b/core/lib/Drupal/Core/Database/Query/Select.php
index b7db605..04efcf4 100644
--- a/core/lib/Drupal/Core/Database/Query/Select.php
+++ b/core/lib/Drupal/Core/Database/Query/Select.php
@@ -5,7 +5,6 @@ namespace Drupal\Core\Database\Query;
use Drupal\Core\Database\Database;
use Drupal\Core\Database\Connection;
-
/**
* Query builder for SELECT statements.
*
@@ -456,6 +455,22 @@ class Select extends Query implements SelectInterface {
// Modules may alter all queries or only those having a particular tag.
if (isset($this->alterTags)) {
+ // Many contrib modules as well as Entity Reference in core assume that
+ // query tags used for access-checking purposes follow the pattern
+ // $entity_type . '_access'. But this is not the case for taxonomy terms,
+ // since the core Taxonomy module used to add term_access instead of
+ // taxonomy_term_access to its queries. Provide backwards compatibility
+ // by adding both tags here instead of attempting to fix all contrib
+ // modules in a coordinated effort.
+ // TODO:
+ // - Extract this mechanism into a hook as part of a public (non-security)
+ // issue.
+ // - Emit E_USER_DEPRECATED if term_access is used.
+ // https://www.drupal.org/node/2575081
+ $term_access_tags = array('term_access' => 1, 'taxonomy_term_access' => 1);
+ if (array_intersect_key($this->alterTags, $term_access_tags)) {
+ $this->alterTags += $term_access_tags;
+ }
$hooks = array('query');
foreach ($this->alterTags as $tag => $value) {
$hooks[] = 'query_' . $tag;
diff --git a/core/lib/Drupal/Core/Render/Element/MachineName.php b/core/lib/Drupal/Core/Render/Element/MachineName.php
index c92d0e0..6cf4559 100644
--- a/core/lib/Drupal/Core/Render/Element/MachineName.php
+++ b/core/lib/Drupal/Core/Render/Element/MachineName.php
@@ -190,6 +190,7 @@ class MachineName extends Textfield {
$element['#attached']['library'][] = 'core/drupal.machine-name';
$options = [
'replace_pattern',
+ 'replace_token',
'replace',
'maxlength',
'target',
@@ -198,6 +199,11 @@ class MachineName extends Textfield {
'field_suffix',
'suffix',
];
+
+ /** @var \Drupal\Core\Access\CsrfTokenGenerator $token_generator */
+ $token_generator = \Drupal::service('csrf_token');
+ $element['#machine_name']['replace_token'] = $token_generator->get($element['#machine_name']['replace_pattern']);
+
$element['#attached']['drupalSettings']['machineName']['#' . $source['#id']] = array_intersect_key($element['#machine_name'], array_flip($options));
$element['#attached']['drupalSettings']['langcode'] = $language->getId();
diff --git a/core/misc/machine-name.js b/core/misc/machine-name.js
index e24cb56..e76292e 100644
--- a/core/misc/machine-name.js
+++ b/core/misc/machine-name.js
@@ -186,6 +186,8 @@
* @param {string} settings.replace_pattern
* A regular expression (without modifiers) matching disallowed characters
* in the machine name; e.g., '[^a-z0-9]+'.
+ * @param {string} settings.replace_token
+ * A token to validate the regular expression.
* @param {string} settings.replace
* A character to replace disallowed characters with; e.g., '_' or '-'.
* @param {number} settings.maxlength
@@ -199,6 +201,7 @@
text: source,
langcode: drupalSettings.langcode,
replace_pattern: settings.replace_pattern,
+ replace_token: settings.replace_token,
replace: settings.replace,
lowercase: true
});
diff --git a/core/modules/system/src/MachineNameController.php b/core/modules/system/src/MachineNameController.php
index 7331eb3..239e5b3 100644
--- a/core/modules/system/src/MachineNameController.php
+++ b/core/modules/system/src/MachineNameController.php
@@ -4,7 +4,9 @@ namespace Drupal\system;
use Drupal\Component\Transliteration\TransliterationInterface;
use Drupal\Component\Utility\Unicode;
+use Drupal\Core\Access\CsrfTokenGenerator;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
+use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -22,13 +24,23 @@ class MachineNameController implements ContainerInjectionInterface {
protected $transliteration;
/**
+ * The token generator.
+ *
+ * @var \Drupal\Core\Access\CsrfTokenGenerator
+ */
+ protected $tokenGenerator;
+
+ /**
* Constructs a MachineNameController object.
*
* @param \Drupal\Component\Transliteration\TransliterationInterface $transliteration
* The transliteration helper.
+ * @param \Drupal\Core\Access\CsrfTokenGenerator $token_generator
+ * The token generator.
*/
- public function __construct(TransliterationInterface $transliteration) {
+ public function __construct(TransliterationInterface $transliteration, CsrfTokenGenerator $token_generator) {
$this->transliteration = $transliteration;
+ $this->tokenGenerator = $token_generator;
}
/**
@@ -36,7 +48,8 @@ class MachineNameController implements ContainerInjectionInterface {
*/
public static function create(ContainerInterface $container) {
return new static(
- $container->get('transliteration')
+ $container->get('transliteration'),
+ $container->get('csrf_token')
);
}
@@ -54,6 +67,7 @@ class MachineNameController implements ContainerInjectionInterface {
$text = $request->query->get('text');
$langcode = $request->query->get('langcode');
$replace_pattern = $request->query->get('replace_pattern');
+ $replace_token = $request->query->get('replace_token');
$replace = $request->query->get('replace');
$lowercase = $request->query->get('lowercase');
@@ -61,7 +75,15 @@ class MachineNameController implements ContainerInjectionInterface {
if ($lowercase) {
$transliterated = Unicode::strtolower($transliterated);
}
+
if (isset($replace_pattern) && isset($replace)) {
+ if (!isset($replace_token)) {
+ throw new AccessDeniedException("Missing 'replace_token' query parameter.");
+ }
+ elseif (!$this->tokenGenerator->validate($replace_token, $replace_pattern)) {
+ throw new AccessDeniedException("Invalid 'replace_token' query parameter.");
+ }
+
// Quote the pattern delimiter and remove null characters to avoid the e
// or other modifiers being injected.
$transliterated = preg_replace('@' . strtr($replace_pattern, ['@' => '\@', chr(0) => '']) . '@', $replace, $transliterated);
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index e8f45eb..d6d6b44 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -1768,3 +1768,19 @@ function system_update_8201() {
/**
* @} End of "addtogroup updates-8.2.0".
*/
+
+/**
+ * @addtogroup updates-8.2.3
+ * @{
+ */
+
+/**
+ * Clear caches due to behavior change in MachineName element.
+ */
+function system_update_8202() {
+ // Empty update to cause a cache rebuild.
+}
+
+/**
+ * @} End of "addtogroup updates-8.2.3".
+ */
diff --git a/core/modules/system/tests/src/Unit/Transliteration/MachineNameControllerTest.php b/core/modules/system/tests/src/Unit/Transliteration/MachineNameControllerTest.php
index 73f4ef3..dbd1f1a 100644
--- a/core/modules/system/tests/src/Unit/Transliteration/MachineNameControllerTest.php
+++ b/core/modules/system/tests/src/Unit/Transliteration/MachineNameControllerTest.php
@@ -2,9 +2,12 @@
namespace Drupal\Tests\system\Unit\Transliteration;
+use Drupal\Core\Access\CsrfTokenGenerator;
use Drupal\Tests\UnitTestCase;
use Drupal\Component\Transliteration\PhpTransliteration;
use Drupal\system\MachineNameController;
+use Prophecy\Argument;
+use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
use Symfony\Component\HttpFoundation\Request;
/**
@@ -21,10 +24,22 @@ class MachineNameControllerTest extends UnitTestCase {
*/
protected $machineNameController;
+ /**
+ * The CSRF token generator.
+ *
+ * @var \Drupal\Core\Access\CsrfTokenGenerator
+ */
+ protected $tokenGenerator;
+
protected function setUp() {
parent::setUp();
// Create the machine name controller.
- $this->machineNameController = new MachineNameController(new PhpTransliteration());
+ $this->tokenGenerator = $this->prophesize(CsrfTokenGenerator::class);
+ $this->tokenGenerator->validate(Argument::cetera())->will(function ($args) {
+ return $args[0] === 'token-' . $args[1];
+ });
+
+ $this->machineNameController = new MachineNameController(new PhpTransliteration(), $this->tokenGenerator->reveal());
}
/**
@@ -38,7 +53,7 @@ class MachineNameControllerTest extends UnitTestCase {
* - The expected content of the JSONresponse.
*/
public function providerTestMachineNameController() {
- return array(
+ $valid_data = array(
array(array('text' => 'Bob', 'langcode' => 'en'), '"Bob"'),
array(array('text' => 'Bob', 'langcode' => 'en', 'lowercase' => TRUE), '"bob"'),
array(array('text' => 'Bob', 'langcode' => 'en', 'replace' => 'Alice', 'replace_pattern' => 'Bob'), '"Alice"'),
@@ -53,6 +68,15 @@ class MachineNameControllerTest extends UnitTestCase {
array(array('text' => 'Bob', 'langcode' => 'en', 'lowercase' => TRUE, 'replace' => 'fail()', 'replace_pattern' => ".*@e\0"), '"bob"'),
array(array('text' => 'Bob@e', 'langcode' => 'en', 'lowercase' => TRUE, 'replace' => 'fail()', 'replace_pattern' => ".*@e\0"), '"fail()"'),
);
+
+ $valid_data = array_map(function ($data) {
+ if (isset($data[0]['replace_pattern'])) {
+ $data[0]['replace_token'] = 'token-' . $data[0]['replace_pattern'];
+ }
+ return $data;
+ }, $valid_data);
+
+ return $valid_data;
}
/**
@@ -73,4 +97,24 @@ class MachineNameControllerTest extends UnitTestCase {
$this->assertEquals($expected_content, $json->getContent());
}
+ /**
+ * Tests the pattern validation.
+ */
+ public function testMachineNameControllerWithInvalidReplacePattern() {
+ $request = Request::create('', 'GET', ['text' => 'Bob', 'langcode' => 'en', 'replace' => 'Alice', 'replace_pattern' => 'Bob', 'replace_token' => 'invalid']);
+
+ $this->setExpectedException(AccessDeniedException::class, "Invalid 'replace_token' query parameter.");
+ $this->machineNameController->transliterate($request);
+ }
+
+ /**
+ * Tests the pattern validation with a missing token.
+ */
+ public function testMachineNameControllerWithMissingToken() {
+ $request = Request::create('', 'GET', ['text' => 'Bob', 'langcode' => 'en', 'replace' => 'Alice', 'replace_pattern' => 'Bob']);
+
+ $this->setExpectedException(AccessDeniedException::class, "Missing 'replace_token' query parameter.");
+ $this->machineNameController->transliterate($request);
+ }
+
}
diff --git a/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php b/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php
index 0158881..d769bb0 100644
--- a/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php
+++ b/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php
@@ -192,7 +192,7 @@ class TaxonomyIndexTid extends ManyToOne {
// https://www.drupal.org/node/1821274.
->sort('weight')
->sort('name')
- ->addTag('term_access');
+ ->addTag('taxonomy_term_access');
if ($this->options['limit']) {
$query->condition('vid', $vocabulary->id());
}
diff --git a/core/modules/taxonomy/src/Plugin/views/relationship/NodeTermData.php b/core/modules/taxonomy/src/Plugin/views/relationship/NodeTermData.php
index 40c8fc7..b1c72e4 100644
--- a/core/modules/taxonomy/src/Plugin/views/relationship/NodeTermData.php
+++ b/core/modules/taxonomy/src/Plugin/views/relationship/NodeTermData.php
@@ -132,7 +132,7 @@ class NodeTermData extends RelationshipPluginBase {
$query = db_select('taxonomy_term_field_data', 'td');
$query->addJoin($def['type'], 'taxonomy_index', 'tn', 'tn.tid = td.tid');
$query->condition('td.vid', array_filter($this->options['vids']), 'IN');
- $query->addTag('term_access');
+ $query->addTag('taxonomy_term_access');
$query->fields('td');
$query->fields('tn', array('nid'));
$def['table formula'] = $query;
diff --git a/core/modules/taxonomy/src/TermStorage.php b/core/modules/taxonomy/src/TermStorage.php
index ffbf1da..bc44c22 100644
--- a/core/modules/taxonomy/src/TermStorage.php
+++ b/core/modules/taxonomy/src/TermStorage.php
@@ -126,7 +126,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
$query->addField('t', 'tid');
$query->condition('h.tid', $tid);
$query->condition('t.default_langcode', 1);
- $query->addTag('term_access');
+ $query->addTag('taxonomy_term_access');
$query->orderBy('t.weight');
$query->orderBy('t.name');
if ($ids = $query->execute()->fetchCol()) {
@@ -178,7 +178,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
$query->condition('t.vid', $vid);
}
$query->condition('t.default_langcode', 1);
- $query->addTag('term_access');
+ $query->addTag('taxonomy_term_access');
$query->orderBy('t.weight');
$query->orderBy('t.name');
if ($ids = $query->execute()->fetchCol()) {
@@ -204,7 +204,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
$query = $this->database->select('taxonomy_term_field_data', 't');
$query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid');
$result = $query
- ->addTag('term_access')
+ ->addTag('taxonomy_term_access')
->fields('t')
->fields('h', array('parent'))
->condition('t.vid', $vid)
@@ -320,7 +320,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
$query->orderby('td.weight');
$query->orderby('td.name');
$query->condition('tn.nid', $nids, 'IN');
- $query->addTag('term_access');
+ $query->addTag('taxonomy_term_access');
if (!empty($vocabs)) {
$query->condition('td.vid', $vocabs, 'IN');
}
diff --git a/core/modules/taxonomy/src/TermViewsData.php b/core/modules/taxonomy/src/TermViewsData.php
index 00bc589..89b2b55 100644
--- a/core/modules/taxonomy/src/TermViewsData.php
+++ b/core/modules/taxonomy/src/TermViewsData.php
@@ -16,7 +16,7 @@ class TermViewsData extends EntityViewsData {
$data = parent::getViewsData();
$data['taxonomy_term_field_data']['table']['base']['help'] = $this->t('Taxonomy terms are attached to nodes.');
- $data['taxonomy_term_field_data']['table']['base']['access query tag'] = 'term_access';
+ $data['taxonomy_term_field_data']['table']['base']['access query tag'] = 'taxonomy_term_access';
$data['taxonomy_term_field_data']['table']['wizard_id'] = 'taxonomy_term';
$data['taxonomy_term_field_data']['table']['join'] = array(
diff --git a/core/modules/taxonomy/src/Tests/TaxonomyQueryAlterTest.php b/core/modules/taxonomy/src/Tests/TaxonomyQueryAlterTest.php
new file mode 100644
index 0000000..543910b
--- /dev/null
+++ b/core/modules/taxonomy/src/Tests/TaxonomyQueryAlterTest.php
@@ -0,0 +1,119 @@
+<?php
+
+namespace Drupal\taxonomy\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests that appropriate query tags are added.
+ *
+ * @group taxonomy
+ */
+class TaxonomyQueryAlterTest extends WebTestBase {
+
+ use TaxonomyTestTrait;
+
+ /**
+ * Modules to enable.
+ *
+ * @var array
+ */
+ public static $modules = ['taxonomy', 'taxonomy_test'];
+
+ /**
+ * Tests that appropriate tags are added when querying the database.
+ */
+ public function testTaxonomyQueryAlter() {
+ // Create a new vocabulary and add a few terms to it.
+ $vocabulary = $this->createVocabulary();
+ $terms = array();
+ for ($i = 0; $i < 5; $i++) {
+ $terms[$i] = $this->createTerm($vocabulary);
+ }
+
+ // Set up hierarchy. Term 2 is a child of 1.
+ $terms[2]->parent = $terms[1]->id();
+ $terms[2]->save();
+
+ $term_storage = \Drupal::entityManager()->getStorage('taxonomy_term');
+
+ $this->setupQueryTagTestHooks();
+ $loaded_term = $term_storage->load($terms[0]->id());
+ $this->assertEqual($loaded_term->id(), $terms[0]->id(), 'First term was loaded');
+ $this->assertQueryTagTestResult(1, 0, 'TermStorage::load()');
+
+ $this->setupQueryTagTestHooks();
+ $loaded_terms = $term_storage->loadTree($vocabulary->id());
+ $this->assertEqual(count($loaded_terms), count($terms), 'All terms were loaded');
+ $this->assertQueryTagTestResult(1, 1, 'TermStorage::loadTree()');
+
+ $this->setupQueryTagTestHooks();
+ $loaded_terms = $term_storage->loadParents($terms[2]->id());
+ $this->assertEqual(count($loaded_terms), 1, 'All parent terms were loaded');
+ $this->assertQueryTagTestResult(2, 1, 'TermStorage::loadParents()');
+
+ $this->setupQueryTagTestHooks();
+ $loaded_terms = $term_storage->loadChildren($terms[1]->id());
+ $this->assertEqual(count($loaded_terms), 1, 'All child terms were loaded');
+ $this->assertQueryTagTestResult(2, 1, 'TermStorage::loadChildren()');
+
+ $this->setupQueryTagTestHooks();
+ $query = db_select('taxonomy_term_data', 't');
+ $query->addField('t', 'tid');
+ $query->addTag('taxonomy_term_access');
+ $tids = $query->execute()->fetchCol();
+ $this->assertEqual(count($tids), count($terms), 'All term IDs were retrieved');
+ $this->assertQueryTagTestResult(1, 1, 'custom db_select() with taxonomy_term_access tag (preferred)');
+
+ $this->setupQueryTagTestHooks();
+ $query = db_select('taxonomy_term_data', 't');
+ $query->addField('t', 'tid');
+ $query->addTag('term_access');
+ $tids = $query->execute()->fetchCol();
+ $this->assertEqual(count($tids), count($terms), 'All term IDs were retrieved');
+ $this->assertQueryTagTestResult(1, 1, 'custom db_select() with term_access tag (deprecated)');
+
+ $this->setupQueryTagTestHooks();
+ $query = \Drupal::entityQuery('taxonomy_term');
+ $query->addTag('taxonomy_term_access');
+ $result = $query->execute();
+ $this->assertEqual(count($result), count($terms), 'All term IDs were retrieved');
+ $this->assertQueryTagTestResult(1, 1, 'custom EntityFieldQuery with taxonomy_term_access tag (preferred)');
+
+ $this->setupQueryTagTestHooks();
+ $query = \Drupal::entityQuery('taxonomy_term');
+ $query->addTag('term_access');
+ $result = $query->execute();
+ $this->assertEqual(count($result), count($terms), 'All term IDs were retrieved');
+ $this->assertQueryTagTestResult(1, 1, 'custom EntityFieldQuery with term_access tag (deprecated)');
+ }
+
+ /**
+ * Sets up the hooks in the test module.
+ */
+ protected function setupQueryTagTestHooks() {
+ taxonomy_terms_static_reset();
+ \Drupal::state()->set('taxonomy_test_query_alter', 0);
+ \Drupal::state()->set('taxonomy_test_query_term_access_alter', 0);
+ \Drupal::state()->set('taxonomy_test_query_taxonomy_term_access_alter', 0);
+ }
+
+ /**
+ * Verifies invocation of the hooks in the test module.
+ *
+ * @param int $expected_generic_invocations
+ * The number of times the generic query_alter hook is expected to have
+ * been invoked.
+ * @param int $expected_specific_invocations
+ * The number of times the tag-specific query_alter hooks are expected to
+ * have been invoked.
+ * @param string $method
+ * A string describing the invoked function which generated the query.
+ */
+ protected function assertQueryTagTestResult($expected_generic_invocations, $expected_specific_invocations, $method) {
+ $this->assertIdentical($expected_generic_invocations, \Drupal::state()->get('taxonomy_test_query_alter'), 'hook_query_alter() invoked when executing ' . $method);
+ $this->assertIdentical($expected_specific_invocations, \Drupal::state()->get('taxonomy_test_query_term_access_alter'), 'Deprecated hook_query_term_access_alter() invoked when executing ' . $method);
+ $this->assertIdentical($expected_specific_invocations, \Drupal::state()->get('taxonomy_test_query_taxonomy_term_access_alter'), 'Preferred hook_query_taxonomy_term_access_alter() invoked when executing ' . $method);
+ }
+
+}
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index 7a1ca65..8088432 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -7,8 +7,8 @@
use Drupal\Component\Utility\Tags;
use Drupal\Component\Utility\Unicode;
-use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
use Drupal\Core\Render\Element;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
diff --git a/core/modules/taxonomy/tests/modules/taxonomy_test/taxonomy_test.info.yml b/core/modules/taxonomy/tests/modules/taxonomy_test/taxonomy_test.info.yml
new file mode 100644
index 0000000..5bc0197
--- /dev/null
+++ b/core/modules/taxonomy/tests/modules/taxonomy_test/taxonomy_test.info.yml
@@ -0,0 +1,8 @@
+name: 'Taxonomy test'
+type: module
+description: 'Provides test hook implementations for taxonomy tests'
+package: Testing
+version: VERSION
+core: 8.x
+dependencies:
+ - taxonomy
diff --git a/core/modules/taxonomy/tests/modules/taxonomy_test/taxonomy_test.module b/core/modules/taxonomy/tests/modules/taxonomy_test/taxonomy_test.module
new file mode 100644
index 0000000..8e08c13
--- /dev/null
+++ b/core/modules/taxonomy/tests/modules/taxonomy_test/taxonomy_test.module
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Provides test hook implementations for taxonomy tests.
+ */
+
+use Drupal\Core\Database\Query\AlterableInterface;
+
+/**
+ * Implements hook_query_alter().
+ */
+function taxonomy_test_query_alter(AlterableInterface $query) {
+ $value = \Drupal::state()->get(__FUNCTION__);
+ if (isset($value)) {
+ \Drupal::state()->set(__FUNCTION__, ++$value);
+ }
+}
+
+/**
+ * Implements hook_query_TAG_alter().
+ */
+function taxonomy_test_query_term_access_alter(AlterableInterface $query) {
+ $value = \Drupal::state()->get(__FUNCTION__);
+ if (isset($value)) {
+ \Drupal::state()->set(__FUNCTION__, ++$value);
+ }
+}
+
+/**
+ * Implements hook_query_TAG_alter().
+ */
+function taxonomy_test_query_taxonomy_term_access_alter(AlterableInterface $query) {
+ $value = \Drupal::state()->get(__FUNCTION__);
+ if (isset($value)) {
+ \Drupal::state()->set(__FUNCTION__, ++$value);
+ }
+}
diff --git a/core/modules/user/src/Form/UserPasswordForm.php b/core/modules/user/src/Form/UserPasswordForm.php
index 83d8e0a..a89549a 100644
--- a/core/modules/user/src/Form/UserPasswordForm.php
+++ b/core/modules/user/src/Form/UserPasswordForm.php
@@ -99,6 +99,7 @@ class UserPasswordForm extends FormBase {
}
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array('#type' => 'submit', '#value' => $this->t('Submit'));
+ $form['#cache']['contexts'][] = 'url.query_args';
return $form;
}
diff --git a/core/modules/user/src/Tests/UserPasswordResetTest.php b/core/modules/user/src/Tests/UserPasswordResetTest.php
index c012e9f..f3463bf 100644
--- a/core/modules/user/src/Tests/UserPasswordResetTest.php
+++ b/core/modules/user/src/Tests/UserPasswordResetTest.php
@@ -292,6 +292,9 @@ class UserPasswordResetTest extends PageCacheTagsTestBase {
unset($edit['pass']);
$this->drupalGet('user/password', array('query' => array('name' => $edit['name'])));
$this->assertFieldByName('name', $edit['name'], 'User name found.');
+ // Ensure the name field value is not cached.
+ $this->drupalGet('user/password');
+ $this->assertNoFieldByName('name', $edit['name'], 'User name not found.');
}
/**
diff --git a/core/tests/Drupal/Tests/Core/Render/Element/MachineNameTest.php b/core/tests/Drupal/Tests/Core/Render/Element/MachineNameTest.php
index d5340cb..0dcdc58 100644
--- a/core/tests/Drupal/Tests/Core/Render/Element/MachineNameTest.php
+++ b/core/tests/Drupal/Tests/Core/Render/Element/MachineNameTest.php
@@ -2,6 +2,7 @@
namespace Drupal\Tests\Core\Render\Element;
+use Drupal\Core\Access\CsrfTokenGenerator;
use Drupal\Core\Form\FormState;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
@@ -78,8 +79,12 @@ class MachineNameTest extends UnitTestCase {
$language_manager = $this->prophesize(LanguageManagerInterface::class);
$language_manager->getCurrentLanguage()->willReturn($language);
+ $csrf_token = $this->prophesize(CsrfTokenGenerator::class);
+ $csrf_token->get('[^a-z0-9_]+')->willReturn('tis-a-fine-token');
+
$container = $this->prophesize(ContainerInterface::class);
$container->get('language_manager')->willReturn($language_manager->reveal());
+ $container->get('csrf_token')->willReturn($csrf_token->reveal());
\Drupal::setContainer($container->reveal());
$element = MachineName::processMachineName($element, $form_state, $complete_form);
@@ -93,7 +98,8 @@ class MachineNameTest extends UnitTestCase {
'label',
'field_prefix',
'field_suffix',
- 'suffix'
+ 'suffix',
+ 'replace_token',
];
$this->assertEmpty(array_diff_key($settings, array_flip($allowed_options)));
foreach ($allowed_options as $key) {