From 1c94124a5a037eead548aef2e2b3cbb512303db6 Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Thu, 8 Jan 2015 10:36:12 +0000
Subject: [PATCH] Issue #2344151 by larowlan: Comment field access doesn't work
 if $items isn't present

---
 .../src/CommentAccessControlHandler.php       |  22 +-
 .../src/Tests/Views/CommentRestExportTest.php |  68 +++
 .../src/Tests/Views/CommentTestBase.php       |   3 +-
 .../views.view.test_comment_rest.yml          | 388 ++++++++++++++++++
 4 files changed, 474 insertions(+), 7 deletions(-)
 create mode 100644 core/modules/comment/src/Tests/Views/CommentRestExportTest.php
 create mode 100644 core/modules/comment/tests/modules/comment_test_views/test_views/views.view.test_comment_rest.yml

diff --git a/core/modules/comment/src/CommentAccessControlHandler.php b/core/modules/comment/src/CommentAccessControlHandler.php
index 0bc58ce77b38..7d6504c9e51a 100644
--- a/core/modules/comment/src/CommentAccessControlHandler.php
+++ b/core/modules/comment/src/CommentAccessControlHandler.php
@@ -57,8 +57,6 @@ protected function checkCreateAccess(AccountInterface $account, array $context,
    * {@inheritdoc}
    */
   protected function checkFieldAccess($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
-    /** @var \Drupal\comment\CommentInterface $entity */
-    $entity = $items->getEntity();
     if ($operation == 'edit') {
       // Only users with the "administer comments" permission can edit
       // administrative fields.
@@ -87,13 +85,22 @@ protected function checkFieldAccess($operation, FieldDefinitionInterface $field_
       if (in_array($field_definition->getName(), $read_only_fields, TRUE)) {
         return AccessResult::forbidden();
       }
-      $commented_entity = $entity->getCommentedEntity();
-      $anonymous_contact = $commented_entity->get($entity->getFieldName())->getFieldDefinition()->getSetting('anonymous_contact');
 
       // If the field is configured to accept anonymous contact details - admins
       // can edit name, homepage and mail. Anonymous users can also fill in the
       // fields on comment creation.
       if (in_array($field_definition->getName(), ['name', 'mail', 'homepage'], TRUE)) {
+        if (!$items) {
+          // We cannot make a decision about access to edit these fields if we
+          // don't have any items and therefore cannot determine the Comment
+          // entity. In this case we err on the side of caution and prevent edit
+          // access.
+          return AccessResult::forbidden();
+        }
+        /** @var \Drupal\comment\CommentInterface $entity */
+        $entity = $items->getEntity();
+        $commented_entity = $entity->getCommentedEntity();
+        $anonymous_contact = $commented_entity->get($entity->getFieldName())->getFieldDefinition()->getSetting('anonymous_contact');
         $admin_access = AccessResult::allowedIfHasPermission($account, 'administer comments');
         $anonymous_access = AccessResult::allowedIf($entity->isNew() && $account->isAnonymous() && $anonymous_contact != COMMENT_ANONYMOUS_MAYNOT_CONTACT && $account->hasPermission('post comments'))
           ->cachePerRole()
@@ -105,14 +112,17 @@ protected function checkFieldAccess($operation, FieldDefinitionInterface $field_
     }
 
     if ($operation == 'view') {
+      $entity = $items ? $items->getEntity() : NULL;
       // Admins can view any fields except hostname, other users need both the
       // "access comments" permission and for the comment to be published. The
       // mail field is hidden from non-admins.
       $admin_access = AccessResult::allowedIf($account->hasPermission('administer comments') && $field_definition->getName() != 'hostname')
         ->cachePerRole();
-      $anonymous_access = AccessResult::allowedIf($account->hasPermission('access comments') && $entity->isPublished() && !in_array($field_definition->getName(), array('mail', 'hostname'), TRUE))
-        ->cacheUntilEntityChanges($entity)
+      $anonymous_access = AccessResult::allowedIf($account->hasPermission('access comments') && (!$entity || $entity->isPublished()) && !in_array($field_definition->getName(), array('mail', 'hostname'), TRUE))
         ->cachePerRole();
+      if ($entity) {
+        $anonymous_access->cacheUntilEntityChanges($entity);
+      }
       return $admin_access->orIf($anonymous_access);
     }
     return parent::checkFieldAccess($operation, $field_definition, $account, $items);
diff --git a/core/modules/comment/src/Tests/Views/CommentRestExportTest.php b/core/modules/comment/src/Tests/Views/CommentRestExportTest.php
new file mode 100644
index 000000000000..8cc432d1f191
--- /dev/null
+++ b/core/modules/comment/src/Tests/Views/CommentRestExportTest.php
@@ -0,0 +1,68 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\comment\Tests\Views\CommentRestExportTest.
+ */
+
+namespace Drupal\comment\Tests\Views;
+
+use Drupal\Component\Serialization\Json;
+
+/**
+ * Tests a comment rest export view.
+ *
+ * @group comment
+ */
+class CommentRestExportTest extends CommentTestBase {
+
+  /**
+   * Views used by this test.
+   *
+   * @var array
+   */
+  public static $testViews = ['test_comment_rest'];
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['node', 'comment', 'comment_test_views', 'rest', 'hal'];
+
+  protected function setUp() {
+    parent::setUp();
+    // Add another anonymous comment.
+    $comment = array(
+      'uid' => 0,
+      'entity_id' => $this->nodeUserCommented->id(),
+      'entity_type' => 'node',
+      'field_name' => 'comment',
+      'subject' => 'A lot, apparently',
+      'cid' => '',
+      'pid' => $this->comment->id(),
+      'mail' => 'someone@example.com',
+      'name' => 'bobby tables',
+      'hostname' => 'public.example.com',
+    );
+    $this->comment = entity_create('comment', $comment);
+    $this->comment->save();
+  }
+
+
+  /**
+   * Test comment row.
+   */
+  public function testCommentRestExport() {
+    $this->drupalGet(sprintf('node/%d/comments', $this->nodeUserCommented->id()), [], ['Accept' => 'application/hal+json']);
+    $this->assertResponse(200);
+    $contents = Json::decode($this->getRawContent());
+    $this->assertEqual($contents[0]['subject'], 'How much wood would a woodchuck chuck');
+    $this->assertEqual($contents[1]['subject'], 'A lot, apparently');
+    $this->assertEqual(count($contents), 2);
+
+    // Ensure field-level access is respected - user shouldn't be able to see
+    // mail or hostname fields.
+    $this->assertNoText('someone@example.com');
+    $this->assertNoText('public.example.com');
+  }
+
+}
diff --git a/core/modules/comment/src/Tests/Views/CommentTestBase.php b/core/modules/comment/src/Tests/Views/CommentTestBase.php
index 306ab24746f3..7d4705f32fe6 100644
--- a/core/modules/comment/src/Tests/Views/CommentTestBase.php
+++ b/core/modules/comment/src/Tests/Views/CommentTestBase.php
@@ -79,9 +79,10 @@ protected function setUp() {
       'entity_id' => $this->nodeUserCommented->id(),
       'entity_type' => 'node',
       'field_name' => 'comment',
+      'subject' => 'How much wood would a woodchuck chuck',
       'cid' => '',
       'pid' => '',
-      'node_type' => '',
+      'mail' => 'someone@example.com',
     );
     $this->comment = entity_create('comment', $comment);
     $this->comment->save();
diff --git a/core/modules/comment/tests/modules/comment_test_views/test_views/views.view.test_comment_rest.yml b/core/modules/comment/tests/modules/comment_test_views/test_views/views.view.test_comment_rest.yml
new file mode 100644
index 000000000000..bd04a83c59c3
--- /dev/null
+++ b/core/modules/comment/tests/modules/comment_test_views/test_views/views.view.test_comment_rest.yml
@@ -0,0 +1,388 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.storage.comment.comment_body
+  module:
+    - comment
+    - node
+    - rest
+    - text
+    - user
+id: test_comment_rest
+label: 'Comments by node'
+module: views
+description: ''
+tag: ''
+base_table: comment
+base_field: cid
+core: 8.x
+display:
+  default:
+    display_plugin: default
+    id: default
+    display_title: Master
+    position: 0
+    display_options:
+      access:
+        type: perm
+        options:
+          perm: 'access content'
+      cache:
+        type: none
+        options: {  }
+      query:
+        type: views_query
+        options:
+          disable_sql_rewrite: false
+          distinct: false
+          replica: false
+          query_comment: false
+          query_tags: {  }
+      exposed_form:
+        type: basic
+        options:
+          submit_button: Apply
+          reset_button: false
+          reset_button_label: Reset
+          exposed_sorts_label: 'Sort by'
+          expose_sort_order: true
+          sort_asc_label: Asc
+          sort_desc_label: Desc
+      pager:
+        type: full
+        options:
+          items_per_page: 10
+          offset: 0
+          id: 0
+          total_pages: null
+          expose:
+            items_per_page: false
+            items_per_page_label: 'Items per page'
+            items_per_page_options: '5, 10, 25, 50'
+            items_per_page_options_all: false
+            items_per_page_options_all_label: '- All -'
+            offset: false
+            offset_label: Offset
+          tags:
+            previous: '‹ previous'
+            next: 'next ›'
+            first: '« first'
+            last: 'last »'
+          quantity: 9
+      style:
+        type: serializer
+      row:
+        type: fields
+        options:
+          inline: {  }
+          separator: ''
+          hide_empty: false
+          default_field_elements: true
+      relationships:
+        node:
+          id: node
+          table: comment_field_data
+          field: node
+          required: true
+          plugin_id: standard
+          relationship: none
+          group_type: group
+          admin_label: Content
+      fields:
+        subject:
+          id: subject
+          table: comment_field_data
+          field: subject
+          relationship: none
+          group_type: group
+          entity_type: comment
+          entity_field: subject
+          admin_label: ''
+          label: ''
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: ''
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          link_to_comment: true
+          link_to_entity: false
+          plugin_id: comment
+        name:
+          id: name
+          table: comment_field_data
+          field: name
+          entity_type: comment
+          entity_field: name
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: ''
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          link_to_user: false
+          plugin_id: comment_username
+        created:
+          id: created
+          table: comment_field_data
+          field: created
+          entity_type: comment
+          entity_field: created
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: ''
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          date_format: long
+          custom_date_format: ''
+          timezone: ''
+          plugin_id: date
+        comment_body:
+          id: comment_body
+          table: comment__comment_body
+          field: comment_body
+          relationship: none
+          entity_type: comment
+          entity_field: comment_body
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: ''
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: text_default
+          settings: {  }
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: all
+          delta_offset: '0'
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          plugin_id: field
+      filters: {  }
+      sorts: {  }
+      header: {  }
+      footer: {  }
+      empty: {  }
+      arguments:
+        nid:
+          id: nid
+          table: node
+          field: nid
+          relationship: node
+          group_type: group
+          admin_label: ''
+          default_action: default
+          exception:
+            value: all
+            title_enable: false
+            title: All
+          title_enable: false
+          title: ''
+          default_argument_type: node
+          default_argument_skip_url: false
+          summary_options:
+            base_path: ''
+            count: true
+            items_per_page: 25
+            override: false
+          summary:
+            sort_order: asc
+            number_of_records: 0
+            format: default_summary
+          specify_validation: false
+          validate:
+            type: none
+            fail: 'not found'
+          validate_options: {  }
+          break_phrase: false
+          not: false
+          plugin_id: numeric
+      field_langcode: '***LANGUAGE_language_content***'
+      field_langcode_add_to_query: null
+      display_extenders: {  }
+  rest_export_1:
+    display_plugin: rest_export
+    id: rest_export_1
+    display_title: 'REST export'
+    position: 1
+    display_options:
+      field_langcode: '***LANGUAGE_language_content***'
+      field_langcode_add_to_query: null
+      path: node/%node/comments
+      pager:
+        type: some
+        options:
+          items_per_page: 10
+          offset: 0
+      style:
+        type: serializer
+        options:
+          uses_fields: false
+          formats:
+            json: json
+      row:
+        type: data_field
+        options:
+          field_options:
+            subject:
+              alias: ''
+              raw_output: true
+            name:
+              alias: ''
+              raw_output: true
+      display_extenders: {  }
-- 
GitLab