From 25b15d075cd4cc680aef9f489dc0992b34737e80 Mon Sep 17 00:00:00 2001
From: Kristiaan Van den Eynde <magentix@gmail.com>
Date: Thu, 25 May 2017 11:00:36 +0200
Subject: [PATCH] Issue #540008 by kristiaanvandeneynde, ianthomas_uk,
 greggles, michaelfavia: Remove the special behavior of uid #1

---
 core/lib/Drupal/Core/Session/AccountInterface.php          |  5 +++++
 core/lib/Drupal/Core/Session/UserSession.php               |  7 +------
 core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php     |  2 ++
 .../filter/tests/src/Kernel/FilterDefaultConfigTest.php    |  3 +++
 .../EntityResource/Role/RoleResourceTestBase.php           |  2 +-
 .../system/tests/src/Functional/Module/UninstallTest.php   |  3 ++-
 core/modules/user/config/install/user.role.superuser.yml   |  8 ++++++++
 core/modules/user/src/Authentication/Provider/Cookie.php   | 13 +++++++++++--
 core/modules/user/src/Entity/User.php                      | 14 +++++++-------
 core/modules/user/src/RoleInterface.php                    |  5 +++++
 .../user/tests/src/Kernel/Migrate/d6/MigrateUserTest.php   |  3 +++
 11 files changed, 48 insertions(+), 17 deletions(-)
 create mode 100644 core/modules/user/config/install/user.role.superuser.yml

diff --git a/core/lib/Drupal/Core/Session/AccountInterface.php b/core/lib/Drupal/Core/Session/AccountInterface.php
index 1cf82dc..18bf9bb 100644
--- a/core/lib/Drupal/Core/Session/AccountInterface.php
+++ b/core/lib/Drupal/Core/Session/AccountInterface.php
@@ -23,6 +23,11 @@
   const AUTHENTICATED_ROLE = 'authenticated';
 
   /**
+   * Role ID for the superuser account.
+   */
+  const SUPERUSER_ROLE = 'superuser';
+
+  /**
    * Returns the user ID or 0 for anonymous.
    *
    * @return int
diff --git a/core/lib/Drupal/Core/Session/UserSession.php b/core/lib/Drupal/Core/Session/UserSession.php
index f426803..4c86320 100644
--- a/core/lib/Drupal/Core/Session/UserSession.php
+++ b/core/lib/Drupal/Core/Session/UserSession.php
@@ -93,7 +93,7 @@ public function getRoles($exclude_locked_roles = FALSE) {
     $roles = $this->roles;
 
     if ($exclude_locked_roles) {
-      $roles = array_values(array_diff($roles, [AccountInterface::ANONYMOUS_ROLE, AccountInterface::AUTHENTICATED_ROLE]));
+      $roles = array_values(array_diff($roles, [AccountInterface::ANONYMOUS_ROLE, AccountInterface::AUTHENTICATED_ROLE, AccountInterface::SUPERUSER_ROLE]));
     }
 
     return $roles;
@@ -103,11 +103,6 @@ public function getRoles($exclude_locked_roles = FALSE) {
    * {@inheritdoc}
    */
   public function hasPermission($permission) {
-    // User #1 has all privileges.
-    if ((int) $this->id() === 1) {
-      return TRUE;
-    }
-
     return $this->getRoleStorage()->isPermissionInRoles($permission, $this->getRoles());
   }
 
diff --git a/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php b/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
index e9d8d66..a531c34 100644
--- a/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
+++ b/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
@@ -9,6 +9,7 @@
 use Drupal\Core\DrupalKernel;
 use Drupal\Core\Extension\MissingDependencyException;
 use Drupal\Core\Serialization\Yaml;
+use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Session\UserSession;
 use Drupal\Core\Site\Settings;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -368,6 +369,7 @@ protected function initUserSession() {
       'pass_raw' => $password,
       'passRaw' => $password,
       'timezone' => date_default_timezone_get(),
+      'roles' => [AccountInterface::AUTHENTICATED_ROLE, AccountInterface::SUPERUSER_ROLE]
     ]);
 
     // The child site derives its session name from the database prefix when
