From 59e21652361ba1086771d0f66660717e3b1b4a9b Mon Sep 17 00:00:00 2001
From: xjm <xjm@65776.no-reply.drupal.org>
Date: Sat, 24 Dec 2022 20:10:37 -0600
Subject: [PATCH] Issue #3171047 by rpayanm, catch, jonathanshaw, Berdir, xjm,
 larowlan, hchonov, mxr576: Entity query in UniqueFieldValueValidator must not
 use access checking

---
 .../Constraint/UniqueFieldValueValidator.php  |  6 ++--
 .../unique_field_constraint_test.module       | 14 ++++++++
 .../Validation/UniqueFieldConstraintTest.php  | 35 +++++++++++++++++++
 3 files changed, 51 insertions(+), 4 deletions(-)

diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php
index 1aad291d9a58..e965310861a3 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php
@@ -23,10 +23,8 @@ public function validate($items, Constraint $constraint) {
     $entity_type_id = $entity->getEntityTypeId();
     $id_key = $entity->getEntityType()->getKey('id');
 
-    $query = \Drupal::entityQuery($entity_type_id);
-
-    // @todo Don't check access. http://www.drupal.org/node/3171047
-    $query->accessCheck(TRUE);
+    $query = \Drupal::entityQuery($entity_type_id)
+      ->accessCheck(FALSE);
 
     $entity_id = $entity->id();
     // Using isset() instead of !empty() as 0 and '0' are valid ID values for
diff --git a/core/modules/system/tests/modules/unique_field_constraint_test/unique_field_constraint_test.module b/core/modules/system/tests/modules/unique_field_constraint_test/unique_field_constraint_test.module
index 0488d3d606e6..54547421b5cc 100644
--- a/core/modules/system/tests/modules/unique_field_constraint_test/unique_field_constraint_test.module
+++ b/core/modules/system/tests/modules/unique_field_constraint_test/unique_field_constraint_test.module
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Database\Query\AlterableInterface;
 
 /**
  * Implements hook_entity_base_field_info_alter().
@@ -15,4 +16,17 @@ function unique_field_constraint_test_entity_base_field_info_alter(&$fields, Ent
     /** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */
     $fields['name']->addConstraint('UniqueField');
   }
+  if ($entity_type->id() === 'entity_test') {
+    /** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */
+    $fields['name']->addConstraint('UniqueField');
+  }
+}
+
+/**
+ * Implements hook_query_entity_test_access_alter().
+ */
+function unique_field_constraint_test_query_entity_test_access_alter(AlterableInterface $query) {
+  // Set an impossible condition to filter out all entities.
+  /** @var \Drupal\Core\Database\Query\Select|\Drupal\Core\Database\Query\AlterableInterface $query */
+  $query->condition('entity_test.id', 0);
 }
diff --git a/core/tests/Drupal/KernelTests/Core/Validation/UniqueFieldConstraintTest.php b/core/tests/Drupal/KernelTests/Core/Validation/UniqueFieldConstraintTest.php
index 11ba975481de..1e8cb229427b 100644
--- a/core/tests/Drupal/KernelTests/Core/Validation/UniqueFieldConstraintTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Validation/UniqueFieldConstraintTest.php
@@ -3,6 +3,7 @@
 namespace Drupal\KernelTests\Core\Validation;
 
 use Drupal\Component\Render\FormattableMarkup;
+use Drupal\entity_test\Entity\EntityTest;
 use Drupal\entity_test\Entity\EntityTestStringId;
 use Drupal\KernelTests\KernelTestBase;
 
@@ -112,4 +113,38 @@ public function providerTestEntityWithStringIdWithViolation() {
     ];
   }
 
+  /**
+   * Tests validating inaccessible entities.
+   *
+   * The unique_field_constraint_test_entity_test_access() function
+   * forbids 'view' access to entity_test entities.
+   *
+   * @covers ::validate
+   */ public function testViolationDespiteNoAccess() {
+    $this->installEntitySchema('entity_test');
+
+    // Create and save an entity with a given field value in the field that has
+    // the unique constraint.
+    EntityTest::create([
+      'name' => 'A totally unique entity name',
+    ])->save();
+
+    // Prepare a second entity with the same value in the unique field.
+    $entity = EntityTest::create([
+      'name' => 'A totally unique entity name',
+    ]);
+    /** @var \Symfony\Component\Validator\ConstraintViolationList $violations */
+    $violations = $entity->get('name')->validate();
+
+    $message = new FormattableMarkup('A @entity_type with @field_name %value already exists.', [
+      '%value' => 'A totally unique entity name',,
+      '@entity_type' => $entity->getEntityType()->getSingularLabel(),
+      '@field_name' => 'Name',
+    ]);
+
+    // Check that the validation has created the appropriate violation.
+    $this->assertCount(1, $violations);
+    $this->assertEquals($message, $violations[0]->getMessage());
+  }
+
 }
-- 
GitLab