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