diff --git a/core/modules/filter/tests/src/Kernel/FilterDefaultConfigTest.php b/core/modules/filter/tests/src/Kernel/FilterDefaultConfigTest.php
index e16bdda..7b4ef56 100644
--- a/core/modules/filter/tests/src/Kernel/FilterDefaultConfigTest.php
+++ b/core/modules/filter/tests/src/Kernel/FilterDefaultConfigTest.php
@@ -47,6 +47,7 @@ public function testInstallation() {
     $this->assertEqual(array_keys(filter_get_roles_by_format($format)), [
       RoleInterface::ANONYMOUS_ID,
       RoleInterface::AUTHENTICATED_ID,
+      RoleInterface::SUPERUSER_ID,
     ]);
 
     // Verify enabled filters.
@@ -76,6 +77,7 @@ public function testUpdateRoles() {
     $this->assertEqual(array_keys(filter_get_roles_by_format($format)), [
       RoleInterface::ANONYMOUS_ID,
       RoleInterface::AUTHENTICATED_ID,
+      RoleInterface::SUPERUSER_ID,
     ]);
 
     // Attempt to change roles.
@@ -89,6 +91,7 @@ public function testUpdateRoles() {
     $this->assertEqual(array_keys(filter_get_roles_by_format($format)), [
       RoleInterface::ANONYMOUS_ID,
       RoleInterface::AUTHENTICATED_ID,
+      RoleInterface::SUPERUSER_ID,
     ]);
   }
 
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Role/RoleResourceTestBase.php b/core/modules/rest/tests/src/Functional/EntityResource/Role/RoleResourceTestBase.php
index ee719c4..041934d 100644
--- a/core/modules/rest/tests/src/Functional/EntityResource/Role/RoleResourceTestBase.php
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Role/RoleResourceTestBase.php
@@ -48,7 +48,7 @@ protected function createEntity() {
   protected function getExpectedNormalizedEntity() {
     return [
       'uuid' => $this->entity->uuid(),
-      'weight' => 2,
+      'weight' => 3,
       'langcode' => 'en',
       'status' => TRUE,
       'dependencies' => [],
diff --git a/core/modules/system/tests/src/Functional/Module/UninstallTest.php b/core/modules/system/tests/src/Functional/Module/UninstallTest.php
index 2b17b8f..a285d19 100644
--- a/core/modules/system/tests/src/Functional/Module/UninstallTest.php
+++ b/core/modules/system/tests/src/Functional/Module/UninstallTest.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Cache\Cache;
 use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Core\Entity\EntityMalformedException;
+use Drupal\Core\Session\AccountInterface;
 use Drupal\node\Entity\Node;
 use Drupal\node\Entity\NodeType;
 use Drupal\Tests\BrowserTestBase;
@@ -32,7 +33,7 @@ public function testUserPermsUninstalled() {
     $this->container->get('module_installer')->uninstall(['module_test']);
 
     // Are the perms defined by module_test removed?
-    $this->assertFalse(user_roles(FALSE, 'module_test perm'), 'Permissions were all removed.');
+    $this->assertEquals([AccountInterface::SUPERUSER_ROLE], user_roles(FALSE, 'module_test perm'), 'Permissions were all removed.');
   }
 
   /**
diff --git a/core/modules/user/config/install/user.role.superuser.yml b/core/modules/user/config/install/user.role.superuser.yml
new file mode 100644
index 0000000..1326493
--- /dev/null
+++ b/core/modules/user/config/install/user.role.superuser.yml
@@ -0,0 +1,8 @@
+langcode: en
+status: true
+dependencies: {  }
+id: superuser
+label: 'Superuser'
+weight: 2
+is_admin: true
+permissions: {  }
diff --git a/core/modules/user/src/Authentication/Provider/Cookie.php b/core/modules/user/src/Authentication/Provider/Cookie.php
index ebcdae7..bd0de3e 100644
--- a/core/modules/user/src/Authentication/Provider/Cookie.php
+++ b/core/modules/user/src/Authentication/Provider/Cookie.php
@@ -76,11 +76,20 @@ protected function getUserFromSession(SessionInterface $session) {
 
       // Check if the user data was found and the user is active.
       if (!empty($values) && $values['status'] == 1) {
-        // Add the user's roles.
+        // Fetch the user's roles.
         $rids = $this->connection
           ->query('SELECT roles_target_id FROM {user__roles} WHERE entity_id = :uid', [':uid' => $values['uid']])
           ->fetchCol();
-        $values['roles'] = array_merge([AccountInterface::AUTHENTICATED_ROLE], $rids);
+
+        // Add in the authenticated user role. If we're dealing with the
+        // superuser account, add the superuser role as well.
+        $added_roles = [AccountInterface::AUTHENTICATED_ROLE];
+        if ($uid == 1) {
+          $added_roles[] = AccountInterface::SUPERUSER_ROLE;
+        }
+
+        // Add the user's roles to the session values.
+        $values['roles'] = array_merge($added_roles, $rids);
 
         return new UserSession($values);
       }
diff --git a/core/modules/user/src/Entity/User.php b/core/modules/user/src/Entity/User.php
index 7529532..c7be251 100644
--- a/core/modules/user/src/Entity/User.php
+++ b/core/modules/user/src/Entity/User.php
@@ -146,6 +146,11 @@ public function getRoles($exclude_locked_roles = FALSE) {
     if (!$exclude_locked_roles) {
       if ($this->isAuthenticated()) {
         $roles[] = RoleInterface::AUTHENTICATED_ID;
+
+        // The superuser account gets the superuser role.
+        if ($this->id() == 1) {
+          $roles[] = RoleInterface::SUPERUSER_ID;
+        }
       }
       else {
         $roles[] = RoleInterface::ANONYMOUS_ID;
@@ -173,8 +178,8 @@ public function hasRole($rid) {
    */
   public function addRole($rid) {
 
-    if (in_array($rid, [RoleInterface::AUTHENTICATED_ID, RoleInterface::ANONYMOUS_ID])) {
-      throw new \InvalidArgumentException('Anonymous or authenticated role ID must not be assigned manually.');
+    if (in_array($rid, [RoleInterface::AUTHENTICATED_ID, RoleInterface::ANONYMOUS_ID, RoleInterface::SUPERUSER_ID])) {
+      throw new \InvalidArgumentException('Anonymous, authenticated or superuser role ID must not be assigned manually.');
     }
 
     $roles = $this->getRoles(TRUE);
@@ -193,11 +198,6 @@ public function removeRole($rid) {
    * {@inheritdoc}
    */
   public function hasPermission($permission) {
-    // User #1 has all privileges.
-    if ((int) $this->id() === 1) {
-      return TRUE;
-    }
-
     return $this->getRoleStorage()->isPermissionInRoles($permission, $this->getRoles());
   }
 
diff --git a/core/modules/user/src/RoleInterface.php b/core/modules/user/src/RoleInterface.php
index 4633637..3c09569 100644
--- a/core/modules/user/src/RoleInterface.php
+++ b/core/modules/user/src/RoleInterface.php
@@ -23,6 +23,11 @@
   const AUTHENTICATED_ID = AccountInterface::AUTHENTICATED_ROLE;
 
   /**
+   * Role ID for the superuser account; should match what's in the "role" table.
+   */
+  const SUPERUSER_ID = AccountInterface::SUPERUSER_ROLE;
+
+  /**
    * Returns a list of permissions assigned to the role.
    *
    * @return array
diff --git a/core/modules/user/tests/src/Kernel/Migrate/d6/MigrateUserTest.php b/core/modules/user/tests/src/Kernel/Migrate/d6/MigrateUserTest.php
index ed28777..79bf355 100644
--- a/core/modules/user/tests/src/Kernel/Migrate/d6/MigrateUserTest.php
+++ b/core/modules/user/tests/src/Kernel/Migrate/d6/MigrateUserTest.php
@@ -89,6 +89,9 @@ public function testUser() {
         ->execute()
         ->fetchCol();
       $roles = [RoleInterface::AUTHENTICATED_ID];
+      if ($source->uid == 1) {
+        $roles[] = RoleInterface::SUPERUSER_ID;
+      }
       $id_map = $this->getMigration('d6_user_role')->getIdMap();
       foreach ($rids as $rid) {
         $role = $id_map->lookupDestinationId([$rid]);
-- 
2.8.1

