summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathaniel Catchpole2016-02-22 10:50:34 (GMT)
committerNathaniel Catchpole2016-02-22 10:50:34 (GMT)
commit59725230900f1fcb78f27e06479c8de19f62d4ec (patch)
treee9902e4faef0d5f26e234a8cfa809e9184e3339a
parentfd16d6eb22fe74b2cf20a4d5b7a323ca454018cd (diff)
Issue #2471154 by amateescu, googletorp, Denchev, mariancalinro, Xano, celdia: Anonymous user label can't be viewed and auth user labels are only accessible with 'access user profiles' permission
-rw-r--r--core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php6
-rw-r--r--core/lib/Drupal/Core/Entity/EntityAccessControlHandler.php17
-rw-r--r--core/lib/Drupal/Core/Entity/EntityAccessControlHandlerInterface.php2
-rw-r--r--core/modules/link/src/Tests/LinkFieldTest.php9
-rw-r--r--core/modules/node/src/Tests/NodeEditFormTest.php10
-rw-r--r--core/modules/system/src/Tests/Entity/EntityAccessControlHandlerTest.php67
-rw-r--r--core/modules/system/tests/modules/entity_test/src/EntityTestAccessControlHandler.php14
-rw-r--r--core/modules/user/src/UserAccessControlHandler.php14
8 files changed, 130 insertions, 9 deletions
diff --git a/core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php b/core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php
index d94e2b5..fc06979 100644
--- a/core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php
+++ b/core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php
@@ -290,7 +290,7 @@ class EntityAutocomplete extends Textfield {
/**
* Converts an array of entity objects into a string of entity labels.
*
- * This method is also responsible for checking the 'view' access on the
+ * This method is also responsible for checking the 'view label' access on the
* passed-in entities.
*
* @param \Drupal\Core\Entity\EntityInterface[] $entities
@@ -302,7 +302,9 @@ class EntityAutocomplete extends Textfield {
public static function getEntityLabels(array $entities) {
$entity_labels = array();
foreach ($entities as $entity) {
- $label = ($entity->access('view')) ? $entity->label() : t('- Restricted access -');
+ // Use the special view label, since some entities allow the label to be
+ // viewed, even if the entity is not allowed to be viewed.
+ $label = ($entity->access('view label')) ? $entity->label() : t('- Restricted access -');
// Take into account "autocreated" entities.
if (!$entity->isNew()) {
diff --git a/core/lib/Drupal/Core/Entity/EntityAccessControlHandler.php b/core/lib/Drupal/Core/Entity/EntityAccessControlHandler.php
index 27fda29..02b497d 100644
--- a/core/lib/Drupal/Core/Entity/EntityAccessControlHandler.php
+++ b/core/lib/Drupal/Core/Entity/EntityAccessControlHandler.php
@@ -40,6 +40,16 @@ class EntityAccessControlHandler extends EntityHandlerBase implements EntityAcce
protected $entityType;
/**
+ * Allows to grant access to just the labels.
+ *
+ * By default, the "view label" operation falls back to "view". Set this to
+ * TRUE to allow returning different access when just listing entity labels.
+ *
+ * @var bool
+ */
+ protected $viewLabelOperation = FALSE;
+
+ /**
* Constructs an access control handler instance.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
@@ -57,6 +67,10 @@ class EntityAccessControlHandler extends EntityHandlerBase implements EntityAcce
$account = $this->prepareUser($account);
$langcode = $entity->language()->getId();
+ if ($operation === 'view label' && $this->viewLabelOperation == FALSE) {
+ $operation = 'view';
+ }
+
if (($return = $this->getCache($entity->uuid(), $operation, $langcode, $account)) !== NULL) {
// Cache hit, no work necessary.
return $return_as_object ? $return : $return->isAllowed();
@@ -124,7 +138,8 @@ class EntityAccessControlHandler extends EntityHandlerBase implements EntityAcce
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity for which to check access.
* @param string $operation
- * The entity operation. Usually one of 'view', 'update' or 'delete'.
+ * The entity operation. Usually one of 'view', 'view label', 'update' or
+ * 'delete'.
* @param \Drupal\Core\Session\AccountInterface $account
* The user for which to check access.
*
diff --git a/core/lib/Drupal/Core/Entity/EntityAccessControlHandlerInterface.php b/core/lib/Drupal/Core/Entity/EntityAccessControlHandlerInterface.php
index c1e7333..1d3c1ed 100644
--- a/core/lib/Drupal/Core/Entity/EntityAccessControlHandlerInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityAccessControlHandlerInterface.php
@@ -27,7 +27,7 @@ interface EntityAccessControlHandlerInterface {
* The entity for which to check access.
* @param string $operation
* The operation access should be checked for.
- * Usually one of "view", "update" or "delete".
+ * Usually one of "view", "view label", "update" or "delete".
* @param \Drupal\Core\Session\AccountInterface $account
* (optional) The user session for which to check access, or NULL to check
* access for the current user. Defaults to NULL.
diff --git a/core/modules/link/src/Tests/LinkFieldTest.php b/core/modules/link/src/Tests/LinkFieldTest.php
index 7fa960c..2d00cfa 100644
--- a/core/modules/link/src/Tests/LinkFieldTest.php
+++ b/core/modules/link/src/Tests/LinkFieldTest.php
@@ -10,6 +10,7 @@ namespace Drupal\link\Tests;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Url;
+use Drupal\entity_test\Entity\EntityTest;
use Drupal\field\Entity\FieldConfig;
use Drupal\link\LinkItemInterface;
use Drupal\simpletest\WebTestBase;
@@ -99,6 +100,12 @@ class LinkFieldTest extends WebTestBase {
// Create a node to test the link widget.
$node = $this->drupalCreateNode();
+ // Create an entity with restricted view access.
+ $entity_test_no_label_access = EntityTest::create([
+ 'name' => 'forbid_access',
+ ]);
+ $entity_test_no_label_access->save();
+
// Define some valid URLs (keys are the entered values, values are the
// strings displayed to the user).
$valid_external_entries = array(
@@ -132,7 +139,7 @@ class LinkFieldTest extends WebTestBase {
// Entity URI displayed as ER autocomplete value when displayed in a form.
'entity:node/1' => $node->label() . ' (1)',
// URI for an entity that exists, but is not accessible by the user.
- 'entity:user/1' => '- Restricted access - (1)',
+ 'entity:entity_test/' . $entity_test_no_label_access->id() => '- Restricted access - (' . $entity_test_no_label_access->id() . ')',
// URI for an entity that doesn't exist, but with a valid ID.
'entity:user/999999' => 'entity:user/999999',
);
diff --git a/core/modules/node/src/Tests/NodeEditFormTest.php b/core/modules/node/src/Tests/NodeEditFormTest.php
index f2701a4..d6c40b6 100644
--- a/core/modules/node/src/Tests/NodeEditFormTest.php
+++ b/core/modules/node/src/Tests/NodeEditFormTest.php
@@ -8,6 +8,7 @@
namespace Drupal\node\Tests;
use Drupal\node\NodeInterface;
+use Drupal\user\Entity\User;
/**
* Create a node and test node edit functionality.
@@ -205,10 +206,17 @@ class NodeEditFormTest extends NodeTestBase {
// won't do.
$this->assertTrue($uid === 0 || $uid === '0', 'Node authored by anonymous user.');
+ // Go back to the edit form and check that the correct value is displayed
+ // in the author widget.
+ $this->drupalGet('node/' . $node->id() . '/edit');
+ $anonymous_user = User::getAnonymousUser();
+ $expected = $anonymous_user->label() . ' (' . $anonymous_user->id() . ')';
+ $this->assertFieldByName($form_element_name, $expected, 'Authored by field displays the correct value for the anonymous user.');
+
// Change the authored by field to another user's name (that is not
// logged in).
$edit[$form_element_name] = $this->webUser->getUsername();
- $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep published'));
+ $this->drupalPostForm(NULL, $edit, t('Save and keep published'));
$this->nodeStorage->resetCache(array($node->id()));
$node = $this->nodeStorage->load($node->id());
$this->assertIdentical($node->getOwnerId(), $this->webUser->id(), 'Node authored by normal user.');
diff --git a/core/modules/system/src/Tests/Entity/EntityAccessControlHandlerTest.php b/core/modules/system/src/Tests/Entity/EntityAccessControlHandlerTest.php
index 222cd7a..f2f05b4 100644
--- a/core/modules/system/src/Tests/Entity/EntityAccessControlHandlerTest.php
+++ b/core/modules/system/src/Tests/Entity/EntityAccessControlHandlerTest.php
@@ -11,9 +11,12 @@ use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Access\AccessibleInterface;
use Drupal\Core\Entity\EntityAccessControlHandler;
+use Drupal\Core\Session\AnonymousUserSession;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\entity_test\Entity\EntityTestDefaultAccess;
+use Drupal\entity_test\Entity\EntityTestLabel;
use Drupal\language\Entity\ConfigurableLanguage;
+use Drupal\user\Entity\User;
/**
* Tests the entity access control handler.
@@ -37,12 +40,69 @@ class EntityAccessControlHandlerTest extends EntityLanguageTestBase {
}
/**
+ * Ensures user labels are accessible for everyone.
+ */
+ public function testUserLabelAccess() {
+ // Set up a non-admin user.
+ \Drupal::currentUser()->setAccount($this->createUser(['uid' => 2]));
+
+ $anonymous_user = User::getAnonymousUser();
+ $user = $this->createUser();
+
+ // The current user is allowed to view the anonymous user label.
+ $this->assertEntityAccess(array(
+ 'create' => FALSE,
+ 'update' => FALSE,
+ 'delete' => FALSE,
+ 'view' => FALSE,
+ 'view label' => TRUE,
+ ), $anonymous_user);
+
+ // The current user is allowed to view user labels.
+ $this->assertEntityAccess(array(
+ 'create' => FALSE,
+ 'update' => FALSE,
+ 'delete' => FALSE,
+ 'view' => FALSE,
+ 'view label' => TRUE,
+ ), $user);
+
+ // Switch to a anonymous user account.
+ $account_switcher = \Drupal::service('account_switcher');
+ $account_switcher->switchTo(new AnonymousUserSession());
+
+ // The anonymous user is allowed to view the anonymous user label.
+ $this->assertEntityAccess(array(
+ 'create' => FALSE,
+ 'update' => FALSE,
+ 'delete' => FALSE,
+ 'view' => FALSE,
+ 'view label' => TRUE,
+ ), $anonymous_user);
+
+ // The anonymous user is allowed to view user labels.
+ $this->assertEntityAccess(array(
+ 'create' => FALSE,
+ 'update' => FALSE,
+ 'delete' => FALSE,
+ 'view' => FALSE,
+ 'view label' => TRUE,
+ ), $user);
+
+ // Restore user account.
+ $account_switcher->switchBack();
+ }
+
+ /**
* Ensures entity access is properly working.
*/
function testEntityAccess() {
// Set up a non-admin user that is allowed to view test entities.
\Drupal::currentUser()->setAccount($this->createUser(array('uid' => 2), array('view test entity')));
- $entity = EntityTest::create(array(
+
+ // Use the 'entity_test_label' entity type in order to test the 'view label'
+ // access operation.
+ $entity = EntityTestLabel::create(array(
'name' => 'test',
));
@@ -52,15 +112,18 @@ class EntityAccessControlHandlerTest extends EntityLanguageTestBase {
'update' => FALSE,
'delete' => FALSE,
'view' => TRUE,
+ 'view label' => TRUE,
), $entity);
- // The custom user is not allowed to perform any operation on test entities.
+ // The custom user is not allowed to perform any operation on test entities,
+ // except for viewing their label.
$custom_user = $this->createUser();
$this->assertEntityAccess(array(
'create' => FALSE,
'update' => FALSE,
'delete' => FALSE,
'view' => FALSE,
+ 'view label' => TRUE,
), $entity, $custom_user);
}
diff --git a/core/modules/system/tests/modules/entity_test/src/EntityTestAccessControlHandler.php b/core/modules/system/tests/modules/entity_test/src/EntityTestAccessControlHandler.php
index bdc3785..7988060 100644
--- a/core/modules/system/tests/modules/entity_test/src/EntityTestAccessControlHandler.php
+++ b/core/modules/system/tests/modules/entity_test/src/EntityTestAccessControlHandler.php
@@ -11,6 +11,7 @@ use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityAccessControlHandler;
use Drupal\Core\Session\AccountInterface;
+use Drupal\entity_test\Entity\EntityTestLabel;
/**
* Defines the access control handler for the test entity type.
@@ -26,6 +27,13 @@ use Drupal\Core\Session\AccountInterface;
class EntityTestAccessControlHandler extends EntityAccessControlHandler {
/**
+ * Allows to grant access to just the labels.
+ *
+ * @var bool
+ */
+ protected $viewLabelOperation = TRUE;
+
+ /**
* {@inheritdoc}
*/
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
@@ -37,7 +45,11 @@ class EntityTestAccessControlHandler extends EntityAccessControlHandler {
return AccessResult::forbidden();
}
- if ($operation === 'view') {
+ if ($operation === 'view label' && $entity instanceof EntityTestLabel) {
+ // Viewing the label of the 'entity_test_label' entity type is allowed.
+ return AccessResult::allowed();
+ }
+ elseif (in_array($operation, array('view', 'view label'))) {
if (!$entity->isDefaultTranslation()) {
return AccessResult::allowedIfHasPermission($account, 'view test entity translations');
}
diff --git a/core/modules/user/src/UserAccessControlHandler.php b/core/modules/user/src/UserAccessControlHandler.php
index ae52b2b..eb89585 100644
--- a/core/modules/user/src/UserAccessControlHandler.php
+++ b/core/modules/user/src/UserAccessControlHandler.php
@@ -22,11 +22,25 @@ use Drupal\Core\Session\AccountInterface;
class UserAccessControlHandler extends EntityAccessControlHandler {
/**
+ * Allow access to user label.
+ *
+ * @var bool
+ */
+ protected $viewLabelOperation = TRUE;
+
+ /**
* {@inheritdoc}
*/
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
/** @var \Drupal\user\UserInterface $entity*/
+ // We don't treat the user label as privileged information, so this check
+ // has to be the first one in order to allow labels for all users to be
+ // viewed, including the special anonymous user.
+ if ($operation === 'view label') {
+ return AccessResult::allowed();
+ }
+
// The anonymous user's profile can neither be viewed, updated nor deleted.
if ($entity->isAnonymous()) {
return AccessResult::forbidden();