Issue #2946073 by claudiu.cristea, mpp, neclimdul, Berdir, idimopoulos, remkoklein: Node grant access check missing cacheable dependency on node

(cherry picked from commit 6685ea27ee)
merge-requests/64/head
catch 2020-05-11 09:05:16 +01:00
parent 3c76ed2503
commit 4732d9f44a
3 changed files with 78 additions and 2 deletions

View File

@ -3,6 +3,7 @@
namespace Drupal\node;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Cache\RefinableCacheableDependencyInterface;
use Drupal\Core\Entity\EntityHandlerInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
@ -104,7 +105,16 @@ class NodeAccessControlHandler extends EntityAccessControlHandler implements Nod
}
// Evaluate node grants.
return $this->grantStorage->access($node, $operation, $account);
$access_result = $this->grantStorage->access($node, $operation, $account);
if ($operation === 'view' && $access_result instanceof RefinableCacheableDependencyInterface) {
// Node variations can affect the access to the node. For instance, the
// access result cache varies on the node's published status. Only the
// 'view' node grant can currently be cached. The 'update' and 'delete'
// grants are already marked as uncacheable in the node grant storage.
// @see \Drupal\node\NodeGrantDatabaseStorage::access()
$access_result->addCacheableDependency($node);
}
return $access_result;
}
/**

View File

@ -71,7 +71,7 @@ class NodeGrantDatabaseStorage implements NodeGrantDatabaseStorageInterface {
// Return the equivalent of the default grant, defined by
// self::writeDefault().
if ($operation === 'view') {
return AccessResult::allowedIf($node->isPublished())->addCacheableDependency($node);
return AccessResult::allowedIf($node->isPublished());
}
else {
return AccessResult::neutral();

View File

@ -0,0 +1,66 @@
<?php
namespace Drupal\Tests\node\Functional;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\node\Entity\NodeType;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\field\Traits\EntityReferenceTestTrait;
/**
* Tests node view access cacheability with node grants.
*
* @group node
*/
class NodeAccessCacheabilityWithNodeGrants extends BrowserTestBase {
use EntityReferenceTestTrait;
/**
* {@inheritdoc}
*/
protected static $modules = ['node', 'node_test'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* Tests node view access cacheability with node grants.
*/
public function testAccessCacheabilityWithNodeGrants() {
NodeType::create(['type' => 'page'])->save();
$this->createEntityReferenceField('node', 'page', 'ref', 'Ref', 'node');
EntityViewDisplay::create([
'targetEntityType' => 'node',
'bundle' => 'page',
'mode' => 'default',
'status' => TRUE,
])->setComponent('ref', ['type' => 'entity_reference_label'])
->save();
// Check that at least one module implements hook_node_grants() as this test
// only tests this case.
// @see \node_test_node_grants()
$node_grants_implementations = \Drupal::moduleHandler()->getImplementations('node_grants');
$this->assertNotEmpty($node_grants_implementations);
// Create an unpublished node.
$referenced = $this->createNode(['status' => FALSE]);
// Create a node referencing $referenced.
$node = $this->createNode(['ref' => $referenced]);
// Check that the referenced entity link doesn't show on the host entity.
$this->drupalGet($node->toUrl());
$this->assertSession()->linkNotExists($referenced->label());
// Publish the referenced node.
$referenced->setPublished()->save();
// Check that the referenced entity link shows on the host entity.
$this->getSession()->reload();
$this->assertSession()->linkExists($referenced->label());
}
}