summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLee Rowlands2017-10-18 22:37:34 (GMT)
committerLee Rowlands2017-10-18 22:37:34 (GMT)
commita13555adf663bee72fe88fc1da2d5c1efc2a51e5 (patch)
treeaef8ec0ee09a67faf3db2253d6b2f46cbcfd2f8d
parent5abe312c943e2b5b62fcbe85588201560c635163 (diff)
Issue #2866666 by vaplas, Wim Leers, dawehner, gaurav.kapoor, pk188, tstoeckler, effulgentsia: Add proper access handlers for view and form displays
-rw-r--r--core/lib/Drupal/Core/Entity/Entity/Access/EntityFormDisplayAccessControlHandler.php24
-rw-r--r--core/lib/Drupal/Core/Entity/Entity/Access/EntityViewDisplayAccessControlHandler.php24
-rw-r--r--core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php3
-rw-r--r--core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php3
-rw-r--r--core/modules/field/tests/src/Unit/FieldConfigAccessControlHandlerTest.php4
-rw-r--r--core/modules/field/tests/src/Unit/FieldStorageConfigAccessControlHandlerTest.php14
-rw-r--r--core/tests/Drupal/Tests/Core/Entity/Access/EntityFormDisplayAccessControlHandlerTest.php244
-rw-r--r--core/tests/Drupal/Tests/Core/Entity/Access/EntityViewDisplayAccessControlHandlerTest.php44
8 files changed, 347 insertions, 13 deletions
diff --git a/core/lib/Drupal/Core/Entity/Entity/Access/EntityFormDisplayAccessControlHandler.php b/core/lib/Drupal/Core/Entity/Entity/Access/EntityFormDisplayAccessControlHandler.php
new file mode 100644
index 0000000..d48a619
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Entity/Access/EntityFormDisplayAccessControlHandler.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace Drupal\Core\Entity\Entity\Access;
+
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Entity\EntityAccessControlHandler;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Session\AccountInterface;
+
+/**
+ * Provides an entity access control handler for form displays.
+ */
+class EntityFormDisplayAccessControlHandler extends EntityAccessControlHandler {
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
+ /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $entity */
+ return parent::checkAccess($entity, $operation, $account)
+ ->orIf(AccessResult::allowedIfHasPermission($account, 'administer ' . $entity->getTargetEntityTypeId() . ' form display'));
+ }
+
+}
diff --git a/core/lib/Drupal/Core/Entity/Entity/Access/EntityViewDisplayAccessControlHandler.php b/core/lib/Drupal/Core/Entity/Entity/Access/EntityViewDisplayAccessControlHandler.php
new file mode 100644
index 0000000..41122a2
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Entity/Access/EntityViewDisplayAccessControlHandler.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace Drupal\Core\Entity\Entity\Access;
+
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Entity\EntityAccessControlHandler;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Session\AccountInterface;
+
+/**
+ * Provides an entity access control handler for displays.
+ */
+class EntityViewDisplayAccessControlHandler extends EntityAccessControlHandler {
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
+ /** @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $entity */
+ return parent::checkAccess($entity, $operation, $account)
+ ->orIf(AccessResult::allowedIfHasPermission($account, 'administer ' . $entity->getTargetEntityTypeId() . ' display'));
+ }
+
+}
diff --git a/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php b/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php
index faa6d0d..6c31df5 100644
--- a/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php
+++ b/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php
@@ -23,6 +23,9 @@ use Symfony\Component\Validator\ConstraintViolationListInterface;
* "id" = "id",
* "status" = "status"
* },
+ * handlers = {
+ * "access" = "\Drupal\Core\Entity\Entity\Access\EntityFormDisplayAccessControlHandler",
+ * },
* config_export = {
* "id",
* "targetEntityType",
diff --git a/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php b/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php
index 74b15b6..1604e31 100644
--- a/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php
+++ b/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php
@@ -21,6 +21,9 @@ use Drupal\Core\TypedData\TranslatableInterface;
* "id" = "id",
* "status" = "status"
* },
+ * handlers = {
+ * "access" = "\Drupal\Core\Entity\Entity\Access\EntityViewDisplayAccessControlHandler",
+ * },
* config_export = {
* "id",
* "targetEntityType",
diff --git a/core/modules/field/tests/src/Unit/FieldConfigAccessControlHandlerTest.php b/core/modules/field/tests/src/Unit/FieldConfigAccessControlHandlerTest.php
index 0ad8265..f7c3c0b 100644
--- a/core/modules/field/tests/src/Unit/FieldConfigAccessControlHandlerTest.php
+++ b/core/modules/field/tests/src/Unit/FieldConfigAccessControlHandlerTest.php
@@ -21,9 +21,9 @@ class FieldConfigAccessControlHandlerTest extends FieldStorageConfigAccessContro
parent::setUp();
$this->entity = new FieldConfig([
- 'field_name' => $this->fieldStorage->getName(),
+ 'field_name' => $this->entity->getName(),
'entity_type' => 'node',
- 'fieldStorage' => $this->fieldStorage,
+ 'fieldStorage' => $this->entity,
'bundle' => 'test_bundle',
'field_type' => 'test_field',
], 'node');
diff --git a/core/modules/field/tests/src/Unit/FieldStorageConfigAccessControlHandlerTest.php b/core/modules/field/tests/src/Unit/FieldStorageConfigAccessControlHandlerTest.php
index 1d47017..83abd3c 100644
--- a/core/modules/field/tests/src/Unit/FieldStorageConfigAccessControlHandlerTest.php
+++ b/core/modules/field/tests/src/Unit/FieldStorageConfigAccessControlHandlerTest.php
@@ -53,17 +53,10 @@ class FieldStorageConfigAccessControlHandlerTest extends UnitTestCase {
protected $member;
/**
- * The mocked test field storage config.
+ * The FieldStorageConfig entity used for testing.
*
* @var \Drupal\field\FieldStorageConfigInterface
*/
- protected $fieldStorage;
-
- /**
- * The main entity used for testing.
- *
- * @var \Drupal\Core\Config\Entity\ConfigEntityInterface
- */
protected $entity;
/**
@@ -160,7 +153,7 @@ class FieldStorageConfigAccessControlHandlerTest extends UnitTestCase {
$entity_manager->setContainer($container);
\Drupal::setContainer($container);
- $this->fieldStorage = new FieldStorageConfig([
+ $this->entity = new FieldStorageConfig([
'field_name' => 'test_field',
'entity_type' => 'node',
'type' => 'boolean',
@@ -168,7 +161,6 @@ class FieldStorageConfigAccessControlHandlerTest extends UnitTestCase {
'uuid' => '6f2f259a-f3c7-42ea-bdd5-111ad1f85ed1',
]);
- $this->entity = $this->fieldStorage;
$this->accessControlHandler = $storage_access_control_handler;
}
@@ -195,7 +187,7 @@ class FieldStorageConfigAccessControlHandlerTest extends UnitTestCase {
$this->assertAllowOperations([], $this->anon);
$this->assertAllowOperations(['view', 'update', 'delete'], $this->member);
- $this->fieldStorage->setLocked(TRUE)->save();
+ $this->entity->setLocked(TRUE)->save();
// Unfortunately, EntityAccessControlHandler has a static cache, which we
// therefore must reset manually.
$this->accessControlHandler->resetCache();
diff --git a/core/tests/Drupal/Tests/Core/Entity/Access/EntityFormDisplayAccessControlHandlerTest.php b/core/tests/Drupal/Tests/Core/Entity/Access/EntityFormDisplayAccessControlHandlerTest.php
new file mode 100644
index 0000000..e4b8bf1
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Entity/Access/EntityFormDisplayAccessControlHandlerTest.php
@@ -0,0 +1,244 @@
+<?php
+
+namespace Drupal\Tests\Core\Entity\Access;
+
+use Drupal\Component\Plugin\PluginManagerInterface;
+use Drupal\Component\Uuid\UuidInterface;
+use Drupal\Core\Cache\Context\CacheContextsManager;
+use Drupal\Core\Config\Entity\ConfigEntityTypeInterface;
+use Drupal\Core\DependencyInjection\Container;
+use Drupal\Core\Entity\Entity\Access\EntityFormDisplayAccessControlHandler;
+use Drupal\Core\Entity\Entity\EntityFormDisplay;
+use Drupal\Core\Entity\EntityFieldManagerInterface;
+use Drupal\Core\Entity\EntityManager;
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Field\FieldTypePluginManagerInterface;
+use Drupal\Core\Field\FormatterPluginManager;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\Render\RendererInterface;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\Core\Entity\Entity\Access\EntityFormDisplayAccessControlHandler
+ * @group Entity
+ */
+class EntityFormDisplayAccessControlHandlerTest extends UnitTestCase {
+
+ /**
+ * The field storage config access controller to test.
+ *
+ * @var \Drupal\field\FieldStorageConfigAccessControlHandler
+ */
+ protected $accessControlHandler;
+
+ /**
+ * The mock module handler.
+ *
+ * @var \Drupal\Core\Extension\ModuleHandlerInterface
+ */
+ protected $moduleHandler;
+
+ /**
+ * The mock account without field storage config access.
+ *
+ * @var \Drupal\Core\Session\AccountInterface
+ */
+ protected $anon;
+
+ /**
+ * The mock account with EntityFormDisplay access.
+ *
+ * @var \Drupal\Core\Session\AccountInterface
+ */
+ protected $member;
+
+ /**
+ * The mock account with EntityFormDisplay access via parent access check.
+ *
+ * @var \Drupal\Core\Session\AccountInterface
+ */
+ protected $parent_member;
+
+ /**
+ * The EntityFormDisplay entity used for testing.
+ *
+ * @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface
+ */
+ protected $entity;
+
+
+ /**
+ * Returns a mock Entity Type Manager.
+ *
+ * @return EntityTypeManagerInterface
+ * The mocked entity type manager.
+ */
+ protected function getEntityTypeManager() {
+ $entity_type_manager = $this->prophesize(EntityTypeManagerInterface::class);
+ return $entity_type_manager->reveal();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ parent::setUp();
+
+ $this->anon = $this->getMock(AccountInterface::class);
+ $this->anon
+ ->expects($this->any())
+ ->method('hasPermission')
+ ->will($this->returnValue(FALSE));
+ $this->anon
+ ->expects($this->any())
+ ->method('id')
+ ->will($this->returnValue(0));
+
+ $this->member = $this->getMock(AccountInterface::class);
+ $this->member
+ ->expects($this->any())
+ ->method('hasPermission')
+ ->will($this->returnValueMap([
+ ['administer foobar form display', TRUE],
+ ]));
+ $this->member
+ ->expects($this->any())
+ ->method('id')
+ ->will($this->returnValue(2));
+
+ $this->parent_member = $this->getMock(AccountInterface::class);
+ $this->parent_member
+ ->expects($this->any())
+ ->method('hasPermission')
+ ->will($this->returnValueMap([
+ ['Llama', TRUE],
+ ]));
+ $this->parent_member
+ ->expects($this->any())
+ ->method('id')
+ ->will($this->returnValue(3));
+
+ $entity_form_display_entity_type = $this->getMock(ConfigEntityTypeInterface::class);
+ $entity_form_display_entity_type->expects($this->any())
+ ->method('getAdminPermission')
+ ->will($this->returnValue('Llama'));
+ $entity_form_display_entity_type
+ ->expects($this->any())
+ ->method('getKey')
+ ->will($this->returnValueMap([
+ ['langcode', 'langcode'],
+ ]));
+ $entity_form_display_entity_type->expects($this->any())
+ ->method('entityClassImplements')
+ ->will($this->returnValue(TRUE));
+ $entity_form_display_entity_type->expects($this->any())
+ ->method('getConfigPrefix')
+ ->willReturn('');
+
+ $this->moduleHandler = $this->getMock(ModuleHandlerInterface::class);
+ $this->moduleHandler
+ ->expects($this->any())
+ ->method('getImplementations')
+ ->will($this->returnValue([]));
+ $this->moduleHandler
+ ->expects($this->any())
+ ->method('invokeAll')
+ ->will($this->returnValue([]));
+
+ $storage_access_control_handler = new EntityFormDisplayAccessControlHandler($entity_form_display_entity_type);
+ $storage_access_control_handler->setModuleHandler($this->moduleHandler);
+
+ $entity_type_manager = $this->getMock(EntityTypeManagerInterface::class);
+ $entity_type_manager
+ ->expects($this->any())
+ ->method('getStorage')
+ ->willReturnMap([
+ ['entity_display', $this->getMock(EntityStorageInterface::class)],
+ ]);
+ $entity_type_manager
+ ->expects($this->any())
+ ->method('getAccessControlHandler')
+ ->willReturnMap([
+ ['entity_display', $storage_access_control_handler],
+ ]);
+ $entity_type_manager
+ ->expects($this->any())
+ ->method('getFieldDefinitions')
+ ->willReturn([]);
+ $entity_type_manager
+ ->expects($this->any())
+ ->method('getDefinition')
+ ->will($this->returnValue($entity_form_display_entity_type));
+
+ $entity_field_manager = $this->getMock(EntityFieldManagerInterface::class);
+ $entity_field_manager->expects($this->any())
+ ->method('getFieldDefinitions')
+ ->will($this->returnValue([]));
+
+ $entity_manager = new EntityManager();
+ $container = new Container();
+ $container->set('entity.manager', $entity_manager);
+ $container->set('entity_type.manager', $entity_type_manager);
+ $container->set('entity_field.manager', $entity_field_manager);
+ $container->set('language_manager', $this->getMock(LanguageManagerInterface::class));
+ $container->set('plugin.manager.field.widget', $this->prophesize(PluginManagerInterface::class));
+ $container->set('plugin.manager.field.field_type', $this->getMock(FieldTypePluginManagerInterface::class));
+ $container->set('plugin.manager.field.formatter', $this->prophesize(FormatterPluginManager::class));
+ $container->set('uuid', $this->getMock(UuidInterface::class));
+ $container->set('renderer', $this->getMock(RendererInterface::class));
+ $container->set('cache_contexts_manager', $this->prophesize(CacheContextsManager::class));
+ // Inject the container into entity.manager so it can defer to
+ // entity_type.manager.
+ $entity_manager->setContainer($container);
+ \Drupal::setContainer($container);
+
+ $this->entity = new EntityFormDisplay([
+ 'targetEntityType' => 'foobar',
+ 'bundle' => 'bazqux',
+ 'mode' => 'default',
+ 'id' => 'foobar.bazqux.default',
+ 'uuid' => '6f2f259a-f3c7-42ea-bdd5-111ad1f85ed1',
+ ], 'entity_display');
+
+ $this->accessControlHandler = $storage_access_control_handler;
+ }
+
+ /**
+ * Assert method to verify the access by operations.
+ *
+ * @param array $allow_operations
+ * A list of allowed operations.
+ * @param \Drupal\Core\Session\AccountInterface $user
+ * The account to use for get access.
+ */
+ public function assertAllowOperations(array $allow_operations, AccountInterface $user) {
+ foreach (['view', 'update', 'delete'] as $operation) {
+ $expected = in_array($operation, $allow_operations);
+ $actual = $this->accessControlHandler->access($this->entity, $operation, $user);
+ $this->assertSame($expected, $actual, "Access problem with '$operation' operation.");
+ }
+ }
+
+ /**
+ * @covers ::access
+ * @covers ::checkAccess
+ */
+ public function testAccess() {
+ $this->assertAllowOperations([], $this->anon);
+ $this->assertAllowOperations(['view', 'update', 'delete'], $this->member);
+ $this->assertAllowOperations(['view', 'update', 'delete'], $this->parent_member);
+
+ $this->entity->enforceIsNew(TRUE)->save();
+ // Unfortunately, EntityAccessControlHandler has a static cache, which we
+ // therefore must reset manually.
+ $this->accessControlHandler->resetCache();
+
+ $this->assertAllowOperations([], $this->anon);
+ $this->assertAllowOperations(['view', 'update'], $this->member);
+ $this->assertAllowOperations(['view', 'update'], $this->parent_member);
+ }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/Entity/Access/EntityViewDisplayAccessControlHandlerTest.php b/core/tests/Drupal/Tests/Core/Entity/Access/EntityViewDisplayAccessControlHandlerTest.php
new file mode 100644
index 0000000..b798681
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Entity/Access/EntityViewDisplayAccessControlHandlerTest.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace Drupal\Tests\Core\Entity\Access;
+
+use Drupal\Core\Entity\Entity\Access\EntityViewDisplayAccessControlHandler;
+use Drupal\Core\Entity\Entity\EntityViewDisplay;
+use Drupal\Core\Session\AccountInterface;
+
+/**
+ * @coversDefaultClass \Drupal\Core\Entity\Entity\Access\EntityViewDisplayAccessControlHandler
+ * @group Entity
+ */
+class EntityViewDisplayAccessControlHandlerTest extends EntityFormDisplayAccessControlHandlerTest {
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ parent::setUp();
+
+ $this->member = $this->getMock(AccountInterface::class);
+ $this->member
+ ->expects($this->any())
+ ->method('hasPermission')
+ ->will($this->returnValueMap([
+ ['administer foobar display', TRUE],
+ ]));
+ $this->member
+ ->expects($this->any())
+ ->method('id')
+ ->will($this->returnValue(2));
+
+ $this->entity = new EntityViewDisplay([
+ 'targetEntityType' => 'foobar',
+ 'bundle' => 'bazqux',
+ 'mode' => 'default',
+ 'id' => 'foobar.bazqux.default',
+ 'uuid' => '6f2f259a-f3c7-42ea-bdd5-111ad1f85ed1',
+ ], 'entity_display');
+ $this->accessControlHandler = new EntityViewDisplayAccessControlHandler($this->entity->getEntityType());
+ $this->accessControlHandler->setModuleHandler($this->moduleHandler);
+ }
+
+}