Chris@0: prophesize(CacheContextsManager::class); Chris@0: $cache_contexts_manager->assertValidTokens()->willReturn(TRUE); Chris@0: $cache_contexts_manager->reveal(); Chris@0: $container = new Container(); Chris@0: $container->set('cache_contexts_manager', $cache_contexts_manager); Chris@0: \Drupal::setContainer($container); Chris@0: Chris@0: $this->viewer = $this->getMock('\Drupal\Core\Session\AccountInterface'); Chris@0: $this->viewer Chris@0: ->expects($this->any()) Chris@0: ->method('hasPermission') Chris@0: ->will($this->returnValue(FALSE)); Chris@0: $this->viewer Chris@0: ->expects($this->any()) Chris@0: ->method('id') Chris@0: ->will($this->returnValue(1)); Chris@0: Chris@0: $this->owner = $this->getMock('\Drupal\Core\Session\AccountInterface'); Chris@0: $this->owner Chris@0: ->expects($this->any()) Chris@0: ->method('hasPermission') Chris@0: ->will($this->returnValueMap([ Chris@0: ['administer users', FALSE], Chris@0: ['change own username', TRUE], Chris@0: ])); Chris@0: Chris@0: $this->owner Chris@0: ->expects($this->any()) Chris@0: ->method('id') Chris@0: ->will($this->returnValue(2)); Chris@0: Chris@0: $this->admin = $this->getMock('\Drupal\Core\Session\AccountInterface'); Chris@0: $this->admin Chris@0: ->expects($this->any()) Chris@0: ->method('hasPermission') Chris@0: ->will($this->returnValue(TRUE)); Chris@0: Chris@0: $entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface'); Chris@0: Chris@0: $this->accessControlHandler = new UserAccessControlHandler($entity_type); Chris@0: $module_handler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface'); Chris@0: $module_handler->expects($this->any()) Chris@0: ->method('getImplementations') Chris@0: ->will($this->returnValue([])); Chris@0: $this->accessControlHandler->setModuleHandler($module_handler); Chris@0: Chris@0: $this->items = $this->getMockBuilder('Drupal\Core\Field\FieldItemList') Chris@0: ->disableOriginalConstructor() Chris@0: ->getMock(); Chris@0: $this->items Chris@0: ->expects($this->any()) Chris@0: ->method('defaultAccess') Chris@0: ->will($this->returnValue(AccessResult::allowed())); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Asserts correct field access grants for a field. Chris@0: */ Chris@0: public function assertFieldAccess($field, $viewer, $target, $view, $edit) { Chris@0: $field_definition = $this->getMock('Drupal\Core\Field\FieldDefinitionInterface'); Chris@0: $field_definition->expects($this->any()) Chris@0: ->method('getName') Chris@0: ->will($this->returnValue($field)); Chris@0: Chris@0: $this->items Chris@0: ->expects($this->any()) Chris@0: ->method('getEntity') Chris@0: ->will($this->returnValue($this->{$target})); Chris@0: Chris@0: foreach (['view' => $view, 'edit' => $edit] as $operation => $result) { Chris@0: $result_text = !isset($result) ? 'null' : ($result ? 'true' : 'false'); Chris@0: $message = "User '$field' field access returns '$result_text' with operation '$operation' for '$viewer' accessing '$target'"; Chris@0: $this->assertSame($result, $this->accessControlHandler->fieldAccess($operation, $field_definition, $this->{$viewer}, $this->items), $message); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Ensures user name access is working properly. Chris@0: * Chris@0: * @dataProvider userNameProvider Chris@0: */ Chris@0: public function testUserNameAccess($viewer, $target, $view, $edit) { Chris@0: $this->assertFieldAccess('name', $viewer, $target, $view, $edit); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Provides test data for testUserNameAccess(). Chris@0: */ Chris@0: public function userNameProvider() { Chris@0: $name_access = [ Chris@0: // The viewer user is allowed to see user names on all accounts. Chris@0: [ Chris@0: 'viewer' => 'viewer', Chris@0: 'target' => 'viewer', Chris@0: 'view' => TRUE, Chris@0: 'edit' => FALSE, Chris@0: ], Chris@0: [ Chris@0: 'viewer' => 'owner', Chris@0: 'target' => 'viewer', Chris@0: 'view' => TRUE, Chris@0: 'edit' => FALSE, Chris@0: ], Chris@0: [ Chris@0: 'viewer' => 'viewer', Chris@0: 'target' => 'owner', Chris@0: 'view' => TRUE, Chris@0: 'edit' => FALSE, Chris@0: ], Chris@0: // The owner user is allowed to change its own user name. Chris@0: [ Chris@0: 'viewer' => 'owner', Chris@0: 'target' => 'owner', Chris@0: 'view' => TRUE, Chris@0: 'edit' => TRUE, Chris@0: ], Chris@0: // The users-administrator user has full access. Chris@0: [ Chris@0: 'viewer' => 'admin', Chris@0: 'target' => 'owner', Chris@0: 'view' => TRUE, Chris@0: 'edit' => TRUE, Chris@0: ], Chris@0: ]; Chris@0: return $name_access; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that private user settings cannot be viewed by other users. Chris@0: * Chris@0: * @dataProvider hiddenUserSettingsProvider Chris@0: */ Chris@0: public function testHiddenUserSettings($field, $viewer, $target, $view, $edit) { Chris@0: $this->assertFieldAccess($field, $viewer, $target, $view, $edit); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Provides test data for testHiddenUserSettings(). Chris@0: */ Chris@0: public function hiddenUserSettingsProvider() { Chris@0: $access_info = []; Chris@0: Chris@0: $fields = [ Chris@0: 'preferred_langcode', Chris@0: 'preferred_admin_langcode', Chris@0: 'timezone', Chris@0: 'mail', Chris@0: ]; Chris@0: Chris@0: foreach ($fields as $field) { Chris@0: $access_info[] = [ Chris@0: 'field' => $field, Chris@0: 'viewer' => 'viewer', Chris@0: 'target' => 'viewer', Chris@0: 'view' => TRUE, Chris@0: 'edit' => TRUE, Chris@0: ]; Chris@0: $access_info[] = [ Chris@0: 'field' => $field, Chris@0: 'viewer' => 'viewer', Chris@0: 'target' => 'owner', Chris@0: 'view' => FALSE, Chris@0: // Anyone with edit access to the user can also edit these fields. In Chris@0: // reality edit access will already be checked on entity level and the Chris@0: // user without view access will typically not be able to edit. Chris@0: 'edit' => TRUE, Chris@0: ]; Chris@0: $access_info[] = [ Chris@0: 'field' => $field, Chris@0: 'viewer' => 'owner', Chris@0: 'target' => 'owner', Chris@0: 'view' => TRUE, Chris@0: 'edit' => TRUE, Chris@0: ]; Chris@0: $access_info[] = [ Chris@0: 'field' => $field, Chris@0: 'viewer' => 'admin', Chris@0: 'target' => 'owner', Chris@0: 'view' => TRUE, Chris@0: 'edit' => TRUE, Chris@0: ]; Chris@0: } Chris@0: Chris@0: return $access_info; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that private user settings cannot be viewed by other users. Chris@0: * Chris@0: * @dataProvider adminFieldAccessProvider Chris@0: */ Chris@0: public function testAdminFieldAccess($field, $viewer, $target, $view, $edit) { Chris@0: $this->assertFieldAccess($field, $viewer, $target, $view, $edit); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Provides test data for testAdminFieldAccess(). Chris@0: */ Chris@0: public function adminFieldAccessProvider() { Chris@0: $access_info = []; Chris@0: Chris@0: $fields = [ Chris@0: 'roles', Chris@0: 'status', Chris@0: 'access', Chris@0: 'login', Chris@0: 'init', Chris@0: ]; Chris@0: Chris@0: foreach ($fields as $field) { Chris@0: $access_info[] = [ Chris@0: 'field' => $field, Chris@0: 'viewer' => 'viewer', Chris@0: 'target' => 'viewer', Chris@0: 'view' => FALSE, Chris@0: 'edit' => FALSE, Chris@0: ]; Chris@0: $access_info[] = [ Chris@0: 'field' => $field, Chris@0: 'viewer' => 'viewer', Chris@0: 'target' => 'owner', Chris@0: 'view' => FALSE, Chris@0: 'edit' => FALSE, Chris@0: ]; Chris@0: $access_info[] = [ Chris@0: 'field' => $field, Chris@0: 'viewer' => 'admin', Chris@0: 'target' => 'owner', Chris@0: 'view' => TRUE, Chris@0: 'edit' => TRUE, Chris@0: ]; Chris@0: } Chris@0: Chris@0: return $access_info; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that passwords cannot be viewed, just edited. Chris@0: * Chris@0: * @dataProvider passwordAccessProvider Chris@0: */ Chris@0: public function testPasswordAccess($viewer, $target, $view, $edit) { Chris@0: $this->assertFieldAccess('pass', $viewer, $target, $view, $edit); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Provides test data for passwordAccessProvider(). Chris@0: */ Chris@0: public function passwordAccessProvider() { Chris@0: $pass_access = [ Chris@0: [ Chris@0: 'viewer' => 'viewer', Chris@0: 'target' => 'viewer', Chris@0: 'view' => FALSE, Chris@0: 'edit' => TRUE, Chris@0: ], Chris@0: [ Chris@0: 'viewer' => 'viewer', Chris@0: 'target' => 'owner', Chris@0: 'view' => FALSE, Chris@0: // Anyone with edit access to the user can also edit these fields. In Chris@0: // reality edit access will already be checked on entity level and the Chris@0: // user without view access will typically not be able to edit. Chris@0: 'edit' => TRUE, Chris@0: ], Chris@0: [ Chris@0: 'viewer' => 'owner', Chris@0: 'target' => 'viewer', Chris@0: 'view' => FALSE, Chris@0: 'edit' => TRUE, Chris@0: ], Chris@0: [ Chris@0: 'viewer' => 'admin', Chris@0: 'target' => 'owner', Chris@0: 'view' => FALSE, Chris@0: 'edit' => TRUE, Chris@0: ], Chris@0: ]; Chris@0: return $pass_access; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the user created field access. Chris@0: * Chris@0: * @dataProvider createdAccessProvider Chris@0: */ Chris@0: public function testCreatedAccess($viewer, $target, $view, $edit) { Chris@0: $this->assertFieldAccess('created', $viewer, $target, $view, $edit); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Provides test data for testCreatedAccess(). Chris@0: */ Chris@0: public function createdAccessProvider() { Chris@0: $created_access = [ Chris@0: [ Chris@0: 'viewer' => 'viewer', Chris@0: 'target' => 'viewer', Chris@0: 'view' => TRUE, Chris@0: 'edit' => FALSE, Chris@0: ], Chris@0: [ Chris@0: 'viewer' => 'owner', Chris@0: 'target' => 'viewer', Chris@0: 'view' => TRUE, Chris@0: 'edit' => FALSE, Chris@0: ], Chris@0: [ Chris@0: 'viewer' => 'admin', Chris@0: 'target' => 'owner', Chris@0: 'view' => TRUE, Chris@0: 'edit' => TRUE, Chris@0: ], Chris@0: ]; Chris@0: return $created_access; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests access to a non-existing base field. Chris@0: * Chris@0: * @dataProvider NonExistingFieldAccessProvider Chris@0: */ Chris@0: public function testNonExistingFieldAccess($viewer, $target, $view, $edit) { Chris@0: // By default everyone has access to all fields that do not have explicit Chris@0: // access control. Chris@0: // @see EntityAccessControlHandler::checkFieldAccess() Chris@0: $this->assertFieldAccess('some_non_existing_field', $viewer, $target, $view, $edit); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Provides test data for testNonExistingFieldAccess(). Chris@0: */ Chris@0: public function NonExistingFieldAccessProvider() { Chris@0: $created_access = [ Chris@0: [ Chris@0: 'viewer' => 'viewer', Chris@0: 'target' => 'viewer', Chris@0: 'view' => TRUE, Chris@0: 'edit' => TRUE, Chris@0: ], Chris@0: [ Chris@0: 'viewer' => 'owner', Chris@0: 'target' => 'viewer', Chris@0: 'view' => TRUE, Chris@0: 'edit' => TRUE, Chris@0: ], Chris@0: [ Chris@0: 'viewer' => 'admin', Chris@0: 'target' => 'owner', Chris@0: 'view' => TRUE, Chris@0: 'edit' => TRUE, Chris@0: ], Chris@0: ]; Chris@0: return $created_access; Chris@0: } Chris@0: Chris@0: }