diff --git a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php index 7b3e49e..14e0b1f 100644 --- a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php +++ b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php @@ -7,10 +7,15 @@ namespace Drupal\rest\Plugin\rest\resource; +use Psr\Log\LoggerInterface; +use Drupal\Core\Entity\ContentEntityInterface; +use Drupal\Core\Entity\EntityDisplayBase; +use Drupal\Core\Session\AccountProxyInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityStorageException; use Drupal\rest\Plugin\ResourceBase; use Drupal\rest\ResourceResponse; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\HttpException; @@ -34,6 +39,47 @@ class EntityResource extends ResourceBase { /** + * A curent user instance. + * + * @var \Drupal\Core\Session\AccountProxyInterface + */ + protected $currentUser; + + /** + * Constructs a Drupal\rest\Plugin\ResourceBase object. + * + * @param array $configuration + * A configuration array containing information about the plugin instance. + * @param string $plugin_id + * The plugin_id for the plugin instance. + * @param mixed $plugin_definition + * The plugin implementation definition. + * @param array $serializer_formats + * The available serialization formats. + * @param \Psr\Log\LoggerInterface $logger + * A logger instance. + * @param \Drupal\Core\Session\AccountProxyInterface $current_user + * A curent user instance. + */ + public function __construct(array $configuration, $plugin_id, $plugin_definition, array $serializer_formats, LoggerInterface $logger, AccountProxyInterface $current_user) { + parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger); + $this->currentUser = $current_user; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->getParameter('serializer.formats'), + $container->get('logger.factory')->get('rest'), + $container->get('current_user') + ); + } + /** * Responds to entity GET requests. * * @param \Drupal\Core\Entity\EntityInterface $entity @@ -45,12 +91,26 @@ class EntityResource extends ResourceBase { * @throws \Symfony\Component\HttpKernel\Exception\HttpException */ public function get(EntityInterface $entity) { - if (!$entity->access('view')) { - throw new AccessDeniedHttpException(); + + // Validate access only for entities extending Content Entity Interface. + if ($entity instanceof ContentEntityInterface) { + if (!$entity->access('view')) { + throw new AccessDeniedHttpException(); + } + + foreach ($entity as $field_name => $field) { + if (!$field->access('view')) { + unset($entity->{$field_name}); + } + } } - foreach ($entity as $field_name => $field) { - if (!$field->access('view')) { - unset($entity->{$field_name}); + // Validate if current has permit to get Entity Display entities. + else if ($entity instanceof EntityDisplayBase) { + // @see \Drupal\rest\Plugin\ResourceBase::permissions() + $plugin_definition = $this->getPluginDefinition(); + $permission = "restful get $plugin_definition->pluginId"; + if(!$this->currentUser->hasPermission($permission)) { + throw new AccessDeniedHttpException(); } } return new ResourceResponse($entity); diff --git a/core/modules/rest/src/Tests/ReadTest.php b/core/modules/rest/src/Tests/ReadTest.php index e1aae7f..1e3f72d 100644 --- a/core/modules/rest/src/Tests/ReadTest.php +++ b/core/modules/rest/src/Tests/ReadTest.php @@ -92,6 +92,36 @@ public function testRead() { $this->assertIdentical($expected_message, $response); } + public function testReadConfigEntity() { + $entity_types = array( + 'menu' => 'entity/menu/main', + 'taxonomy_vocabulary' => 'entity/taxonomy_vocabulary/tags', + ); + foreach ($entity_types as $entity_type => $path) { + $this->enableService('entity:' . $entity_type, 'GET'); + // Create a user account that has the required permissions to read + // resources via the REST API. + $permissions[] = 'restful get entity:' . $entity_type; + $account = $this->drupalCreateUser($permissions); + $this->drupalLogin($account); + + // Read it over the REST API. + $response = $this->httpRequest($path, 'GET', NULL, $this->defaultMimeType); + $this->assertResponse('200', 'HTTP response code is correct.'); + $this->assertHeader('content-type', $this->defaultMimeType); + $data = Json::decode($response); + // Only assert one example property here, other properties should be + // checked in serialization tests. + $this->assertNotEmpty($data['uuid'], 'Entity UUID found'); + + // Try to read an entity without proper permissions. + $this->drupalLogout(); + $response = $this->httpRequest($$path, 'GET', NULL, $this->defaultMimeType); + $this->assertResponse(403); + $this->assertIdentical('{}', $response); + } + } + /** * Tests the resource structure. */