From 75d6aa33cd7770e3ceebd14a378978b1c93a8cc2 Mon Sep 17 00:00:00 2001 From: xjm <xjm@65776.no-reply.drupal.org> Date: Wed, 21 Sep 2016 12:39:14 -0500 Subject: [PATCH] SA-CORE-2016-004 by alexpott, andypost, antongp, cashwilliams, catch, Chi, dawehner, dsnopek, Heine, kierheyl, Pere Orga, pwolanin, larowlan, q2u, stefan.r, xjm --- .../DefaultExceptionSubscriber.php | 7 +- .../comment/src/CommentFieldItemList.php | 26 +++++ .../comment/src/Tests/CommentNonNodeTest.php | 1 + .../CommentStatusFieldAccessTest.php | 100 ++++++++++++++++++ core/modules/config/config.module | 21 ++-- .../config/src/Tests/ConfigExportUITest.php | 6 ++ .../Core/Routing/ExceptionHandlingTest.php | 11 ++ 7 files changed, 161 insertions(+), 11 deletions(-) create mode 100644 core/modules/comment/tests/src/Functional/CommentStatusFieldAccessTest.php diff --git a/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionSubscriber.php index 4049f865b32d..4737e8031a48 100644 --- a/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionSubscriber.php @@ -188,13 +188,16 @@ public function onException(GetResponseForExceptionEvent $event) { if (!method_exists($this, $method)) { if ($exception instanceof HttpExceptionInterface) { $this->onFormatUnknown($event); + $response = $event->getResponse(); + $response->headers->set('Content-Type', 'text/plain'); } else { $this->onHtml($event); } - return; } - $this->$method($event); + else { + $this->$method($event); + } } /** diff --git a/core/modules/comment/src/CommentFieldItemList.php b/core/modules/comment/src/CommentFieldItemList.php index de00c7d71d81..7a4cdad4e6d8 100644 --- a/core/modules/comment/src/CommentFieldItemList.php +++ b/core/modules/comment/src/CommentFieldItemList.php @@ -2,7 +2,9 @@ namespace Drupal\comment; +use Drupal\Core\Access\AccessResult; use Drupal\Core\Field\FieldItemList; +use Drupal\Core\Session\AccountInterface; /** * Defines a item list class for comment fields. @@ -37,4 +39,28 @@ public function offsetExists($offset) { return parent::offsetExists($offset); } + /** + * {@inheritdoc} + */ + public function access($operation = 'view', AccountInterface $account = NULL, $return_as_object = FALSE) { + if ($operation === 'edit') { + // Only users with administer comments permission can edit the comment + // status field. + $result = AccessResult::allowedIfHasPermission($account ?: \Drupal::currentUser(), 'administer comments'); + return $return_as_object ? $result : $result->isAllowed(); + } + if ($operation === 'view') { + // Only users with either post comments or access comments permisison can + // view the field value. The formatter, + // Drupal\comment\Plugin\Field\FieldFormatter\CommentDefaultFormatter, + // takes care of showing the thread and form based on individual + // permissions, so if a user only has ‘post comments’ access, only the + // form will be shown and not the comments. + $result = AccessResult::allowedIfHasPermission($account ?: \Drupal::currentUser(), 'access comments') + ->orIf(AccessResult::allowedIfHasPermission($account ?: \Drupal::currentUser(), 'post comments')); + return $return_as_object ? $result : $result->isAllowed(); + } + return parent::access($operation, $account, $return_as_object); + } + } diff --git a/core/modules/comment/src/Tests/CommentNonNodeTest.php b/core/modules/comment/src/Tests/CommentNonNodeTest.php index 1b37c1f79cff..e43e0bc42a60 100644 --- a/core/modules/comment/src/Tests/CommentNonNodeTest.php +++ b/core/modules/comment/src/Tests/CommentNonNodeTest.php @@ -384,6 +384,7 @@ function testCommentFunctionality() { 'administer entity_test fields', 'view test entity', 'administer entity_test content', + 'administer comments', )); $this->drupalLogin($limited_user); $this->drupalGet('entity_test/structure/entity_test/fields/entity_test.entity_test.comment'); diff --git a/core/modules/comment/tests/src/Functional/CommentStatusFieldAccessTest.php b/core/modules/comment/tests/src/Functional/CommentStatusFieldAccessTest.php new file mode 100644 index 000000000000..504b3bacf671 --- /dev/null +++ b/core/modules/comment/tests/src/Functional/CommentStatusFieldAccessTest.php @@ -0,0 +1,100 @@ +<?php + +namespace Drupal\Tests\comment\Functional; + + +use Drupal\comment\Tests\CommentTestTrait; +use Drupal\node\Entity\NodeType; +use Drupal\Tests\BrowserTestBase; + +/** + * Tests comment status field access. + * + * @group comment + */ +class CommentStatusFieldAccessTest extends BrowserTestBase { + + use CommentTestTrait; + + /** + * {@inheritdoc} + */ + public $profile = 'testing'; + + /** + * Comment admin. + * + * @var \Drupal\user\UserInterface + */ + protected $commentAdmin; + + /** + * Node author. + * + * @var \Drupal\user\UserInterface + */ + protected $nodeAuthor; + + /** + * {@inheritdoc} + */ + public static $modules = [ + 'node', + 'comment', + 'user', + 'system', + 'text', + ]; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + $node_type = NodeType::create([ + 'type' => 'article', + 'name' => t('Article'), + ]); + $node_type->save(); + $this->nodeAuthor = $this->drupalCreateUser([ + 'create article content', + 'skip comment approval', + 'post comments', + 'edit own comments', + 'access comments', + 'administer nodes', + ]); + $this->commentAdmin = $this->drupalCreateUser([ + 'administer comments', + 'create article content', + 'edit own comments', + 'skip comment approval', + 'post comments', + 'access comments', + 'administer nodes', + ]); + $this->addDefaultCommentField('node', 'article'); + } + + /** + * Tests comment status field access. + */ + public function testCommentStatusFieldAccessStatus() { + $this->drupalLogin($this->nodeAuthor); + $this->drupalGet('node/add/article'); + $assert = $this->assertSession(); + $assert->fieldNotExists('comment[0][status]'); + $this->submitForm([ + 'title[0][value]' => 'Node 1', + ], t('Save and publish')); + $assert->fieldExists('subject[0][value]'); + $this->drupalLogin($this->commentAdmin); + $this->drupalGet('node/add/article'); + $assert->fieldExists('comment[0][status]'); + $this->submitForm([ + 'title[0][value]' => 'Node 2', + ], t('Save and publish')); + $assert->fieldExists('subject[0][value]'); + } + +} diff --git a/core/modules/config/config.module b/core/modules/config/config.module index 4f31e08f7bfa..874caac8b5f4 100644 --- a/core/modules/config/config.module +++ b/core/modules/config/config.module @@ -65,14 +65,17 @@ function config_file_download($uri) { $scheme = file_uri_scheme($uri); $target = file_uri_target($uri); if ($scheme == 'temporary' && $target == 'config.tar.gz') { - $request = \Drupal::request(); - $date = DateTime::createFromFormat('U', $request->server->get('REQUEST_TIME')); - $date_string = $date->format('Y-m-d-H-i'); - $hostname = str_replace('.', '-', $request->getHttpHost()); - $filename = 'config' . '-' . $hostname . '-' . $date_string . '.tar.gz'; - $disposition = 'attachment; filename="' . $filename . '"'; - return array( - 'Content-disposition' => $disposition, - ); + if (\Drupal::currentUser()->hasPermission('export configuration')) { + $request = \Drupal::request(); + $date = DateTime::createFromFormat('U', $request->server->get('REQUEST_TIME')); + $date_string = $date->format('Y-m-d-H-i'); + $hostname = str_replace('.', '-', $request->getHttpHost()); + $filename = 'config' . '-' . $hostname . '-' . $date_string . '.tar.gz'; + $disposition = 'attachment; filename="' . $filename . '"'; + return array( + 'Content-disposition' => $disposition, + ); + } + return -1; } } diff --git a/core/modules/config/src/Tests/ConfigExportUITest.php b/core/modules/config/src/Tests/ConfigExportUITest.php index 413ce29b5ce0..d3133d8dfddb 100644 --- a/core/modules/config/src/Tests/ConfigExportUITest.php +++ b/core/modules/config/src/Tests/ConfigExportUITest.php @@ -88,6 +88,12 @@ function testExport() { // Check the single export form doesn't have "form-required" elements. $this->drupalGet('admin/config/development/configuration/single/export'); $this->assertNoRaw('js-form-required form-required', 'No form required fields are found.'); + + // Ensure the temporary file is not available to users without the + // permission. + $this->drupalLogout(); + $this->drupalGet('system/temporary', ['query' => ['file' => 'config.tar.gz']]); + $this->assertResponse(403); } } diff --git a/core/tests/Drupal/KernelTests/Core/Routing/ExceptionHandlingTest.php b/core/tests/Drupal/KernelTests/Core/Routing/ExceptionHandlingTest.php index 7d11b817d9a8..85649484bb7f 100644 --- a/core/tests/Drupal/KernelTests/Core/Routing/ExceptionHandlingTest.php +++ b/core/tests/Drupal/KernelTests/Core/Routing/ExceptionHandlingTest.php @@ -185,6 +185,17 @@ public function testExceptionEscaping() { $this->setRawContent($response->getContent()); $this->assertRaw(Html::escape('Escaped content: <p> <br> <h3>')); $this->assertNoRaw('<p> <br> <h3>'); + + $string = '<script>alert(123);</script>'; + $request = Request::create('/router_test/test2?_format=json' . urlencode($string), 'GET'); + + $kernel = \Drupal::getContainer()->get('http_kernel'); + $response = $kernel->handle($request)->prepare($request); + // As the Content-type is text/plain the fact that the raw string is + // contained in the output does not matter. + $this->assertEqual($response->headers->get('Content-type'), 'text/plain; charset=UTF-8'); + $this->setRawContent($response->getContent()); + $this->assertRaw($string); } } -- GitLab