Problem/Motivation

It is not possible to create a comment via a REST POST because the field access is too strict.

Well, this is the way to add a comment using hal+json

{
    "_links": {
        "type": {
            "href": "http://d8/rest/type/comment/comment_type"
        },
        "http://d8/rest/relation/comment/comment/entity_id": [
            {
                "href": "http://d8/node/1"
            }
        ]
    },
    "entity_type": [{
            "value": "node"
        }],
    "entity_id":
      [{"target_id":"1"
}],
    "field_name": [{
        "value":"field_test_comment"
    }],
    "uid": [{
        "target_id":"1"
    }],
    "comment_body":[{
      "value":"HEYYYYYYYYYYY"
    }]
}

Here another example #2300827-19: How to POST a comment and other entities using entity references

So, if you avoid the validation, the comment is created as expected. It is not correct because we need to avoid to add the uid for example and of course we need the validation.

But, if you try to add the comment using the validation you will see this error:

{"error":"Access denied on creating field entity_id"}

or the same for entity_type...

If you remove the field from the json then you will see:

{"error":"Unprocessable Entity: validation failed.\nentity_id: This value should not be null.\n"}

And the problem is here (CommentAccessControlHandler::checkFieldAccess)

      // No user can change read-only fields.
      $read_only_fields = array(
        'hostname',
        'uuid',
        'cid',
        'thread',
        'comment_type',
        'pid',
        'entity_id',
        'entity_type',
        'field_name',
      );
      if (in_array($field_definition->getName(), $read_only_fields, TRUE)) {
        return AccessResult::forbidden();
      }

Proposed resolution

Some of the read-only fields are in fact editable when the comment is new. Update access controller to reflect this.

Remaining tasks

Reviews

Original report by @marthinal

Comments

marthinal’s picture

Issue summary: View changes
marthinal’s picture

Status: Needs work » Needs review
StatusFileSize
new1021 bytes

Working a little bit more on this I have detected that we set to 0 the uid by default. No uid is added when creating a comment programatically. This patch fixes the problem but maybe we should add this method(getCurrentUserId()) to the ContentEntityBase class...

larowlan’s picture

So that fixes entity type too, or are you fixing something else with that patch?

marthinal’s picture

StatusFileSize
new1.83 KB

@larowlan I was adding the uid by default when creating a comment programatically. The current patch fixes the entity type problem.

By default only cid and uuid are read only fields...

    $fields['cid'] = BaseFieldDefinition::create('integer')
      ->setLabel(t('Comment ID'))
      ->setDescription(t('The comment ID.'))
      <strong>->setReadOnly(TRUE)</strong>
      ->setSetting('unsigned', TRUE);

    $fields['uuid'] = BaseFieldDefinition::create('uuid')
      ->setLabel(t('UUID'))
      ->setDescription(t('The comment UUID.'))
     <strong> ->setReadOnly(TRUE);</strong>
larowlan’s picture

Yeah but this is going to impact #2227503: Apply formatters and widgets to Comment base fields - we have to make sure those fields don't show up in the edit form after we change the access controls.

Also, expect CommentFieldAccessTest will fail with current patch.

Status: Needs review » Needs work

The last submitted patch, 4: 2430669-4.patch, failed testing.

clemens.tolboom’s picture

Issue summary: View changes

In trying patch from #2 or #4 I cannot post a comment.

It fails on \Drupal\comment\Plugin\Validation\Constraint\CommentNameConstraintValidator maybe due to anonymous user?

I thought this issue was connected with #1964034: Pass entity_type into Serializer via context but are not sure anymore. To post a comment we now need lot of tricky data: entity_type, entity_id, field_name of which the first 2 are duplicates as their values are derivable from _links.

I've created #2469581: Add tests for comments CRUD for REST as we are chasing head for POST comments :-/

larowlan’s picture

Issue tags: +Needs reroll

tagging

larowlan’s picture

Assigned: Unassigned » larowlan

Looking

larowlan’s picture

Component: rest.module » comment.module
larowlan’s picture

Closed #2469581: Add tests for comments CRUD for REST in favour of this. Bringing in the tests to here.

alexpott’s picture

Creating @clemens.tolboom as requested by @larowlan

larowlan’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests, -Needs reroll
StatusFileSize
new6.97 KB
new8.41 KB

Brings in and finishes tests from #2469581: Add tests for comments CRUD for REST and changes implementation to make sure that the fields are only editable on create, when the entity is new.

The last submitted patch, 13: comment-rest-access-2430669.fail_.patch, failed testing.

larowlan’s picture

Issue summary: View changes

Issue summary changes

larowlan’s picture

Title: Cannot create comments from REST {"error":"Access denied on creating field entity_id"} » Cannot create comments from REST - field access is too strict
jibran’s picture

+++ b/core/modules/comment/src/CommentAccessControlHandler.php
@@ -80,15 +80,26 @@ protected function checkFieldAccess($operation, FieldDefinitionInterface $field_
+        'uuid',

How is this create only field?

larowlan’s picture

How is this create only field?

You can't edit uuid after an entity is created right?

larowlan’s picture

@jibran and I discussed this on IRC - whether uuid should be read only, or allowed on creation. Based on our existing tests we concluded that it is allowed on creation.

logs below

jibran
larowlan: ping
larowlan: My point was user can set uid field ever so why we are allowing it for comment creation.
8:55
larowlan
jibran: uuid or uid?
jibran: you are saying it should not be settable at all?
8:55
jibran
larowlan: uuid*
larowlan: afaik it is not settable at all
8:57
larowlan
jibran: it is via the serializer
jibran: e.g. content staging scenario where config depends on content with given uuid, you need to be able to nominate the uuid so reference remain intact
jibran: all of our rest tests enforce that
8:58
jibran
larowlan: does default content set uuid in yml files?
8:59
larowlan
jibran: e.g. all entity types in CreateTest explicitly test that you can send a uuid
jibran: yes default content does, thats how ER fields are dereferenced
8:59
jibran
larowlan: config importer use uuid to update configs.
larowlan: if we import new config with uuid using importer it throws error that config doesn't exist.
9:01
larowlan
jibran: this is content, not config
9:02
jibran
larowlan: "all entity types in CreateTest explicitly test that you can send a uuid" which test?
9:02
larowlan
jibran: if you can ship a view that relies on an entity for its header with a given uuid, then you have to be able to create content with that uuid
9:02
jibran
larowlan: I want to have a look
larowlan: yeah I know this case
9:02
larowlan
jibran: in rest CreateTest uses the serializer to turn an unsaved entity (created with EntityType::create) into hal+json
jibran: then it posts that
jibran: then it asserts all the fields sent were found in the entity after loading it back from the db
jibran: uuid is one of those fields
jibran: some fields are explicitly unset before serializing (e.g. changed)
jibran’s picture

Status: Needs review » Reviewed & tested by the community

Patch has a dedicated test for access check which is good and it also has a comment creation test using rest api which fixes the original bug so it's awesome. Code changes look good so RTBC.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

This issue addresses a major bug and is allowed per https://www.drupal.org/core/beta-changes. Committed db390cd and pushed to 8.0.x. Thanks!

  • alexpott committed db390cd on 8.0.x
    Issue #2430669 by larowlan, marthinal, clemens.tolboom, jibran: Cannot...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.