3 namespace Drupal\Tests\user\Unit;
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;
12 * Tests the user access controller.
17 * @coversDefaultClass \Drupal\user\UserAccessControlHandler
19 class UserAccessControlHandlerTest extends UnitTestCase {
22 * The user access controller to test.
24 * @var \Drupal\user\UserAccessControlHandler
26 protected $accessControlHandler;
29 * The mock user account with view access.
31 * @var \Drupal\Core\Session\AccountInterface
36 * The mock user account that is able to change their own account name.
38 * @var \Drupal\Core\Session\AccountInterface
43 * The mock administrative test user.
45 * @var \Drupal\Core\Session\AccountInterface
50 * The mocked test field items.
52 * @var \Drupal\Core\Field\FieldItemList
59 protected function setUp() {
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);
69 $this->viewer = $this->getMock('\Drupal\Core\Session\AccountInterface');
71 ->expects($this->any())
72 ->method('hasPermission')
73 ->will($this->returnValue(FALSE));
75 ->expects($this->any())
77 ->will($this->returnValue(1));
79 $this->owner = $this->getMock('\Drupal\Core\Session\AccountInterface');
81 ->expects($this->any())
82 ->method('hasPermission')
83 ->will($this->returnValueMap([
84 ['administer users', FALSE],
85 ['change own username', TRUE],
89 ->expects($this->any())
91 ->will($this->returnValue(2));
93 $this->admin = $this->getMock('\Drupal\Core\Session\AccountInterface');
95 ->expects($this->any())
96 ->method('hasPermission')
97 ->will($this->returnValue(TRUE));
99 $entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
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);
108 $this->items = $this->getMockBuilder('Drupal\Core\Field\FieldItemList')
109 ->disableOriginalConstructor()
112 ->expects($this->any())
113 ->method('defaultAccess')
114 ->will($this->returnValue(AccessResult::allowed()));
118 * Asserts correct field access grants for a field.
120 public function assertFieldAccess($field, $viewer, $target, $view, $edit) {
121 $field_definition = $this->getMock('Drupal\Core\Field\FieldDefinitionInterface');
122 $field_definition->expects($this->any())
124 ->will($this->returnValue($field));
127 ->expects($this->any())
128 ->method('getEntity')
129 ->will($this->returnValue($this->{$target}));
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);
139 * Ensures user name access is working properly.
141 * @dataProvider userNameProvider
143 public function testUserNameAccess($viewer, $target, $view, $edit) {
144 $this->assertFieldAccess('name', $viewer, $target, $view, $edit);
148 * Provides test data for testUserNameAccess().
150 public function userNameProvider() {
152 // The viewer user is allowed to see user names on all accounts.
154 'viewer' => 'viewer',
155 'target' => 'viewer',
161 'target' => 'viewer',
166 'viewer' => 'viewer',
171 // The owner user is allowed to change its own user name.
178 // The users-administrator user has full access.
190 * Tests that private user settings cannot be viewed by other users.
192 * @dataProvider hiddenUserSettingsProvider
194 public function testHiddenUserSettings($field, $viewer, $target, $view, $edit) {
195 $this->assertFieldAccess($field, $viewer, $target, $view, $edit);
199 * Provides test data for testHiddenUserSettings().
201 public function hiddenUserSettingsProvider() {
205 'preferred_langcode',
206 'preferred_admin_langcode',
211 foreach ($fields as $field) {
214 'viewer' => 'viewer',
215 'target' => 'viewer',
221 'viewer' => 'viewer',
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.
249 * Tests that private user settings cannot be viewed by other users.
251 * @dataProvider adminFieldAccessProvider
253 public function testAdminFieldAccess($field, $viewer, $target, $view, $edit) {
254 $this->assertFieldAccess($field, $viewer, $target, $view, $edit);
258 * Provides test data for testAdminFieldAccess().
260 public function adminFieldAccessProvider() {
271 foreach ($fields as $field) {
274 'viewer' => 'viewer',
275 'target' => 'viewer',
281 'viewer' => 'viewer',
299 * Tests that passwords cannot be viewed, just edited.
301 * @dataProvider passwordAccessProvider
303 public function testPasswordAccess($viewer, $target, $view, $edit) {
304 $this->assertFieldAccess('pass', $viewer, $target, $view, $edit);
308 * Provides test data for passwordAccessProvider().
310 public function passwordAccessProvider() {
313 'viewer' => 'viewer',
314 'target' => 'viewer',
319 'viewer' => 'viewer',
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.
329 'target' => 'viewer',
344 * Tests the user created field access.
346 * @dataProvider createdAccessProvider
348 public function testCreatedAccess($viewer, $target, $view, $edit) {
349 $this->assertFieldAccess('created', $viewer, $target, $view, $edit);
353 * Provides test data for testCreatedAccess().
355 public function createdAccessProvider() {
358 'viewer' => 'viewer',
359 'target' => 'viewer',
365 'target' => 'viewer',
376 return $created_access;
380 * Tests access to a non-existing base field.
382 * @dataProvider NonExistingFieldAccessProvider
384 public function testNonExistingFieldAccess($viewer, $target, $view, $edit) {
385 // By default everyone has access to all fields that do not have explicit
387 // @see EntityAccessControlHandler::checkFieldAccess()
388 $this->assertFieldAccess('some_non_existing_field', $viewer, $target, $view, $edit);
392 * Provides test data for testNonExistingFieldAccess().
394 public function NonExistingFieldAccessProvider() {
397 'viewer' => 'viewer',
398 'target' => 'viewer',
404 'target' => 'viewer',
415 return $created_access;