comparison core/modules/user/tests/src/Unit/UserAccessControlHandlerTest.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4c8ae668cc8c
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 }