Upgraded drupal core with security updates
[yaffs-website] / web / core / modules / user / tests / src / Unit / UserAccessControlHandlerTest.php
1 <?php
2
3 namespace Drupal\Tests\user\Unit;
4
5 use Drupal\Core\Access\AccessResult;
6 use Drupal\Core\Cache\Context\CacheContextsManager;
7 use Drupal\Core\DependencyInjection\Container;
8 use Drupal\Tests\UnitTestCase;
9 use Drupal\user\UserAccessControlHandler;
10
11 /**
12  * Tests the user access controller.
13  *
14  * @group Drupal
15  * @group User
16  *
17  * @coversDefaultClass \Drupal\user\UserAccessControlHandler
18  */
19 class UserAccessControlHandlerTest extends UnitTestCase {
20
21   /**
22    * The user access controller to test.
23    *
24    * @var \Drupal\user\UserAccessControlHandler
25    */
26   protected $accessControlHandler;
27
28   /**
29    * The mock user account with view access.
30    *
31    * @var \Drupal\Core\Session\AccountInterface
32    */
33   protected $viewer;
34
35   /**
36    * The mock user account that is able to change their own account name.
37    *
38    * @var \Drupal\Core\Session\AccountInterface
39    */
40   protected $owner;
41
42   /**
43    * The mock administrative test user.
44    *
45    * @var \Drupal\Core\Session\AccountInterface
46    */
47   protected $admin;
48
49   /**
50    * The mocked test field items.
51    *
52    * @var \Drupal\Core\Field\FieldItemList
53    */
54   protected $items;
55
56   /**
57    * {@inheritdoc}
58    */
59   protected function setUp() {
60     parent::setUp();
61
62     $cache_contexts_manager = $this->prophesize(CacheContextsManager::class);
63     $cache_contexts_manager->assertValidTokens()->willReturn(TRUE);
64     $cache_contexts_manager->reveal();
65     $container = new Container();
66     $container->set('cache_contexts_manager', $cache_contexts_manager);
67     \Drupal::setContainer($container);
68
69     $this->viewer = $this->getMock('\Drupal\Core\Session\AccountInterface');
70     $this->viewer
71       ->expects($this->any())
72       ->method('hasPermission')
73       ->will($this->returnValue(FALSE));
74     $this->viewer
75       ->expects($this->any())
76       ->method('id')
77       ->will($this->returnValue(1));
78
79     $this->owner = $this->getMock('\Drupal\Core\Session\AccountInterface');
80     $this->owner
81       ->expects($this->any())
82       ->method('hasPermission')
83       ->will($this->returnValueMap([
84         ['administer users', FALSE],
85         ['change own username', TRUE],
86       ]));
87
88     $this->owner
89       ->expects($this->any())
90       ->method('id')
91       ->will($this->returnValue(2));
92
93     $this->admin = $this->getMock('\Drupal\Core\Session\AccountInterface');
94     $this->admin
95       ->expects($this->any())
96       ->method('hasPermission')
97       ->will($this->returnValue(TRUE));
98
99     $entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
100
101     $this->accessControlHandler = new UserAccessControlHandler($entity_type);
102     $module_handler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
103     $module_handler->expects($this->any())
104       ->method('getImplementations')
105       ->will($this->returnValue([]));
106     $this->accessControlHandler->setModuleHandler($module_handler);
107
108     $this->items = $this->getMockBuilder('Drupal\Core\Field\FieldItemList')
109       ->disableOriginalConstructor()
110       ->getMock();
111     $this->items
112       ->expects($this->any())
113       ->method('defaultAccess')
114       ->will($this->returnValue(AccessResult::allowed()));
115   }
116
117   /**
118    * Asserts correct field access grants for a field.
119    */
120   public function assertFieldAccess($field, $viewer, $target, $view, $edit) {
121     $field_definition = $this->getMock('Drupal\Core\Field\FieldDefinitionInterface');
122     $field_definition->expects($this->any())
123       ->method('getName')
124       ->will($this->returnValue($field));
125
126     $this->items
127       ->expects($this->any())
128       ->method('getEntity')
129       ->will($this->returnValue($this->{$target}));
130
131     foreach (['view' => $view, 'edit' => $edit] as $operation => $result) {
132       $result_text = !isset($result) ? 'null' : ($result ? 'true' : 'false');
133       $message = "User '$field' field access returns '$result_text' with operation '$operation' for '$viewer' accessing '$target'";
134       $this->assertSame($result, $this->accessControlHandler->fieldAccess($operation, $field_definition, $this->{$viewer}, $this->items), $message);
135     }
136   }
137
138   /**
139    * Ensures user name access is working properly.
140    *
141    * @dataProvider userNameProvider
142    */
143   public function testUserNameAccess($viewer, $target, $view, $edit) {
144     $this->assertFieldAccess('name', $viewer, $target, $view, $edit);
145   }
146
147   /**
148    * Provides test data for testUserNameAccess().
149    */
150   public function userNameProvider() {
151     $name_access = [
152       // The viewer user is allowed to see user names on all accounts.
153       [
154         'viewer' => 'viewer',
155         'target' => 'viewer',
156         'view' => TRUE,
157         'edit' => FALSE,
158       ],
159       [
160         'viewer' => 'owner',
161         'target' => 'viewer',
162         'view' => TRUE,
163         'edit' => FALSE,
164       ],
165       [
166         'viewer' => 'viewer',
167         'target' => 'owner',
168         'view' => TRUE,
169         'edit' => FALSE,
170       ],
171       // The owner user is allowed to change its own user name.
172       [
173         'viewer' => 'owner',
174         'target' => 'owner',
175         'view' => TRUE,
176         'edit' => TRUE,
177       ],
178       // The users-administrator user has full access.
179       [
180         'viewer' => 'admin',
181         'target' => 'owner',
182         'view' => TRUE,
183         'edit' => TRUE,
184       ],
185     ];
186     return $name_access;
187   }
188
189   /**
190    * Tests that private user settings cannot be viewed by other users.
191    *
192    * @dataProvider hiddenUserSettingsProvider
193    */
194   public function testHiddenUserSettings($field, $viewer, $target, $view, $edit) {
195     $this->assertFieldAccess($field, $viewer, $target, $view, $edit);
196   }
197
198   /**
199    * Provides test data for testHiddenUserSettings().
200    */
201   public function hiddenUserSettingsProvider() {
202     $access_info = [];
203
204     $fields = [
205       'preferred_langcode',
206       'preferred_admin_langcode',
207       'timezone',
208       'mail',
209     ];
210
211     foreach ($fields as $field) {
212       $access_info[] = [
213         'field' => $field,
214         'viewer' => 'viewer',
215         'target' => 'viewer',
216         'view' => TRUE,
217         'edit' => TRUE,
218       ];
219       $access_info[] = [
220         'field' => $field,
221         'viewer' => 'viewer',
222         'target' => 'owner',
223         'view' => FALSE,
224         // Anyone with edit access to the user can also edit these fields. In
225         // reality edit access will already be checked on entity level and the
226         // user without view access will typically not be able to edit.
227         'edit' => TRUE,
228       ];
229       $access_info[] = [
230         'field' => $field,
231         'viewer' => 'owner',
232         'target' => 'owner',
233         'view' => TRUE,
234         'edit' => TRUE,
235       ];
236       $access_info[] = [
237         'field' => $field,
238         'viewer' => 'admin',
239         'target' => 'owner',
240         'view' => TRUE,
241         'edit' => TRUE,
242       ];
243     }
244
245     return $access_info;
246   }
247
248   /**
249    * Tests that private user settings cannot be viewed by other users.
250    *
251    * @dataProvider adminFieldAccessProvider
252    */
253   public function testAdminFieldAccess($field, $viewer, $target, $view, $edit) {
254     $this->assertFieldAccess($field, $viewer, $target, $view, $edit);
255   }
256
257   /**
258    * Provides test data for testAdminFieldAccess().
259    */
260   public function adminFieldAccessProvider() {
261     $access_info = [];
262
263     $fields = [
264       'roles',
265       'status',
266       'access',
267       'login',
268       'init',
269     ];
270
271     foreach ($fields as $field) {
272       $access_info[] = [
273         'field' => $field,
274         'viewer' => 'viewer',
275         'target' => 'viewer',
276         'view' => FALSE,
277         'edit' => FALSE,
278       ];
279       $access_info[] = [
280         'field' => $field,
281         'viewer' => 'viewer',
282         'target' => 'owner',
283         'view' => FALSE,
284         'edit' => FALSE,
285       ];
286       $access_info[] = [
287         'field' => $field,
288         'viewer' => 'admin',
289         'target' => 'owner',
290         'view' => TRUE,
291         'edit' => TRUE,
292       ];
293     }
294
295     return $access_info;
296   }
297
298   /**
299    * Tests that passwords cannot be viewed, just edited.
300    *
301    * @dataProvider passwordAccessProvider
302    */
303   public function testPasswordAccess($viewer, $target, $view, $edit) {
304     $this->assertFieldAccess('pass', $viewer, $target, $view, $edit);
305   }
306
307   /**
308    * Provides test data for passwordAccessProvider().
309    */
310   public function passwordAccessProvider() {
311     $pass_access = [
312       [
313         'viewer' => 'viewer',
314         'target' => 'viewer',
315         'view' => FALSE,
316         'edit' => TRUE,
317       ],
318       [
319         'viewer' => 'viewer',
320         'target' => 'owner',
321         'view' => FALSE,
322         // Anyone with edit access to the user can also edit these fields. In
323         // reality edit access will already be checked on entity level and the
324         // user without view access will typically not be able to edit.
325         'edit' => TRUE,
326       ],
327       [
328         'viewer' => 'owner',
329         'target' => 'viewer',
330         'view' => FALSE,
331         'edit' => TRUE,
332       ],
333       [
334         'viewer' => 'admin',
335         'target' => 'owner',
336         'view' => FALSE,
337         'edit' => TRUE,
338       ],
339     ];
340     return $pass_access;
341   }
342
343   /**
344    * Tests the user created field access.
345    *
346    * @dataProvider createdAccessProvider
347    */
348   public function testCreatedAccess($viewer, $target, $view, $edit) {
349     $this->assertFieldAccess('created', $viewer, $target, $view, $edit);
350   }
351
352   /**
353    * Provides test data for testCreatedAccess().
354    */
355   public function createdAccessProvider() {
356     $created_access = [
357       [
358         'viewer' => 'viewer',
359         'target' => 'viewer',
360         'view' => TRUE,
361         'edit' => FALSE,
362       ],
363       [
364         'viewer' => 'owner',
365         'target' => 'viewer',
366         'view' => TRUE,
367         'edit' => FALSE,
368       ],
369       [
370         'viewer' => 'admin',
371         'target' => 'owner',
372         'view' => TRUE,
373         'edit' => TRUE,
374       ],
375     ];
376     return $created_access;
377   }
378
379   /**
380    * Tests access to a non-existing base field.
381    *
382    * @dataProvider NonExistingFieldAccessProvider
383    */
384   public function testNonExistingFieldAccess($viewer, $target, $view, $edit) {
385     // By default everyone has access to all fields that do not have explicit
386     // access control.
387     // @see EntityAccessControlHandler::checkFieldAccess()
388     $this->assertFieldAccess('some_non_existing_field', $viewer, $target, $view, $edit);
389   }
390
391   /**
392    * Provides test data for testNonExistingFieldAccess().
393    */
394   public function NonExistingFieldAccessProvider() {
395     $created_access = [
396       [
397         'viewer' => 'viewer',
398         'target' => 'viewer',
399         'view' => TRUE,
400         'edit' => TRUE,
401       ],
402       [
403         'viewer' => 'owner',
404         'target' => 'viewer',
405         'view' => TRUE,
406         'edit' => TRUE,
407       ],
408       [
409         'viewer' => 'admin',
410         'target' => 'owner',
411         'view' => TRUE,
412         'edit' => TRUE,
413       ],
414     ];
415     return $created_access;
416   }
417
418 }