Upgraded drupal core with security updates
[yaffs-website] / web / core / tests / Drupal / KernelTests / Core / Entity / EntityAccessControlHandlerTest.php
1 <?php
2
3 namespace Drupal\KernelTests\Core\Entity;
4
5 use Drupal\Core\Language\LanguageInterface;
6 use Drupal\Core\Session\AccountInterface;
7 use Drupal\Core\Access\AccessibleInterface;
8 use Drupal\Core\Entity\EntityAccessControlHandler;
9 use Drupal\Core\Session\AnonymousUserSession;
10 use Drupal\entity_test\Entity\EntityTest;
11 use Drupal\entity_test\Entity\EntityTestDefaultAccess;
12 use Drupal\entity_test\Entity\EntityTestNoUuid;
13 use Drupal\entity_test\Entity\EntityTestLabel;
14 use Drupal\entity_test\Entity\EntityTestRev;
15 use Drupal\language\Entity\ConfigurableLanguage;
16 use Drupal\user\Entity\User;
17
18 /**
19  * Tests the entity access control handler.
20  *
21  * @group Entity
22  */
23 class EntityAccessControlHandlerTest extends EntityLanguageTestBase {
24
25   /**
26    * {@inheritdoc}
27    */
28   public function setUp() {
29     parent::setUp();
30
31     $this->installEntitySchema('entity_test_no_uuid');
32     $this->installEntitySchema('entity_test_rev');
33   }
34
35   /**
36    * Asserts entity access correctly grants or denies access.
37    */
38   public function assertEntityAccess($ops, AccessibleInterface $object, AccountInterface $account = NULL) {
39     foreach ($ops as $op => $result) {
40       $message = format_string("Entity access returns @result with operation '@op'.", [
41         '@result' => !isset($result) ? 'null' : ($result ? 'true' : 'false'),
42         '@op' => $op,
43       ]);
44
45       $this->assertEqual($result, $object->access($op, $account), $message);
46     }
47   }
48
49   /**
50    * Ensures user labels are accessible for everyone.
51    */
52   public function testUserLabelAccess() {
53     // Set up a non-admin user.
54     \Drupal::currentUser()->setAccount($this->createUser(['uid' => 2]));
55
56     $anonymous_user = User::getAnonymousUser();
57     $user = $this->createUser();
58
59     // The current user is allowed to view the anonymous user label.
60     $this->assertEntityAccess([
61       'create' => FALSE,
62       'update' => FALSE,
63       'delete' => FALSE,
64       'view' => FALSE,
65       'view label' => TRUE,
66     ], $anonymous_user);
67
68     // The current user is allowed to view user labels.
69     $this->assertEntityAccess([
70       'create' => FALSE,
71       'update' => FALSE,
72       'delete' => FALSE,
73       'view' => FALSE,
74       'view label' => TRUE,
75     ], $user);
76
77     // Switch to a anonymous user account.
78     $account_switcher = \Drupal::service('account_switcher');
79     $account_switcher->switchTo(new AnonymousUserSession());
80
81     // The anonymous user is allowed to view the anonymous user label.
82     $this->assertEntityAccess([
83       'create' => FALSE,
84       'update' => FALSE,
85       'delete' => FALSE,
86       'view' => FALSE,
87       'view label' => TRUE,
88     ], $anonymous_user);
89
90     // The anonymous user is allowed to view user labels.
91     $this->assertEntityAccess([
92       'create' => FALSE,
93       'update' => FALSE,
94       'delete' => FALSE,
95       'view' => FALSE,
96       'view label' => TRUE,
97     ], $user);
98
99     // Restore user account.
100     $account_switcher->switchBack();
101   }
102
103   /**
104    * Ensures entity access is properly working.
105    */
106   public function testEntityAccess() {
107     // Set up a non-admin user that is allowed to view test entities.
108     \Drupal::currentUser()->setAccount($this->createUser(['uid' => 2], ['view test entity']));
109
110     // Use the 'entity_test_label' entity type in order to test the 'view label'
111     // access operation.
112     $entity = EntityTestLabel::create([
113       'name' => 'test',
114     ]);
115
116     // The current user is allowed to view entities.
117     $this->assertEntityAccess([
118       'create' => FALSE,
119       'update' => FALSE,
120       'delete' => FALSE,
121       'view' => TRUE,
122       'view label' => TRUE,
123     ], $entity);
124
125     // The custom user is not allowed to perform any operation on test entities,
126     // except for viewing their label.
127     $custom_user = $this->createUser();
128     $this->assertEntityAccess([
129       'create' => FALSE,
130       'update' => FALSE,
131       'delete' => FALSE,
132       'view' => FALSE,
133       'view label' => TRUE,
134     ], $entity, $custom_user);
135   }
136
137   /**
138    * Ensures default entity access is checked when necessary.
139    *
140    * This ensures that the default checkAccess() implementation of the
141    * entity access control handler is considered if hook_entity_access() has not
142    * explicitly forbidden access. Therefore the default checkAccess()
143    * implementation can forbid access, even after access was already explicitly
144    * allowed by hook_entity_access().
145    *
146    * @see \Drupal\entity_test\EntityTestAccessControlHandler::checkAccess()
147    * @see entity_test_entity_access()
148    */
149   public function testDefaultEntityAccess() {
150     // Set up a non-admin user that is allowed to view test entities.
151     \Drupal::currentUser()->setAccount($this->createUser(['uid' => 2], ['view test entity']));
152     $entity = EntityTest::create([
153         'name' => 'forbid_access',
154       ]);
155
156     // The user is denied access to the entity.
157     $this->assertEntityAccess([
158         'create' => FALSE,
159         'update' => FALSE,
160         'delete' => FALSE,
161         'view' => FALSE,
162       ], $entity);
163   }
164
165   /**
166    * Ensures that the default handler is used as a fallback.
167    */
168   public function testEntityAccessDefaultController() {
169     // The implementation requires that the global user id can be loaded.
170     \Drupal::currentUser()->setAccount($this->createUser(['uid' => 2]));
171
172     // Check that the default access control handler is used for entities that don't
173     // have a specific access control handler defined.
174     $handler = $this->container->get('entity.manager')->getAccessControlHandler('entity_test_default_access');
175     $this->assertTrue($handler instanceof EntityAccessControlHandler, 'The default entity handler is used for the entity_test_default_access entity type.');
176
177     $entity = EntityTestDefaultAccess::create();
178     $this->assertEntityAccess([
179       'create' => FALSE,
180       'update' => FALSE,
181       'delete' => FALSE,
182       'view' => FALSE,
183     ], $entity);
184   }
185
186   /**
187    * Ensures entity access for entity translations is properly working.
188    */
189   public function testEntityTranslationAccess() {
190
191     // Set up a non-admin user that is allowed to view test entity translations.
192     \Drupal::currentUser()->setAccount($this->createUser(['uid' => 2], ['view test entity translations']));
193
194     // Create two test languages.
195     foreach (['foo', 'bar'] as $langcode) {
196       ConfigurableLanguage::create([
197         'id' => $langcode,
198         'label' => $this->randomString(),
199       ])->save();
200     }
201
202     $entity = EntityTest::create([
203       'name' => 'test',
204       'langcode' => 'foo',
205     ]);
206     $entity->save();
207
208     $translation = $entity->addTranslation('bar');
209     $this->assertEntityAccess([
210       'view' => TRUE,
211     ], $translation);
212   }
213
214   /**
215    * Ensures the static access cache works correctly in the absence of an UUID.
216    *
217    * @see entity_test_entity_access()
218    */
219   public function testEntityWithoutUuidAccessCache() {
220     $account = $this->createUser();
221
222     $entity1 = EntityTestNoUuid::create([
223       'name' => 'Accessible',
224     ]);
225     $entity1->save();
226
227     $entity2 = EntityTestNoUuid::create([
228       'name' => 'Inaccessible',
229     ]);
230     $entity2->save();
231
232     $this->assertTrue($entity1->access('delete', $account), 'Entity 1 can be deleted.');
233     $this->assertFalse($entity2->access('delete', $account), 'Entity 2 CANNOT be deleted.');
234
235     $entity1
236       ->setName('Inaccessible')
237       ->setNewRevision();
238     $entity1->save();
239
240     $this->assertFalse($entity1->access('delete', $account), 'Entity 1 revision 2 CANNOT be deleted.');
241   }
242
243   /**
244    * Ensures the static access cache works correctly with a UUID and revisions.
245    *
246    * @see entity_test_entity_access()
247    */
248   public function testEntityWithUuidAccessCache() {
249     $account = $this->createUser();
250
251     $entity1 = EntityTestRev::create([
252       'name' => 'Accessible',
253     ]);
254     $entity1->save();
255
256     $entity2 = EntityTestRev::create([
257       'name' => 'Inaccessible',
258     ]);
259     $entity2->save();
260
261     $this->assertTrue($entity1->access('delete', $account), 'Entity 1 can be deleted.');
262     $this->assertFalse($entity2->access('delete', $account), 'Entity 2 CANNOT be deleted.');
263
264     $entity1
265       ->setName('Inaccessible')
266       ->setNewRevision();
267     $entity1->save();
268
269     $this->assertFalse($entity1->access('delete', $account), 'Entity 1 revision 2 CANNOT be deleted.');
270   }
271
272   /**
273    * Tests hook invocations.
274    */
275   public function testHooks() {
276     $state = $this->container->get('state');
277     $entity = EntityTest::create([
278       'name' => 'test',
279     ]);
280
281     // Test hook_entity_create_access() and hook_ENTITY_TYPE_create_access().
282     $entity->access('create');
283     $this->assertEqual($state->get('entity_test_entity_create_access'), TRUE);
284     $this->assertIdentical($state->get('entity_test_entity_create_access_context'), [
285       'entity_type_id' => 'entity_test',
286       'langcode' => LanguageInterface::LANGCODE_DEFAULT,
287     ]);
288     $this->assertEqual($state->get('entity_test_entity_test_create_access'), TRUE);
289
290     // Test hook_entity_access() and hook_ENTITY_TYPE_access().
291     $entity->access('view');
292     $this->assertEqual($state->get('entity_test_entity_access'), TRUE);
293     $this->assertEqual($state->get('entity_test_entity_test_access'), TRUE);
294   }
295
296 }