class UserAccessControlHandlerTest

Same name in other branches
  1. 9 core/modules/user/tests/src/Unit/UserAccessControlHandlerTest.php \Drupal\Tests\user\Unit\UserAccessControlHandlerTest
  2. 8.9.x core/modules/user/tests/src/Unit/UserAccessControlHandlerTest.php \Drupal\Tests\user\Unit\UserAccessControlHandlerTest
  3. 10 core/modules/user/tests/src/Unit/UserAccessControlHandlerTest.php \Drupal\Tests\user\Unit\UserAccessControlHandlerTest

Tests the user access controller.

@group Drupal @group User

@coversDefaultClass \Drupal\user\UserAccessControlHandler

Hierarchy

Expanded class hierarchy of UserAccessControlHandlerTest

File

core/modules/user/tests/src/Unit/UserAccessControlHandlerTest.php, line 21

Namespace

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

}

Members

Title Sort descending Modifiers Object type Summary Overriden Title
ExpectDeprecationTrait::expectDeprecation public function Adds an expected deprecation.
ExpectDeprecationTrait::getCallableName private static function Returns a callable as a string suitable for inclusion in a message.
ExpectDeprecationTrait::setUpErrorHandler public function Sets up the test error handler.
ExpectDeprecationTrait::tearDownErrorHandler public function Tears down the test error handler.
RandomGeneratorTrait::getRandomGenerator protected function Gets the random generator for the utility methods.
RandomGeneratorTrait::randomMachineName protected function Generates a unique random string containing letters and numbers.
RandomGeneratorTrait::randomObject public function Generates a random PHP object.
RandomGeneratorTrait::randomString public function Generates a pseudo-random string of ASCII characters of codes 32 to 126.
UnitTestCase::$root protected property The app root.
UnitTestCase::getClassResolverStub protected function Returns a stub class resolver.
UnitTestCase::getConfigFactoryStub public function Returns a stub config factory that behaves according to the passed array.
UnitTestCase::getConfigStorageStub public function Returns a stub config storage that returns the supplied configuration.
UnitTestCase::getContainerWithCacheTagsInvalidator protected function Sets up a container with a cache tags invalidator.
UnitTestCase::getStringTranslationStub public function Returns a stub translation manager that just returns the passed string.
UnitTestCase::setUpBeforeClass public static function
UserAccessControlHandlerTest::$accessControlHandler protected property The user access controller to test.
UserAccessControlHandlerTest::$admin protected property The mock administrative test user.
UserAccessControlHandlerTest::$emailViewer protected property The mock user account with 'view user email addresses' permission.
UserAccessControlHandlerTest::$items protected property The mocked test field items.
UserAccessControlHandlerTest::$owner protected property The mock user account that is able to change their own account name.
UserAccessControlHandlerTest::$viewer protected property The mock user account with view access.
UserAccessControlHandlerTest::adminFieldAccessProvider public static function Provides test data for testAdminFieldAccess().
UserAccessControlHandlerTest::assertFieldAccess public function Asserts correct field access grants for a field.
UserAccessControlHandlerTest::createdAccessProvider public static function Provides test data for testCreatedAccess().
UserAccessControlHandlerTest::hiddenUserSettingsProvider public static function Provides test data for testHiddenUserSettings().
UserAccessControlHandlerTest::NonExistingFieldAccessProvider public static function Provides test data for testNonExistingFieldAccess().
UserAccessControlHandlerTest::passwordAccessProvider public static function Provides test data for passwordAccessProvider().
UserAccessControlHandlerTest::setUp protected function Overrides UnitTestCase::setUp
UserAccessControlHandlerTest::testAdminFieldAccess public function Tests that private user settings cannot be viewed by other users.
UserAccessControlHandlerTest::testCreatedAccess public function Tests the user created field access.
UserAccessControlHandlerTest::testHiddenUserSettings public function Tests that private user settings cannot be viewed by other users.
UserAccessControlHandlerTest::testNonExistingFieldAccess public function Tests access to a non-existing base field.
UserAccessControlHandlerTest::testPasswordAccess public function Tests that passwords cannot be viewed, just edited.
UserAccessControlHandlerTest::testUserNameAccess public function Ensures user name access is working properly.
UserAccessControlHandlerTest::userNameProvider public static function Provides test data for testUserNameAccess().

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.