summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDries2013-07-18 18:31:35 (GMT)
committerDries2013-07-18 18:31:35 (GMT)
commitedcd8df4bd07a4ff986e83c8c3a38bd65f15bd26 (patch)
tree570fa3c960c3ff1d247acea2be8c44bb82c482e9
parent4f6161a226704a71e0aa734d7001669e229bdfc9 (diff)
Issue #1966334 by Alan Evans, fubhy, dawehner, ParisLiakos: Convert user_access() to User::hasPermission().
-rw-r--r--core/lib/Drupal/Core/Extension/UpdateModuleHandler.php4
-rw-r--r--core/lib/Drupal/Core/Session/AccountInterface.php11
-rw-r--r--core/lib/Drupal/Core/Session/UserSession.php20
-rw-r--r--core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php20
-rw-r--r--core/modules/user/lib/Drupal/user/RoleStorageController.php9
-rw-r--r--core/modules/user/lib/Drupal/user/UserBCDecorator.php7
-rw-r--r--core/modules/user/lib/Drupal/user/UserInterface.php11
-rw-r--r--core/modules/user/tests/Drupal/user/Tests/Plugin/Core/Entity/UserTest.php46
-rw-r--r--core/modules/user/user.module26
-rw-r--r--core/tests/Drupal/Tests/Core/Session/UserSessionTest.php156
10 files changed, 276 insertions, 34 deletions
diff --git a/core/lib/Drupal/Core/Extension/UpdateModuleHandler.php b/core/lib/Drupal/Core/Extension/UpdateModuleHandler.php
index 0ef5259..0e5a57b 100644
--- a/core/lib/Drupal/Core/Extension/UpdateModuleHandler.php
+++ b/core/lib/Drupal/Core/Extension/UpdateModuleHandler.php
@@ -41,6 +41,10 @@ class UpdateModuleHandler extends ModuleHandler {
return array('system');
// This is called during rebuild to find testing themes.
case 'system_theme_info':
+ // Those are needed by user_access() to check access on update.php.
+ case 'entity_info':
+ case 'entity_load':
+ case 'user_role_load':
return array();
// t() in system_stream_wrappers() needs this. Other schema calls aren't
// supported.
diff --git a/core/lib/Drupal/Core/Session/AccountInterface.php b/core/lib/Drupal/Core/Session/AccountInterface.php
index 3771437..a53d088 100644
--- a/core/lib/Drupal/Core/Session/AccountInterface.php
+++ b/core/lib/Drupal/Core/Session/AccountInterface.php
@@ -32,6 +32,17 @@ interface AccountInterface {
public function getRoles();
/**
+ * Checks whether a user has a certain permission.
+ *
+ * @param string $permission
+ * The permission string to check.
+ *
+ * @return bool
+ * TRUE if the user has the permission, FALSE otherwise.
+ */
+ public function hasPermission($permission);
+
+ /**
* Returns the session ID.
*
* @return string|NULL
diff --git a/core/lib/Drupal/Core/Session/UserSession.php b/core/lib/Drupal/Core/Session/UserSession.php
index b3dae61..7922d06 100644
--- a/core/lib/Drupal/Core/Session/UserSession.php
+++ b/core/lib/Drupal/Core/Session/UserSession.php
@@ -115,6 +115,26 @@ class UserSession implements AccountInterface {
/**
* {@inheritdoc}
*/
+ public function hasPermission($permission) {
+ // User #1 has all privileges.
+ if ((int) $this->id() === 1) {
+ return TRUE;
+ }
+
+ $roles = \Drupal::entityManager()->getStorageController('user_role')->loadMultiple($this->getRoles());
+
+ foreach ($roles as $role) {
+ if ($role->hasPermission($permission)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
public function getSecureSessionId() {
return $this->ssid;
}
diff --git a/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php b/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php
index 413cdb7..b229ff1 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php
@@ -218,6 +218,26 @@ class User extends EntityNG implements UserInterface {
/**
* {@inheritdoc}
*/
+ public function hasPermission($permission) {
+ // User #1 has all privileges.
+ if ((int) $this->id() === 1) {
+ return TRUE;
+ }
+
+ $roles = \Drupal::entityManager()->getStorageController('user_role')->loadMultiple($this->getRoles());
+
+ foreach ($roles as $role) {
+ if ($role->hasPermission($permission)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
public function getPassword() {
return $this->get('pass')->value;
}
diff --git a/core/modules/user/lib/Drupal/user/RoleStorageController.php b/core/modules/user/lib/Drupal/user/RoleStorageController.php
index fff106e..ff012f3 100644
--- a/core/modules/user/lib/Drupal/user/RoleStorageController.php
+++ b/core/modules/user/lib/Drupal/user/RoleStorageController.php
@@ -17,15 +17,6 @@ class RoleStorageController extends ConfigStorageController implements RoleStora
/**
* {@inheritdoc}
*/
- public function resetCache(array $ids = NULL) {
- parent::resetCache($ids);
- // Clear the user access cache.
- drupal_static_reset('user_access');
- }
-
- /**
- * {@inheritdoc}
- */
public function deleteRoleReferences(array $rids) {
// Remove the role from all users.
db_delete('users_roles')
diff --git a/core/modules/user/lib/Drupal/user/UserBCDecorator.php b/core/modules/user/lib/Drupal/user/UserBCDecorator.php
index 4568f00..d705d56 100644
--- a/core/modules/user/lib/Drupal/user/UserBCDecorator.php
+++ b/core/modules/user/lib/Drupal/user/UserBCDecorator.php
@@ -44,6 +44,13 @@ class UserBCDecorator extends EntityBCDecorator implements UserInterface {
/**
* {@inheritdoc}
*/
+ public function hasPermission($permission) {
+ return $this->decorated->hasPermission($permission);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
public function getSecureSessionId() {
return $this->decorated->getSecureSessionId();
}
diff --git a/core/modules/user/lib/Drupal/user/UserInterface.php b/core/modules/user/lib/Drupal/user/UserInterface.php
index fbede92..832be39 100644
--- a/core/modules/user/lib/Drupal/user/UserInterface.php
+++ b/core/modules/user/lib/Drupal/user/UserInterface.php
@@ -51,6 +51,17 @@ interface UserInterface extends EntityInterface, AccountInterface {
public function removeRole($rid);
/**
+ * Checks whether a user has a certain permission.
+ *
+ * @param string $permission
+ * The permission string to check.
+ *
+ * @return bool
+ * TRUE if the user has the permission, FALSE otherwise.
+ */
+ public function hasPermission($permission);
+
+ /**
* Returns the hashed password.
*
* @return string
diff --git a/core/modules/user/tests/Drupal/user/Tests/Plugin/Core/Entity/UserTest.php b/core/modules/user/tests/Drupal/user/Tests/Plugin/Core/Entity/UserTest.php
new file mode 100644
index 0000000..0758f63
--- /dev/null
+++ b/core/modules/user/tests/Drupal/user/Tests/Plugin/Core/Entity/UserTest.php
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\Tests\Plugin\Core\Entity\UserTest.
+ */
+
+namespace Drupal\user\Tests\Plugin\Core\Entity;
+
+use Drupal\Tests\Core\Session\UserSessionTest;
+use Drupal\user\Plugin\Core\Entity\User;
+
+/**
+ * Tests the user object.
+ *
+ * @see \Drupal\user\Plugin\Core\Entity\User
+ */
+class UserTest extends UserSessionTest {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'User object',
+ 'description' => 'Tests the user object.',
+ 'group' => 'User',
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function createUserSession(array $rids = array()) {
+ $user = $this->getMockBuilder('Drupal\user\Plugin\Core\Entity\User')
+ ->disableOriginalConstructor()
+ ->setMethods(array('getRoles', 'id'))
+ ->getMock();
+ $user->expects($this->any())
+ ->method('id')
+ // @todo Also test the uid = 1 handling.
+ ->will($this->returnValue(0));
+ $user->expects($this->any())
+ ->method('getRoles')
+ ->will($this->returnValue($rids));
+ return $user;
+ }
+
+}
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 50580ff..5127a4c 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -462,27 +462,7 @@ function user_access($string, AccountInterface $account = NULL) {
$account = Drupal::request()->attributes->get('account') ?: $user;
}
- // User #1 has all privileges:
- if ($account->id() == 1) {
- return TRUE;
- }
-
- // To reduce the number of SQL queries, we cache the user's permissions
- // in a static variable.
- // Use the advanced drupal_static() pattern, since this is called very often.
- static $drupal_static_fast;
- if (!isset($drupal_static_fast)) {
- $drupal_static_fast['perm'] = &drupal_static(__FUNCTION__);
- }
- $perm = &$drupal_static_fast['perm'];
- if (!isset($perm[$account->id()])) {
- $perm[$account->id()] = array();
- foreach (user_role_permissions($account->getRoles()) as $role_permissions) {
- $perm[$account->id()] += array_fill_keys($role_permissions, TRUE);
- }
- }
-
- return isset($perm[$account->id()][$string]);
+ return $account->hasPermission($string);
}
/**
@@ -1744,8 +1724,6 @@ function user_role_grant_permissions($rid, array $permissions = array()) {
$role->grantPermission($permission);
}
$role->save();
- // Clear the user access cache.
- drupal_static_reset('user_access');
}
/**
@@ -1766,8 +1744,6 @@ function user_role_revoke_permissions($rid, array $permissions = array()) {
$role->revokePermission($permission);
}
$role->save();
- // Clear the user access cache.
- drupal_static_reset('user_access');
}
function user_multiple_cancel_confirm($form, &$form_state) {
diff --git a/core/tests/Drupal/Tests/Core/Session/UserSessionTest.php b/core/tests/Drupal/Tests/Core/Session/UserSessionTest.php
new file mode 100644
index 0000000..1c26b56
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Session/UserSessionTest.php
@@ -0,0 +1,156 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\Session\UserSessionTest.
+ */
+
+namespace Drupal\Tests\Core\Session;
+
+use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\Session\UserSession;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * Tests the user session object.
+ *
+ * @see \Drupal\Core\Session\UserSession
+ */
+class UserSessionTest extends UnitTestCase {
+
+ /**
+ * The user sessions used in the test
+ *
+ * @var \Drupal\Core\Session\AccountInterface[]
+ */
+ protected $users = array();
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'User session object',
+ 'description' => 'Tests the user session object.',
+ 'group' => 'Session',
+ );
+ }
+
+ /**
+ * Provides test data for getHasPermission().
+ *
+ * @return array
+ */
+ public function providerTestHasPermission() {
+ $data = array();
+ $data[] = array('example permission', array('user_one', 'user_two'), array('user_last'));
+ $data[] = array('another example permission', array('user_two'), array('user_one', 'user_last'));
+ $data[] = array('final example permission', array(), array('user_one', 'user_two', 'user_last'));
+
+ return $data;
+ }
+
+ /**
+ * Setups a user session for the test.
+ *
+ * @param array $rids
+ * The rids of the user.
+ *
+ * @return \Drupal\Core\Session\AccountInterface
+ * The created user session.
+ */
+ protected function createUserSession(array $rids = array()) {
+ return new UserSession(array('roles' => $rids));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ parent::setUp();
+
+ $roles = array();
+ $roles['role_one'] = $this->getMockBuilder('Drupal\user\Plugin\Core\Entity\Role')
+ ->disableOriginalConstructor()
+ ->setMethods(array('hasPermission'))
+ ->getMock();
+ $roles['role_one']->expects($this->any())
+ ->method('hasPermission')
+ ->will($this->returnValueMap(array(
+ array('example permission', TRUE),
+ array('another example permission', FALSE),
+ array('last example permission', FALSE),
+ )));
+
+ $roles['role_two'] = $this->getMockBuilder('Drupal\user\Plugin\Core\Entity\Role')
+ ->disableOriginalConstructor()
+ ->setMethods(array('hasPermission'))
+ ->getMock();
+ $roles['role_two']->expects($this->any())
+ ->method('hasPermission')
+ ->will($this->returnValueMap(array(
+ array('example permission', TRUE),
+ array('another example permission', TRUE),
+ array('last example permission', FALSE),
+ )));
+
+ $role_storage = $this->getMockBuilder('Drupal\user\RoleStorageController')
+ ->disableOriginalConstructor()
+ ->setMethods(array('loadMultiple'))
+ ->getMock();
+ $role_storage->expects($this->any())
+ ->method('loadMultiple')
+ ->will($this->returnValueMap(array(
+ array(array(), array()),
+ array(NULL, $roles),
+ array(array('role_one'), array($roles['role_one'])),
+ array(array('role_two'), array($roles['role_two'])),
+ array(array('role_one', 'role_two'), array($roles['role_one'], $roles['role_two'])),
+ )));
+
+ $entity_manager = $this->getMockBuilder('Drupal\Core\Entity\EntityManager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $entity_manager->expects($this->any())
+ ->method('getStorageController')
+ ->with($this->equalTo('user_role'))
+ ->will($this->returnValue($role_storage));
+ $container = new ContainerBuilder();
+ $container->set('plugin.manager.entity', $entity_manager);
+ \Drupal::setContainer($container);
+
+ $this->users['user_one'] = $this->createUserSession(array('role_one'));
+ $this->users['user_two'] = $this->createUserSession(array('role_one', 'role_two'));
+ $this->users['user_last'] = $this->createUserSession();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function tearDown() {
+ parent::tearDown();
+ $container = new ContainerBuilder();
+ \Drupal::setContainer($container);
+ }
+
+ /**
+ * Tests the has permission method.
+ *
+ * @param string $permission
+ * The permission to check.
+ * @param \Drupal\Core\Session\AccountInterface[] $sessions_with_access
+ * The users with access.
+ * @param \Drupal\Core\Session\AccountInterface[] $sessions_without_access
+ * The users without access.
+ *
+ * @dataProvider providerTestHasPermission
+ *
+ * @see \Drupal\Core\Session\UserSession::hasPermission().
+ */
+ public function testHasPermission($permission, array $sessions_with_access, array $sessions_without_access) {
+ foreach ($sessions_with_access as $name) {
+ $this->assertTrue($this->users[$name]->hasPermission($permission));
+ }
+ foreach ($sessions_without_access as $name) {
+ $this->assertFalse($this->users[$name]->hasPermission($permission));
+ }
+ }
+
+}