I have a list of articles, some of them are published and others are not published.

If I do an anonymous request to:

GET /api/node/article/1234?_format=api_json

And node 1234 is not published I got:

{"errors":[{"title":"Forbidden","status":403,"detail":"The current user is not allowed to GET the selected resource.","links":{"info":"http:\/\/www.w3.org\/Protocols\/rfc2616\/rfc2616-sec10.html#sec10.4.4"},"code":0}]}

Which makes sense.

But, when I do:

GET /api/node/article?_format=api_json

The article 1234 is listed on the results. The permissions to see published content are not respected.

My understanding is this is not applicable to all entities (not all entities have status to restrict access), but this is valid at least for nodes.

Comments

dagmar created an issue. See original summary.

e0ipso’s picture

Title: Access check for listings » [BUGFIX] Check for individual entity access in listings
e0ipso’s picture

Again, thanks for reporting this. You are killing it @dagmar!

Anonymous’s picture

I can confirm the same issue.

I've found that the node access is checked when requesting a single one but, in the other hand,
when requesting a list of resources the access isn't checked.

Perhaps a filter by status can be added when the query is formed, isntead iterating by all the results checking the access individually.

e0ipso’s picture

Assigned: Unassigned » e0ipso
StatusFileSize
new1.32 KB

Added a test that proves the error.

e0ipso’s picture

Status: Active » Needs review

Making the testbot execute the tests and seeing them fail.

Status: Needs review » Needs work

The last submitted patch, 5: 2778627--individual-entity-access--5.patch, failed testing.

The last submitted patch, 5: 2778627--individual-entity-access--5.patch, failed testing.

e0ipso’s picture

Since the access handlers are not executed during the entity queries, we need to manually check for the errors in the collection.

Then we need to treat the errors as if they were includes and bubble them up to the top level. That way we can effectively have something like:

{
  "data": [{…}],
  "errors": [{…}]
}
e0ipso’s picture

It turns out that for it to be valid JSON API we need something like:

We'll need an extension to document the opinionated stance towards errored entities in collections.

e0ipso’s picture

Status: Needs work » Needs review
StatusFileSize
new26.03 KB

This one was tricky.

e0ipso’s picture

Status: Needs review » Needs work

The last submitted patch, 11: 2778627--individual-entity-access--11.patch, failed testing.

The last submitted patch, 11: 2778627--individual-entity-access--11.patch, failed testing.

The last submitted patch, 11: 2778627--individual-entity-access--11.patch, failed testing.

The last submitted patch, 11: 2778627--individual-entity-access--11.patch, failed testing.

e0ipso’s picture

Status: Needs work » Needs review
StatusFileSize
new26.18 KB
new321 bytes
dawehner’s picture

  1. +++ b/src/Normalizer/Value/DocumentRootNormalizerValue.php
    @@ -107,7 +108,14 @@ class DocumentRootNormalizerValue implements DocumentRootNormalizerValueInterfac
    +      if ($normalizer_value instanceof HttpExceptionNormalizerValue) {
    +        $previous_errors = NestedArray::getValue($rasterized, ['meta', 'errors']) ?: [];
    +        // Add the errors to the pre-existing errors.
    +        $rasterized['meta']['errors'] = array_merge($previous_errors, $normalizer_value->rasterizeValue());
    +      }
    

    I totally love how this patch encodes more things in pure return objects than other potential solutions, like setting some data somewhere.

  2. +++ b/src/Resource/EntityResource.php
    @@ -226,9 +228,17 @@ class EntityResource implements EntityResourceInterface {
    +    $access_info = array_column($collection_data, 'access');
    +    array_walk($access_info, function ($access) use ($response) {
    +      $response->addCacheableDependency($access);
    +    });
    

    This is just lovely. For better readability I would have separated access related stuff with new lines.

wim leers’s picture

#777578: Add an entity query access API and deprecate hook_query_ENTITY_TYPE_access_alter() would help with this a lot; then you wouldn't need to call access() on every individual entity anymore.

Which makes me wonder whether this should actually avoid calling $entity->access() if $entity instanceof NodeInterface? Listings are always per entity type, so if the entity type is 'node', then JSON API should rely on that instead of this?

wim leers’s picture

David Hernández’s picture

I'm not sure but this might be the same issue as #2807185: [BUGFIX] Handle relationships when target resource is not accessible or at least related with it.

e0ipso’s picture

StatusFileSize
new26.19 KB
new878 bytes

Addressed the feedback provided by @dawehner.

@Wim Leers afaik the logic in \Drupal\Node\NodeAccessControlHandler::access is not checked during the EntityQuery. If that is the case then this check is indeed needed and additional to the grants system. I may be wrong though, I'm a bit fuzzy on this area.

  • e0ipso committed 7a2902d on 8.x-1.x
    Issue #2778627 by e0ipso: [BUGFIX] Check for individual entity access in...
e0ipso’s picture

Status: Needs review » Fixed

There is a question still open for @Wim Leers, but this code will still be needed atm regardless of the answer.

Status: Fixed » Closed (fixed)

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