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
parent
fd16d6eb22
commit
5972523090
|
@ -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()) {
|
||||
|
|
|
@ -39,6 +39,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.
|
||||
*
|
||||
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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',
|
||||
);
|
||||
|
|
|
@ -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.');
|
||||
|
|
|
@ -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.
|
||||
|
@ -36,13 +39,70 @@ 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
@ -25,6 +26,13 @@ use Drupal\Core\Session\AccountInterface;
|
|||
*/
|
||||
class EntityTestAccessControlHandler extends EntityAccessControlHandler {
|
||||
|
||||
/**
|
||||
* Allows to grant access to just the labels.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $viewLabelOperation = TRUE;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -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');
|
||||
}
|
||||
|
|
|
@ -21,12 +21,26 @@ 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();
|
||||
|
|
Loading…
Reference in New Issue