Factors out permissions check from User into PermissionManager service
authorVedmaka <god.vedmaka@gmail.com>
Tue, 9 Apr 2019 06:58:04 +0000 (09:58 +0300)
committerdaniel <dkinzler@wikimedia.org>
Wed, 29 May 2019 15:41:07 +0000 (17:41 +0200)
The following methods should are factored out of the User class into PermissionManager, leaving only deprecated stubs:

- User::isAllowed -> PermissionManager::userHasRight
- User::getRights -> PermissionManager::getUserPermissions
- User::groupHasPermission -> PermissionManager::groupHasPermission
- User::getGroupPermissions -> PermissionManager::getGroupPermissions
 -User::getGroupsWithPermission -> PermissionManager::getGroupsWithPermission
- User::groupHasPermission -> PermissionManager::groupHasPermission
- User::isEveryoneAllowed -> PermissionManager::isEveryoneAllowed
- User::getAllRights -> PermissionManager::getAllPermissions

Depends-On: I258f02e286b6ba0387e1bff540a744fafb03dc55
Depends-On: Ie4cedf457eaaa93ec3055c37539322855e02ce26
Depends-On: Id274f240d687efa61cb9f7a15033ae2a7a532083

Bug: T218558
Bug: T223294
Change-Id: Ia0d840b772ea5f20c9594ce151cc57adc270e48b

25 files changed:
includes/Permissions/PermissionManager.php
includes/ServiceWiring.php
includes/user/User.php
tests/phpunit/MediaWikiTestCase.php
tests/phpunit/includes/Permissions/PermissionManagerTest.php
tests/phpunit/includes/RevisionDbTestBase.php
tests/phpunit/includes/TemplateCategoriesTest.php
tests/phpunit/includes/TitlePermissionTest.php
tests/phpunit/includes/TitleTest.php
tests/phpunit/includes/actions/ActionTest.php
tests/phpunit/includes/api/ApiBlockTest.php
tests/phpunit/includes/api/ApiDeleteTest.php
tests/phpunit/includes/api/ApiEditPageTest.php
tests/phpunit/includes/api/ApiMainTest.php
tests/phpunit/includes/api/ApiMoveTest.php
tests/phpunit/includes/api/ApiParseTest.php
tests/phpunit/includes/api/ApiStashEditTest.php
tests/phpunit/includes/api/ApiUnblockTest.php
tests/phpunit/includes/api/ApiUserrightsTest.php
tests/phpunit/includes/auth/AuthManagerTest.php
tests/phpunit/includes/page/ArticleTablesTest.php
tests/phpunit/includes/page/WikiPageDbTestBase.php
tests/phpunit/includes/user/LocalIdLookupTest.php
tests/phpunit/includes/user/UserGroupMembershipTest.php
tests/phpunit/includes/user/UserTest.php

index e443803..0f68a13 100644 (file)
@@ -21,12 +21,12 @@ namespace MediaWiki\Permissions;
 
 use Action;
 use Exception;
-use FatalError;
 use Hooks;
 use MediaWiki\Linker\LinkTarget;
+use MediaWiki\Session\SessionManager;
 use MediaWiki\Special\SpecialPageFactory;
+use MediaWiki\User\UserIdentity;
 use MessageSpecifier;
-use MWException;
 use NamespaceInfo;
 use RequestContext;
 use SpecialPage;
@@ -69,12 +69,121 @@ class PermissionManager {
        /** @var NamespaceInfo */
        private $nsInfo;
 
+       /** @var string[][] Access rights for groups and users in these groups */
+       private $groupPermissions;
+
+       /** @var string[][] Permission keys revoked from users in each group */
+       private $revokePermissions;
+
+       /** @var string[] A list of available rights, in addition to the ones defined by the core */
+       private $availableRights;
+
+       /** @var string[] Cached results of getAllRights() */
+       private $allRights = false;
+
+       /** @var string[][] Cached user rights */
+       private $usersRights = null;
+
+       /** @var string[] Cached rights for isEveryoneAllowed */
+       private $cachedRights = [];
+
+       /**
+        * Array of Strings Core rights.
+        * Each of these should have a corresponding message of the form
+        * "right-$right".
+        * @showinitializer
+        */
+       private $coreRights = [
+               'apihighlimits',
+               'applychangetags',
+               'autoconfirmed',
+               'autocreateaccount',
+               'autopatrol',
+               'bigdelete',
+               'block',
+               'blockemail',
+               'bot',
+               'browsearchive',
+               'changetags',
+               'createaccount',
+               'createpage',
+               'createtalk',
+               'delete',
+               'deletechangetags',
+               'deletedhistory',
+               'deletedtext',
+               'deletelogentry',
+               'deleterevision',
+               'edit',
+               'editcontentmodel',
+               'editinterface',
+               'editprotected',
+               'editmyoptions',
+               'editmyprivateinfo',
+               'editmyusercss',
+               'editmyuserjson',
+               'editmyuserjs',
+               'editmywatchlist',
+               'editsemiprotected',
+               'editsitecss',
+               'editsitejson',
+               'editsitejs',
+               'editusercss',
+               'edituserjson',
+               'edituserjs',
+               'hideuser',
+               'import',
+               'importupload',
+               'ipblock-exempt',
+               'managechangetags',
+               'markbotedits',
+               'mergehistory',
+               'minoredit',
+               'move',
+               'movefile',
+               'move-categorypages',
+               'move-rootuserpages',
+               'move-subpages',
+               'nominornewtalk',
+               'noratelimit',
+               'override-export-depth',
+               'pagelang',
+               'patrol',
+               'patrolmarks',
+               'protect',
+               'purge',
+               'read',
+               'reupload',
+               'reupload-own',
+               'reupload-shared',
+               'rollback',
+               'sendemail',
+               'siteadmin',
+               'suppressionlog',
+               'suppressredirect',
+               'suppressrevision',
+               'unblockself',
+               'undelete',
+               'unwatchedpages',
+               'upload',
+               'upload_by_url',
+               'userrights',
+               'userrights-interwiki',
+               'viewmyprivateinfo',
+               'viewmywatchlist',
+               'viewsuppressed',
+               'writeapi',
+       ];
+
        /**
         * @param SpecialPageFactory $specialPageFactory
         * @param string[] $whitelistRead
         * @param string[] $whitelistReadRegexp
         * @param bool $emailConfirmToEdit
         * @param bool $blockDisablesLogin
+        * @param string[][] $groupPermissions
+        * @param string[][] $revokePermissions
+        * @param string[] $availableRights
         * @param NamespaceInfo $nsInfo
         */
        public function __construct(
@@ -83,6 +192,9 @@ class PermissionManager {
                $whitelistReadRegexp,
                $emailConfirmToEdit,
                $blockDisablesLogin,
+               $groupPermissions,
+               $revokePermissions,
+               $availableRights,
                NamespaceInfo $nsInfo
        ) {
                $this->specialPageFactory = $specialPageFactory;
@@ -90,6 +202,9 @@ class PermissionManager {
                $this->whitelistReadRegexp = $whitelistReadRegexp;
                $this->emailConfirmToEdit = $emailConfirmToEdit;
                $this->blockDisablesLogin = $blockDisablesLogin;
+               $this->groupPermissions = $groupPermissions;
+               $this->revokePermissions = $revokePermissions;
+               $this->availableRights = $availableRights;
                $this->nsInfo = $nsInfo;
        }
 
@@ -111,7 +226,6 @@ class PermissionManager {
         *   - RIGOR_SECURE : does cheap and expensive checks, using the master as needed
         *
         * @return bool
-        * @throws Exception
         */
        public function userCan( $action, User $user, LinkTarget $page, $rigor = self::RIGOR_SECURE ) {
                return !count( $this->getPermissionErrorsInternal( $action, $user, $page, $rigor, true ) );
@@ -133,7 +247,6 @@ class PermissionManager {
         *   whose corresponding errors may be ignored.
         *
         * @return array Array of arrays of the arguments to wfMessage to explain permissions problems.
-        * @throws Exception
         */
        public function getPermissionErrors(
                $action,
@@ -167,8 +280,6 @@ class PermissionManager {
         * @param bool $fromReplica Whether to check the replica DB instead of the master
         *
         * @return bool
-        * @throws FatalError
-        * @throws MWException
         */
        public function isBlockedFrom( User $user, LinkTarget $page, $fromReplica = false ) {
                $blocked = $user->isHidden();
@@ -286,8 +397,6 @@ class PermissionManager {
         * @param LinkTarget $page
         *
         * @return array List of errors
-        * @throws FatalError
-        * @throws MWException
         */
        private function checkPermissionHooks(
                $action,
@@ -363,8 +472,6 @@ class PermissionManager {
         * @param LinkTarget $page
         *
         * @return array List of errors
-        * @throws FatalError
-        * @throws MWException
         */
        private function checkReadPermissions(
                $action,
@@ -497,7 +604,6 @@ class PermissionManager {
         * @param LinkTarget $page
         *
         * @return array List of errors
-        * @throws MWException
         */
        private function checkUserBlock(
                $action,
@@ -583,8 +689,6 @@ class PermissionManager {
         * @param LinkTarget $page
         *
         * @return array List of errors
-        * @throws FatalError
-        * @throws MWException
         */
        private function checkQuickPermissions(
                $action,
@@ -762,6 +866,7 @@ class PermissionManager {
                                        }
                                        if ( $right != '' && !$user->isAllowedAll( 'protect', $right ) ) {
                                                $wikiPages = '';
+                                               /** @var Title $wikiPage */
                                                foreach ( $cascadingSources as $wikiPage ) {
                                                        $wikiPages .= '* [[:' . $wikiPage->getPrefixedText() . "]]\n";
                                                }
@@ -789,7 +894,6 @@ class PermissionManager {
         * @param LinkTarget $page
         *
         * @return array List of errors
-        * @throws Exception
         */
        private function checkActionPermissions(
                $action,
@@ -1052,4 +1156,256 @@ class PermissionManager {
                return $errors;
        }
 
+       /**
+        * Testing a permission
+        *
+        * @since 1.34
+        *
+        * @param UserIdentity $user
+        * @param string $action
+        *
+        * @return bool
+        */
+       public function userHasRight( UserIdentity $user, $action = '' ) {
+               if ( $action === '' ) {
+                       return true; // In the spirit of DWIM
+               }
+               // Use strict parameter to avoid matching numeric 0 accidentally inserted
+               // by misconfiguration: 0 == 'foo'
+               return in_array( $action, $this->getUserPermissions( $user ), true );
+       }
+
+       /**
+        * Get the permissions this user has.
+        *
+        * @since 1.34
+        *
+        * @param UserIdentity $user
+        *
+        * @return string[] permission names
+        */
+       public function getUserPermissions( UserIdentity $user ) {
+               $user = User::newFromIdentity( $user );
+               if ( !isset( $this->usersRights[ $user->getId() ] ) ) {
+                       $this->usersRights[ $user->getId() ] = $this->getGroupPermissions(
+                               $user->getEffectiveGroups()
+                       );
+                       Hooks::run( 'UserGetRights', [ $user, &$this->usersRights[ $user->getId() ] ] );
+
+                       // Deny any rights denied by the user's session, unless this
+                       // endpoint has no sessions.
+                       if ( !defined( 'MW_NO_SESSION' ) ) {
+                               // FIXME: $user->getRequest().. need to be replaced with something else
+                               $allowedRights = $user->getRequest()->getSession()->getAllowedUserRights();
+                               if ( $allowedRights !== null ) {
+                                       $this->usersRights[ $user->getId() ] = array_intersect(
+                                               $this->usersRights[ $user->getId() ],
+                                               $allowedRights
+                                       );
+                               }
+                       }
+
+                       Hooks::run( 'UserGetRightsRemove', [ $user, &$this->usersRights[ $user->getId() ] ] );
+                       // Force reindexation of rights when a hook has unset one of them
+                       $this->usersRights[ $user->getId() ] = array_values(
+                               array_unique( $this->usersRights[ $user->getId() ] )
+                       );
+
+                       if (
+                               $user->isLoggedIn() &&
+                               $this->blockDisablesLogin &&
+                               $user->getBlock()
+                       ) {
+                               $anon = new User;
+                               $this->usersRights[ $user->getId() ] = array_intersect(
+                                       $this->usersRights[ $user->getId() ],
+                                       $this->getUserPermissions( $anon )
+                               );
+                       }
+               }
+               return $this->usersRights[ $user->getId() ];
+       }
+
+       /**
+        * Clears users permissions cache, if specific user is provided it tries to clear
+        * permissions cache only for provided user.
+        *
+        * @since 1.34
+        *
+        * @param User|null $user
+        */
+       public function invalidateUsersRightsCache( $user = null ) {
+               if ( $user !== null ) {
+                       if ( isset( $this->usersRights[ $user->getId() ] ) ) {
+                               unset( $this->usersRights[$user->getId()] );
+                       }
+               } else {
+                       $this->usersRights = null;
+               }
+       }
+
+       /**
+        * Check, if the given group has the given permission
+        *
+        * If you're wanting to check whether all users have a permission, use
+        * PermissionManager::isEveryoneAllowed() instead. That properly checks if it's revoked
+        * from anyone.
+        *
+        * @since 1.34
+        *
+        * @param string $group Group to check
+        * @param string $role Role to check
+        *
+        * @return bool
+        */
+       public function groupHasPermission( $group, $role ) {
+               return isset( $this->groupPermissions[$group][$role] ) &&
+                          $this->groupPermissions[$group][$role] &&
+                          !( isset( $this->revokePermissions[$group][$role] ) &&
+                                 $this->revokePermissions[$group][$role] );
+       }
+
+       /**
+        * Get the permissions associated with a given list of groups
+        *
+        * @since 1.34
+        *
+        * @param array $groups Array of Strings List of internal group names
+        * @return array Array of Strings List of permission key names for given groups combined
+        */
+       public function getGroupPermissions( $groups ) {
+               $rights = [];
+               // grant every granted permission first
+               foreach ( $groups as $group ) {
+                       if ( isset( $this->groupPermissions[$group] ) ) {
+                               $rights = array_merge( $rights,
+                                       // array_filter removes empty items
+                                       array_keys( array_filter( $this->groupPermissions[$group] ) ) );
+                       }
+               }
+               // now revoke the revoked permissions
+               foreach ( $groups as $group ) {
+                       if ( isset( $this->revokePermissions[$group] ) ) {
+                               $rights = array_diff( $rights,
+                                       array_keys( array_filter( $this->revokePermissions[$group] ) ) );
+                       }
+               }
+               return array_unique( $rights );
+       }
+
+       /**
+        * Get all the groups who have a given permission
+        *
+        * @since 1.34
+        *
+        * @param string $role Role to check
+        * @return array Array of Strings List of internal group names with the given permission
+        */
+       public function getGroupsWithPermission( $role ) {
+               $allowedGroups = [];
+               foreach ( array_keys( $this->groupPermissions ) as $group ) {
+                       if ( $this->groupHasPermission( $group, $role ) ) {
+                               $allowedGroups[] = $group;
+                       }
+               }
+               return $allowedGroups;
+       }
+
+       /**
+        * Check if all users may be assumed to have the given permission
+        *
+        * We generally assume so if the right is granted to '*' and isn't revoked
+        * on any group. It doesn't attempt to take grants or other extension
+        * limitations on rights into account in the general case, though, as that
+        * would require it to always return false and defeat the purpose.
+        * Specifically, session-based rights restrictions (such as OAuth or bot
+        * passwords) are applied based on the current session.
+        *
+        * @param string $right Right to check
+        *
+        * @return bool
+        * @since 1.34
+        */
+       public function isEveryoneAllowed( $right ) {
+               // Use the cached results, except in unit tests which rely on
+               // being able change the permission mid-request
+               if ( isset( $this->cachedRights[$right] ) ) {
+                       return $this->cachedRights[$right];
+               }
+
+               if ( !isset( $this->groupPermissions['*'][$right] )
+                        || !$this->groupPermissions['*'][$right] ) {
+                       $this->cachedRights[$right] = false;
+                       return false;
+               }
+
+               // If it's revoked anywhere, then everyone doesn't have it
+               foreach ( $this->revokePermissions as $rights ) {
+                       if ( isset( $rights[$right] ) && $rights[$right] ) {
+                               $this->cachedRights[$right] = false;
+                               return false;
+                       }
+               }
+
+               // Remove any rights that aren't allowed to the global-session user,
+               // unless there are no sessions for this endpoint.
+               if ( !defined( 'MW_NO_SESSION' ) ) {
+
+                       // XXX: think what could be done with the below
+                       $allowedRights = SessionManager::getGlobalSession()->getAllowedUserRights();
+                       if ( $allowedRights !== null && !in_array( $right, $allowedRights, true ) ) {
+                               $this->cachedRights[$right] = false;
+                               return false;
+                       }
+               }
+
+               // Allow extensions to say false
+               if ( !Hooks::run( 'UserIsEveryoneAllowed', [ $right ] ) ) {
+                       $this->cachedRights[$right] = false;
+                       return false;
+               }
+
+               $this->cachedRights[$right] = true;
+               return true;
+       }
+
+       /**
+        * Get a list of all available permissions.
+        *
+        * @since 1.34
+        *
+        * @return string[] Array of permission names
+        */
+       public function getAllPermissions() {
+               if ( $this->allRights === false ) {
+                       if ( count( $this->availableRights ) ) {
+                               $this->allRights = array_unique( array_merge(
+                                       $this->coreRights,
+                                       $this->availableRights
+                               ) );
+                       } else {
+                               $this->allRights = $this->coreRights;
+                       }
+                       Hooks::run( 'UserGetAllRights', [ &$this->allRights ] );
+               }
+               return $this->allRights;
+       }
+
+       /**
+        * Overrides user permissions cache
+        *
+        * @since 1.34
+        *
+        * @param User $user
+        * @param string[]|string $rights
+        *
+        * @throws Exception
+        */
+       public function overrideUserRightsForTesting( $user, $rights = [] ) {
+               if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
+                       throw new Exception( __METHOD__ . ' can not be called outside of tests' );
+               }
+               $this->usersRights[ $user->getId() ] = is_array( $rights ) ? $rights : [ $rights ];
+       }
+
 }
index c5764d2..75c7435 100644 (file)
@@ -463,6 +463,9 @@ return [
                        $config->get( 'WhitelistReadRegexp' ),
                        $config->get( 'EmailConfirmToEdit' ),
                        $config->get( 'BlockDisablesLogin' ),
+                       $config->get( 'GroupPermissions' ),
+                       $config->get( 'RevokePermissions' ),
+                       $config->get( 'AvailableRights' ),
                        $services->getNamespaceInfo()
                );
        },
index e8ca7ce..f3a3e12 100644 (file)
@@ -109,94 +109,6 @@ class User implements IDBAccessObject, UserIdentity {
                'mActorId',
        ];
 
-       /**
-        * Array of Strings Core rights.
-        * Each of these should have a corresponding message of the form
-        * "right-$right".
-        * @showinitializer
-        */
-       protected static $mCoreRights = [
-               'apihighlimits',
-               'applychangetags',
-               'autoconfirmed',
-               'autocreateaccount',
-               'autopatrol',
-               'bigdelete',
-               'block',
-               'blockemail',
-               'bot',
-               'browsearchive',
-               'changetags',
-               'createaccount',
-               'createpage',
-               'createtalk',
-               'delete',
-               'deletechangetags',
-               'deletedhistory',
-               'deletedtext',
-               'deletelogentry',
-               'deleterevision',
-               'edit',
-               'editcontentmodel',
-               'editinterface',
-               'editprotected',
-               'editmyoptions',
-               'editmyprivateinfo',
-               'editmyusercss',
-               'editmyuserjson',
-               'editmyuserjs',
-               'editmywatchlist',
-               'editsemiprotected',
-               'editsitecss',
-               'editsitejson',
-               'editsitejs',
-               'editusercss',
-               'edituserjson',
-               'edituserjs',
-               'hideuser',
-               'import',
-               'importupload',
-               'ipblock-exempt',
-               'managechangetags',
-               'markbotedits',
-               'mergehistory',
-               'minoredit',
-               'move',
-               'movefile',
-               'move-categorypages',
-               'move-rootuserpages',
-               'move-subpages',
-               'nominornewtalk',
-               'noratelimit',
-               'override-export-depth',
-               'pagelang',
-               'patrol',
-               'patrolmarks',
-               'protect',
-               'purge',
-               'read',
-               'reupload',
-               'reupload-own',
-               'reupload-shared',
-               'rollback',
-               'sendemail',
-               'siteadmin',
-               'suppressionlog',
-               'suppressredirect',
-               'suppressrevision',
-               'unblockself',
-               'undelete',
-               'unwatchedpages',
-               'upload',
-               'upload_by_url',
-               'userrights',
-               'userrights-interwiki',
-               'viewmyprivateinfo',
-               'viewmywatchlist',
-               'viewsuppressed',
-               'writeapi',
-       ];
-
        /**
         * String Cached results of getAllRights()
         */
@@ -271,8 +183,6 @@ class User implements IDBAccessObject, UserIdentity {
        public $mBlockedby;
        /** @var string */
        protected $mHash;
-       /** @var array */
-       public $mRights;
        /** @var string */
        protected $mBlockreason;
        /** @var array */
@@ -329,6 +239,24 @@ class User implements IDBAccessObject, UserIdentity {
                return (string)$this->getName();
        }
 
+       public function __get( $name ) {
+               // A shortcut for $mRights deprecation phase
+               if ( $name === 'mRights' ) {
+                       return $this->getRights();
+               }
+       }
+
+       public function __set( $name, $value ) {
+               // A shortcut for $mRights deprecation phase, only known legitimate use was for
+               // testing purposes, other uses seem bad in principle
+               if ( $name === 'mRights' ) {
+                       MediaWikiServices::getInstance()->getPermissionManager()->overrideUserRightsForTesting(
+                               $this,
+                               is_null( $value ) ? [] : $value
+                       );
+               }
+       }
+
        /**
         * Test if it's safe to load this User object.
         *
@@ -1706,11 +1634,12 @@ class User implements IDBAccessObject, UserIdentity {
         *   given source. May be "name", "id", "actor", "defaults", "session", or false for no reload.
         */
        public function clearInstanceCache( $reloadFrom = false ) {
+               global $wgFullyInitialised;
+
                $this->mNewtalk = -1;
                $this->mDatePreference = null;
                $this->mBlockedby = -1; # Unset
                $this->mHash = false;
-               $this->mRights = null;
                $this->mEffectiveGroups = null;
                $this->mImplicitGroups = null;
                $this->mGroupMemberships = null;
@@ -1718,6 +1647,13 @@ class User implements IDBAccessObject, UserIdentity {
                $this->mOptionsLoaded = false;
                $this->mEditCount = null;
 
+               // Replacement of former `$this->mRights = null` line
+               if ( $wgFullyInitialised && $this->mFrom ) {
+                       MediaWikiServices::getInstance()->getPermissionManager()->invalidateUsersRightsCache(
+                               $this
+                       );
+               }
+
                if ( $reloadFrom ) {
                        $this->mLoadedItems = [];
                        $this->mFrom = $reloadFrom;
@@ -2157,7 +2093,6 @@ class User implements IDBAccessObject, UserIdentity {
         * @param Title $title Title to check
         * @param bool $fromReplica Whether to check the replica DB instead of the master
         * @return bool
-        * @throws MWException
         *
         * @deprecated since 1.33,
         * use MediaWikiServices::getInstance()->getPermissionManager()->isBlockedFrom(..)
@@ -3403,44 +3338,13 @@ class User implements IDBAccessObject, UserIdentity {
        /**
         * Get the permissions this user has.
         * @return string[] permission names
+        *
+        * @deprecated since 1.34, use MediaWikiServices::getInstance()->getPermissionManager()
+        * ->getUserPermissions(..) instead
+        *
         */
        public function getRights() {
-               if ( is_null( $this->mRights ) ) {
-                       $this->mRights = self::getGroupPermissions( $this->getEffectiveGroups() );
-                       Hooks::run( 'UserGetRights', [ $this, &$this->mRights ] );
-
-                       // Deny any rights denied by the user's session, unless this
-                       // endpoint has no sessions.
-                       if ( !defined( 'MW_NO_SESSION' ) ) {
-                               $allowedRights = $this->getRequest()->getSession()->getAllowedUserRights();
-                               if ( $allowedRights !== null ) {
-                                       $this->mRights = array_intersect( $this->mRights, $allowedRights );
-                               }
-                       }
-
-                       Hooks::run( 'UserGetRightsRemove', [ $this, &$this->mRights ] );
-                       // Force reindexation of rights when a hook has unset one of them
-                       $this->mRights = array_values( array_unique( $this->mRights ) );
-
-                       // If block disables login, we should also remove any
-                       // extra rights blocked users might have, in case the
-                       // blocked user has a pre-existing session (T129738).
-                       // This is checked here for cases where people only call
-                       // $user->isAllowed(). It is also checked in Title::checkUserBlock()
-                       // to give a better error message in the common case.
-                       $config = RequestContext::getMain()->getConfig();
-                       // @TODO Partial blocks should not prevent the user from logging in.
-                       //       see: https://phabricator.wikimedia.org/T208895
-                       if (
-                               $this->isLoggedIn() &&
-                               $config->get( 'BlockDisablesLogin' ) &&
-                               $this->getBlock()
-                       ) {
-                               $anon = new User;
-                               $this->mRights = array_intersect( $this->mRights, $anon->getRights() );
-                       }
-               }
-               return $this->mRights;
+               return MediaWikiServices::getInstance()->getPermissionManager()->getUserPermissions( $this );
        }
 
        /**
@@ -3609,8 +3513,7 @@ class User implements IDBAccessObject, UserIdentity {
                // Refresh the groups caches, and clear the rights cache so it will be
                // refreshed on the next call to $this->getRights().
                $this->getEffectiveGroups( true );
-               $this->mRights = null;
-
+               MediaWikiServices::getInstance()->getPermissionManager()->invalidateUsersRightsCache( $this );
                $this->invalidateCache();
 
                return true;
@@ -3641,8 +3544,7 @@ class User implements IDBAccessObject, UserIdentity {
                // Refresh the groups caches, and clear the rights cache so it will be
                // refreshed on the next call to $this->getRights().
                $this->getEffectiveGroups( true );
-               $this->mRights = null;
-
+               MediaWikiServices::getInstance()->getPermissionManager()->invalidateUsersRightsCache( $this );
                $this->invalidateCache();
 
                return true;
@@ -3725,16 +3627,17 @@ class User implements IDBAccessObject, UserIdentity {
 
        /**
         * Internal mechanics of testing a permission
+        *
+        * @deprecated since 1.34, use MediaWikiServices::getInstance()
+        * ->getPermissionManager()->userHasRight(...) instead
+        *
         * @param string $action
+        *
         * @return bool
         */
        public function isAllowed( $action = '' ) {
-               if ( $action === '' ) {
-                       return true; // In the spirit of DWIM
-               }
-               // Use strict parameter to avoid matching numeric 0 accidentally inserted
-               // by misconfiguration: 0 == 'foo'
-               return in_array( $action, $this->getRights(), true );
+               return MediaWikiServices::getInstance()->getPermissionManager()
+                       ->userHasRight( $this, $action );
        }
 
        /**
@@ -4883,45 +4786,27 @@ class User implements IDBAccessObject, UserIdentity {
        /**
         * Get the permissions associated with a given list of groups
         *
+        * @deprecated since 1.34, use MediaWikiServices::getInstance()->getPermissionManager()
+        *             ->getGroupPermissions() instead
+        *
         * @param array $groups Array of Strings List of internal group names
         * @return array Array of Strings List of permission key names for given groups combined
         */
        public static function getGroupPermissions( $groups ) {
-               global $wgGroupPermissions, $wgRevokePermissions;
-               $rights = [];
-               // grant every granted permission first
-               foreach ( $groups as $group ) {
-                       if ( isset( $wgGroupPermissions[$group] ) ) {
-                               $rights = array_merge( $rights,
-                                       // array_filter removes empty items
-                                       array_keys( array_filter( $wgGroupPermissions[$group] ) ) );
-                       }
-               }
-               // now revoke the revoked permissions
-               foreach ( $groups as $group ) {
-                       if ( isset( $wgRevokePermissions[$group] ) ) {
-                               $rights = array_diff( $rights,
-                                       array_keys( array_filter( $wgRevokePermissions[$group] ) ) );
-                       }
-               }
-               return array_unique( $rights );
+               return MediaWikiServices::getInstance()->getPermissionManager()->getGroupPermissions( $groups );
        }
 
        /**
         * Get all the groups who have a given permission
         *
+        * @deprecated since 1.34, use MediaWikiServices::getInstance()->getPermissionManager()
+        *             ->getGroupsWithPermission() instead
+        *
         * @param string $role Role to check
         * @return array Array of Strings List of internal group names with the given permission
         */
        public static function getGroupsWithPermission( $role ) {
-               global $wgGroupPermissions;
-               $allowedGroups = [];
-               foreach ( array_keys( $wgGroupPermissions ) as $group ) {
-                       if ( self::groupHasPermission( $group, $role ) ) {
-                               $allowedGroups[] = $group;
-                       }
-               }
-               return $allowedGroups;
+               return MediaWikiServices::getInstance()->getPermissionManager()->getGroupsWithPermission( $role );
        }
 
        /**
@@ -4931,15 +4816,17 @@ class User implements IDBAccessObject, UserIdentity {
         * User::isEveryoneAllowed() instead. That properly checks if it's revoked
         * from anyone.
         *
+        * @deprecated since 1.34, use MediaWikiServices::getInstance()->getPermissionManager()
+        * ->groupHasPermission(..) instead
+        *
         * @since 1.21
         * @param string $group Group to check
         * @param string $role Role to check
         * @return bool
         */
        public static function groupHasPermission( $group, $role ) {
-               global $wgGroupPermissions, $wgRevokePermissions;
-               return isset( $wgGroupPermissions[$group][$role] ) && $wgGroupPermissions[$group][$role]
-                       && !( isset( $wgRevokePermissions[$group][$role] ) && $wgRevokePermissions[$group][$role] );
+               return MediaWikiServices::getInstance()->getPermissionManager()
+                       ->groupHasPermission( $group, $role );
        }
 
        /**
@@ -4952,51 +4839,16 @@ class User implements IDBAccessObject, UserIdentity {
         * Specifically, session-based rights restrictions (such as OAuth or bot
         * passwords) are applied based on the current session.
         *
-        * @since 1.22
+        * @deprecated since 1.34, use MediaWikiServices::getInstance()->getPermissionManager()
+        *             ->isEveryoneAllowed() instead
+        *
         * @param string $right Right to check
+        *
         * @return bool
+        * @since 1.22
         */
        public static function isEveryoneAllowed( $right ) {
-               global $wgGroupPermissions, $wgRevokePermissions;
-               static $cache = [];
-
-               // Use the cached results, except in unit tests which rely on
-               // being able change the permission mid-request
-               if ( isset( $cache[$right] ) && !defined( 'MW_PHPUNIT_TEST' ) ) {
-                       return $cache[$right];
-               }
-
-               if ( !isset( $wgGroupPermissions['*'][$right] ) || !$wgGroupPermissions['*'][$right] ) {
-                       $cache[$right] = false;
-                       return false;
-               }
-
-               // If it's revoked anywhere, then everyone doesn't have it
-               foreach ( $wgRevokePermissions as $rights ) {
-                       if ( isset( $rights[$right] ) && $rights[$right] ) {
-                               $cache[$right] = false;
-                               return false;
-                       }
-               }
-
-               // Remove any rights that aren't allowed to the global-session user,
-               // unless there are no sessions for this endpoint.
-               if ( !defined( 'MW_NO_SESSION' ) ) {
-                       $allowedRights = SessionManager::getGlobalSession()->getAllowedUserRights();
-                       if ( $allowedRights !== null && !in_array( $right, $allowedRights, true ) ) {
-                               $cache[$right] = false;
-                               return false;
-                       }
-               }
-
-               // Allow extensions to say false
-               if ( !Hooks::run( 'UserIsEveryoneAllowed', [ $right ] ) ) {
-                       $cache[$right] = false;
-                       return false;
-               }
-
-               $cache[$right] = true;
-               return true;
+               return MediaWikiServices::getInstance()->getPermissionManager()->isEveryoneAllowed( $right );
        }
 
        /**
@@ -5015,19 +4867,14 @@ class User implements IDBAccessObject, UserIdentity {
 
        /**
         * Get a list of all available permissions.
+        *
+        * @deprecated since 1.34, use MediaWikiServices::getInstance()->getPermissionManager()
+        *             ->getAllPermissions() instead
+        *
         * @return string[] Array of permission names
         */
        public static function getAllRights() {
-               if ( self::$mAllRights === false ) {
-                       global $wgAvailableRights;
-                       if ( count( $wgAvailableRights ) ) {
-                               self::$mAllRights = array_unique( array_merge( self::$mCoreRights, $wgAvailableRights ) );
-                       } else {
-                               self::$mAllRights = self::$mCoreRights;
-                       }
-                       Hooks::run( 'UserGetAllRights', [ &self::$mAllRights ] );
-               }
-               return self::$mAllRights;
+               return MediaWikiServices::getInstance()->getPermissionManager()->getAllPermissions();
        }
 
        /**
index 486b16d..c84ac44 100644 (file)
@@ -1130,6 +1130,21 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                $this->setMwGlobals( 'wgGroupPermissions', $newPermissions );
        }
 
+       /**
+        * Overrides specific user permissions until services are reloaded
+        *
+        * @param User $user
+        * @param string[]|string $permissions
+        *
+        * @throws Exception
+        */
+       public function overrideUserPermissions( $user, $permissions = [] ) {
+               MediaWikiServices::getInstance()->getPermissionManager()->overrideUserRightsForTesting(
+                       $user,
+                       $permissions
+               );
+       }
+
        /**
         * Sets the logger for a specified channel, for the duration of the test.
         * @since 1.27
index 2ce50b7..138f8d0 100644 (file)
@@ -3,8 +3,12 @@
 namespace MediaWiki\Tests\Permissions;
 
 use Action;
+use FauxRequest;
+use MediaWiki\Session\SessionId;
+use MediaWiki\Session\TestUtils;
 use MediaWikiLangTestCase;
 use RequestContext;
+use stdClass;
 use Title;
 use User;
 use MediaWiki\Block\DatabaseBlock;
@@ -13,6 +17,7 @@ use MediaWiki\Block\Restriction\PageRestriction;
 use MediaWiki\Block\SystemBlock;
 use MediaWiki\MediaWikiServices;
 use MediaWiki\Permissions\PermissionManager;
+use Wikimedia\TestingAccessWrapper;
 
 /**
  * @group Database
@@ -56,7 +61,32 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                        'wgNamespaceProtection' => [
                                NS_MEDIAWIKI => 'editinterface',
                        ],
+                       'wgRevokePermissions' => [
+                               'formertesters' => [
+                                       'runtest' => true
+                               ]
+                       ],
+                       'wgAvailableRights' => [
+                               'test',
+                               'runtest',
+                               'writetest',
+                               'nukeworld',
+                               'modifytest',
+                               'editmyoptions'
+                       ]
                ] );
+
+               $this->setGroupPermissions( 'unittesters', 'test', true );
+               $this->setGroupPermissions( 'unittesters', 'runtest', true );
+               $this->setGroupPermissions( 'unittesters', 'writetest', false );
+               $this->setGroupPermissions( 'unittesters', 'nukeworld', false );
+
+               $this->setGroupPermissions( 'testwriters', 'test', true );
+               $this->setGroupPermissions( 'testwriters', 'writetest', true );
+               $this->setGroupPermissions( 'testwriters', 'modifytest', true );
+
+               $this->setGroupPermissions( '*', 'editmyoptions', true );
+
                // Without this testUserBlock will use a non-English context on non-English MediaWiki
                // installations (because of how Title::checkUserBlock is implemented) and fail.
                RequestContext::resetMain();
@@ -89,19 +119,12 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                        $this->user = $this->userUser;
                }
 
-               $this->permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
-
                $this->overrideMwServices();
        }
 
-       protected function setUserPerm( $perm ) {
-               // Setting member variables is evil!!!
-
-               if ( is_array( $perm ) ) {
-                       $this->user->mRights = $perm;
-               } else {
-                       $this->user->mRights = [ $perm ];
-               }
+       public function tearDown() {
+               parent::tearDown();
+               $this->restoreMwServices();
        }
 
        protected function setTitle( $ns, $title = "Main_Page" ) {
@@ -116,6 +139,7 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                } else {
                        $this->user = $this->altUser;
                }
+               $this->overrideMwServices();
        }
 
        /**
@@ -133,163 +157,165 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
 
                $this->setUser( 'anon' );
                $this->setTitle( NS_TALK );
-               $this->setUserPerm( "createtalk" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "createtalk" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'create', $this->user, $this->title );
                $this->assertEquals( [], $res );
 
                $this->setTitle( NS_TALK );
-               $this->setUserPerm( "createpage" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "createpage" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'create', $this->user, $this->title );
                $this->assertEquals( [ [ "nocreatetext" ] ], $res );
 
                $this->setTitle( NS_TALK );
-               $this->setUserPerm( "" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'create', $this->user, $this->title );
                $this->assertEquals( [ [ 'nocreatetext' ] ], $res );
 
                $this->setTitle( NS_MAIN );
-               $this->setUserPerm( "createpage" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "createpage" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'create', $this->user, $this->title );
                $this->assertEquals( [], $res );
 
                $this->setTitle( NS_MAIN );
-               $this->setUserPerm( "createtalk" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "createtalk" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'create', $this->user, $this->title );
                $this->assertEquals( [ [ 'nocreatetext' ] ], $res );
 
                $this->setUser( $this->userName );
                $this->setTitle( NS_TALK );
-               $this->setUserPerm( "createtalk" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "createtalk" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'create', $this->user, $this->title );
                $this->assertEquals( [], $res );
 
                $this->setTitle( NS_TALK );
-               $this->setUserPerm( "createpage" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "createpage" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'create', $this->user, $this->title );
                $this->assertEquals( [ [ 'nocreate-loggedin' ] ], $res );
 
                $this->setTitle( NS_TALK );
-               $this->setUserPerm( "" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'create', $this->user, $this->title );
                $this->assertEquals( [ [ 'nocreate-loggedin' ] ], $res );
 
                $this->setTitle( NS_MAIN );
-               $this->setUserPerm( "createpage" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "createpage" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'create', $this->user, $this->title );
                $this->assertEquals( [], $res );
 
                $this->setTitle( NS_MAIN );
-               $this->setUserPerm( "createtalk" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "createtalk" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'create', $this->user, $this->title );
                $this->assertEquals( [ [ 'nocreate-loggedin' ] ], $res );
 
                $this->setTitle( NS_MAIN );
-               $this->setUserPerm( "" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'create', $this->user, $this->title );
                $this->assertEquals( [ [ 'nocreate-loggedin' ] ], $res );
 
                $this->setUser( 'anon' );
                $this->setTitle( NS_USER, $this->userName . '' );
-               $this->setUserPerm( "" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'move', $this->user, $this->title );
                $this->assertEquals( [ [ 'cant-move-user-page' ], [ 'movenologintext' ] ], $res );
 
                $this->setTitle( NS_USER, $this->userName . '/subpage' );
-               $this->setUserPerm( "" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'move', $this->user, $this->title );
                $this->assertEquals( [ [ 'movenologintext' ] ], $res );
 
                $this->setTitle( NS_USER, $this->userName . '' );
-               $this->setUserPerm( "move-rootuserpages" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "move-rootuserpages" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'move', $this->user, $this->title );
                $this->assertEquals( [ [ 'movenologintext' ] ], $res );
 
                $this->setTitle( NS_USER, $this->userName . '/subpage' );
-               $this->setUserPerm( "move-rootuserpages" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "move-rootuserpages" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'move', $this->user, $this->title );
                $this->assertEquals( [ [ 'movenologintext' ] ], $res );
 
                $this->setTitle( NS_USER, $this->userName . '' );
-               $this->setUserPerm( "" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'move', $this->user, $this->title );
                $this->assertEquals( [ [ 'cant-move-user-page' ], [ 'movenologintext' ] ], $res );
 
                $this->setTitle( NS_USER, $this->userName . '/subpage' );
-               $this->setUserPerm( "" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'move', $this->user, $this->title );
                $this->assertEquals( [ [ 'movenologintext' ] ], $res );
 
                $this->setTitle( NS_USER, $this->userName . '' );
-               $this->setUserPerm( "move-rootuserpages" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "move-rootuserpages" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'move', $this->user, $this->title );
                $this->assertEquals( [ [ 'movenologintext' ] ], $res );
 
                $this->setTitle( NS_USER, $this->userName . '/subpage' );
-               $this->setUserPerm( "move-rootuserpages" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "move-rootuserpages" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'move', $this->user, $this->title );
                $this->assertEquals( [ [ 'movenologintext' ] ], $res );
 
                $this->setUser( $this->userName );
                $this->setTitle( NS_FILE, "img.png" );
-               $this->setUserPerm( "" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'move', $this->user, $this->title );
                $this->assertEquals( [ [ 'movenotallowedfile' ], [ 'movenotallowed' ] ], $res );
 
                $this->setTitle( NS_FILE, "img.png" );
-               $this->setUserPerm( "movefile" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "movefile" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'move', $this->user, $this->title );
                $this->assertEquals( [ [ 'movenotallowed' ] ], $res );
 
                $this->setUser( 'anon' );
                $this->setTitle( NS_FILE, "img.png" );
-               $this->setUserPerm( "" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'move', $this->user, $this->title );
                $this->assertEquals( [ [ 'movenotallowedfile' ], [ 'movenologintext' ] ], $res );
 
                $this->setTitle( NS_FILE, "img.png" );
-               $this->setUserPerm( "movefile" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "movefile" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'move', $this->user, $this->title );
                $this->assertEquals( [ [ 'movenologintext' ] ], $res );
 
                $this->setUser( $this->userName );
-               $this->setUserPerm( "move" );
-               $this->runGroupPermissions( 'move', [ [ 'movenotallowedfile' ] ] );
+               // $this->setUserPerm( "move" );
+               $this->runGroupPermissions( 'move', 'move', [ [ 'movenotallowedfile' ] ] );
 
-               $this->setUserPerm( "" );
+               // $this->setUserPerm( "" );
                $this->runGroupPermissions(
+                       '',
                        'move',
                        [ [ 'movenotallowedfile' ], [ 'movenotallowed' ] ]
                );
 
                $this->setUser( 'anon' );
-               $this->setUserPerm( "move" );
-               $this->runGroupPermissions( 'move', [ [ 'movenotallowedfile' ] ] );
+               //$this->setUserPerm( "move" );
+               $this->runGroupPermissions( 'move', 'move', [ [ 'movenotallowedfile' ] ] );
 
-               $this->setUserPerm( "" );
+               // $this->setUserPerm( "" );
                $this->runGroupPermissions(
+                       '',
                        'move',
                        [ [ 'movenotallowedfile' ], [ 'movenotallowed' ] ],
                        [ [ 'movenotallowedfile' ], [ 'movenologintext' ] ]
@@ -301,58 +327,58 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
 
                        $this->setTitle( NS_MAIN );
                        $this->setUser( 'anon' );
-                       $this->setUserPerm( "move" );
-                       $this->runGroupPermissions( 'move', [] );
+                       // $this->setUserPerm( "move" );
+                       $this->runGroupPermissions( 'move', 'move', [] );
 
-                       $this->setUserPerm( "" );
-                       $this->runGroupPermissions( 'move', [ [ 'movenotallowed' ] ],
+                       // $this->setUserPerm( "" );
+                       $this->runGroupPermissions( '', 'move', [ [ 'movenotallowed' ] ],
                                [ [ 'movenologintext' ] ] );
 
                        $this->setUser( $this->userName );
-                       $this->setUserPerm( "" );
-                       $this->runGroupPermissions( 'move', [ [ 'movenotallowed' ] ] );
+                       // $this->setUserPerm( "" );
+                       $this->runGroupPermissions( '', 'move', [ [ 'movenotallowed' ] ] );
 
-                       $this->setUserPerm( "move" );
-                       $this->runGroupPermissions( 'move', [] );
+                       //$this->setUserPerm( "move" );
+                       $this->runGroupPermissions( 'move', 'move', [] );
 
                        $this->setUser( 'anon' );
-                       $this->setUserPerm( 'move' );
-                       $res = $this->permissionManager
+                       $this->overrideUserPermissions( $this->user, 'move' );
+                       $res = MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'move-target', $this->user, $this->title );
                        $this->assertEquals( [], $res );
 
-                       $this->setUserPerm( '' );
-                       $res = $this->permissionManager
+                       $this->overrideUserPermissions( $this->user, '' );
+                       $res = MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'move-target', $this->user, $this->title );
                        $this->assertEquals( [ [ 'movenotallowed' ] ], $res );
                }
 
                $this->setTitle( NS_USER );
                $this->setUser( $this->userName );
-               $this->setUserPerm( [ "move", "move-rootuserpages" ] );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, [ "move", "move-rootuserpages" ] );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'move-target', $this->user, $this->title );
                $this->assertEquals( [], $res );
 
-               $this->setUserPerm( "move" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "move" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'move-target', $this->user, $this->title );
                $this->assertEquals( [ [ 'cant-move-to-user-page' ] ], $res );
 
                $this->setUser( 'anon' );
-               $this->setUserPerm( [ "move", "move-rootuserpages" ] );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, [ "move", "move-rootuserpages" ] );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'move-target', $this->user, $this->title );
                $this->assertEquals( [], $res );
 
                $this->setTitle( NS_USER, "User/subpage" );
-               $this->setUserPerm( [ "move", "move-rootuserpages" ] );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, [ "move", "move-rootuserpages" ] );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'move-target', $this->user, $this->title );
                $this->assertEquals( [], $res );
 
-               $this->setUserPerm( "move" );
-               $res = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, "move" );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'move-target', $this->user, $this->title );
                $this->assertEquals( [], $res );
 
@@ -378,54 +404,58 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                ];
 
                foreach ( [ "edit", "protect", "" ] as $action ) {
-                       $this->setUserPerm( null );
+                       $this->overrideUserPermissions( $this->user );
                        $this->assertEquals( $check[$action][0],
-                               $this->permissionManager
+                               MediaWikiServices::getInstance()->getPermissionManager()
                                        ->getPermissionErrors( $action, $this->user, $this->title, true ) );
                        $this->assertEquals( $check[$action][0],
-                               $this->permissionManager
+                               MediaWikiServices::getInstance()->getPermissionManager()
                                        ->getPermissionErrors( $action, $this->user, $this->title, 'full' ) );
                        $this->assertEquals( $check[$action][0],
-                               $this->permissionManager
+                               MediaWikiServices::getInstance()->getPermissionManager()
                                        ->getPermissionErrors( $action, $this->user, $this->title, 'secure' ) );
 
                        global $wgGroupPermissions;
                        $old = $wgGroupPermissions;
                        $wgGroupPermissions = [];
+                       $this->overrideMwServices();
 
                        $this->assertEquals( $check[$action][1],
-                               $this->permissionManager
+                               MediaWikiServices::getInstance()->getPermissionManager()
                                        ->getPermissionErrors( $action, $this->user, $this->title, true ) );
                        $this->assertEquals( $check[$action][1],
-                               $this->permissionManager
+                               MediaWikiServices::getInstance()->getPermissionManager()
                                        ->getPermissionErrors( $action, $this->user, $this->title, 'full' ) );
                        $this->assertEquals( $check[$action][1],
-                               $this->permissionManager
+                               MediaWikiServices::getInstance()->getPermissionManager()
                                        ->getPermissionErrors( $action, $this->user, $this->title, 'secure' ) );
                        $wgGroupPermissions = $old;
+                       $this->overrideMwServices();
 
-                       $this->setUserPerm( $action );
+                       $this->overrideUserPermissions( $this->user, $action );
                        $this->assertEquals( $check[$action][2],
-                               $this->permissionManager
+                               MediaWikiServices::getInstance()->getPermissionManager()
                                        ->getPermissionErrors( $action, $this->user, $this->title, true ) );
                        $this->assertEquals( $check[$action][2],
-                               $this->permissionManager
+                               MediaWikiServices::getInstance()->getPermissionManager()
                                        ->getPermissionErrors( $action, $this->user, $this->title, 'full' ) );
                        $this->assertEquals( $check[$action][2],
-                               $this->permissionManager
+                               MediaWikiServices::getInstance()->getPermissionManager()
                                        ->getPermissionErrors( $action, $this->user, $this->title, 'secure' ) );
 
-                       $this->setUserPerm( $action );
+                       $this->overrideUserPermissions( $this->user, $action );
                        $this->assertEquals( $check[$action][3],
-                               $this->permissionManager->userCan( $action, $this->user, $this->title, true ) );
+                               MediaWikiServices::getInstance()->getPermissionManager()
+                                       ->userCan( $action, $this->user, $this->title, true ) );
                        $this->assertEquals( $check[$action][3],
-                               $this->permissionManager->userCan( $action, $this->user, $this->title,
+                               MediaWikiServices::getInstance()->getPermissionManager()
+                                       ->userCan( $action, $this->user, $this->title,
                                        PermissionManager::RIGOR_QUICK ) );
                        # count( User::getGroupsWithPermissions( $action ) ) < 1
                }
        }
 
-       protected function runGroupPermissions( $action, $result, $result2 = null ) {
+       protected function runGroupPermissions( $perm, $action, $result, $result2 = null ) {
                global $wgGroupPermissions;
 
                if ( $result2 === null ) {
@@ -434,25 +464,33 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
 
                $wgGroupPermissions['autoconfirmed']['move'] = false;
                $wgGroupPermissions['user']['move'] = false;
-               $res = $this->permissionManager
+               $this->overrideMwServices();
+               $this->overrideUserPermissions( $this->user, $perm );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( $action, $this->user, $this->title );
                $this->assertEquals( $result, $res );
 
                $wgGroupPermissions['autoconfirmed']['move'] = true;
                $wgGroupPermissions['user']['move'] = false;
-               $res = $this->permissionManager
+               $this->overrideMwServices();
+               $this->overrideUserPermissions( $this->user, $perm );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( $action, $this->user, $this->title );
                $this->assertEquals( $result2, $res );
 
                $wgGroupPermissions['autoconfirmed']['move'] = true;
                $wgGroupPermissions['user']['move'] = true;
-               $res = $this->permissionManager
+               $this->overrideMwServices();
+               $this->overrideUserPermissions( $this->user, $perm );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( $action, $this->user, $this->title );
                $this->assertEquals( $result2, $res );
 
                $wgGroupPermissions['autoconfirmed']['move'] = false;
                $wgGroupPermissions['user']['move'] = true;
-               $res = $this->permissionManager
+               $this->overrideMwServices();
+               $this->overrideUserPermissions( $this->user, $perm );
+               $res = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( $action, $this->user, $this->title );
                $this->assertEquals( $result2, $res );
        }
@@ -469,57 +507,59 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                $this->setTitle( NS_SPECIAL );
 
                $this->assertEquals( [ [ 'badaccess-group0' ], [ 'ns-specialprotected' ] ],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
 
                $this->setTitle( NS_MAIN );
-               $this->setUserPerm( 'bogus' );
+               $this->overrideUserPermissions( $this->user, 'bogus' );
                $this->assertEquals( [],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
 
                $this->setTitle( NS_MAIN );
-               $this->setUserPerm( '' );
+               $this->overrideUserPermissions( $this->user, '' );
                $this->assertEquals( [ [ 'badaccess-group0' ] ],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
 
                $wgNamespaceProtection[NS_USER] = [ 'bogus' ];
 
                $this->setTitle( NS_USER );
-               $this->setUserPerm( '' );
+               $this->overrideUserPermissions( $this->user, '' );
                $this->assertEquals( [ [ 'badaccess-group0' ],
                        [ 'namespaceprotected', 'User', 'bogus' ] ],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
 
                $this->setTitle( NS_MEDIAWIKI );
-               $this->setUserPerm( 'bogus' );
+               $this->overrideUserPermissions( $this->user, 'bogus' );
                $this->assertEquals( [ [ 'protectedinterface', 'bogus' ] ],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
 
                $this->setTitle( NS_MEDIAWIKI );
-               $this->setUserPerm( 'bogus' );
+               $this->overrideUserPermissions( $this->user, 'bogus' );
                $this->assertEquals( [ [ 'protectedinterface', 'bogus' ] ],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
 
                $wgNamespaceProtection = null;
 
-               $this->setUserPerm( 'bogus' );
+               $this->overrideUserPermissions( $this->user, 'bogus' );
                $this->assertEquals( [],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
                $this->assertEquals( true,
-                       $this->permissionManager->userCan( 'bogus', $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()
+                               ->userCan( 'bogus', $this->user, $this->title ) );
 
-               $this->setUserPerm( '' );
+               $this->overrideUserPermissions( $this->user, '' );
                $this->assertEquals( [ [ 'badaccess-group0' ] ],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
                $this->assertEquals( false,
-                       $this->permissionManager->userCan( 'bogus', $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()
+                               ->userCan( 'bogus', $this->user, $this->title ) );
        }
 
        /**
@@ -716,48 +756,48 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                $resultUserJs,
                $resultPatrol
        ) {
-               $this->setUserPerm( '' );
-               $result = $this->permissionManager
+               $this->overrideUserPermissions( $this->user );
+               $result = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'bogus', $this->user, $this->title );
                $this->assertEquals( $resultNone, $result );
 
-               $this->setUserPerm( 'editmyusercss' );
-               $result = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, 'editmyusercss' );
+               $result = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'bogus', $this->user, $this->title );
                $this->assertEquals( $resultMyCss, $result );
 
-               $this->setUserPerm( 'editmyuserjson' );
-               $result = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, 'editmyuserjson' );
+               $result = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'bogus', $this->user, $this->title );
                $this->assertEquals( $resultMyJson, $result );
 
-               $this->setUserPerm( 'editmyuserjs' );
-               $result = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, 'editmyuserjs' );
+               $result = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'bogus', $this->user, $this->title );
                $this->assertEquals( $resultMyJs, $result );
 
-               $this->setUserPerm( 'editusercss' );
-               $result = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, 'editusercss' );
+               $result = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'bogus', $this->user, $this->title );
                $this->assertEquals( $resultUserCss, $result );
 
-               $this->setUserPerm( 'edituserjson' );
-               $result = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, 'edituserjson' );
+               $result = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'bogus', $this->user, $this->title );
                $this->assertEquals( $resultUserJson, $result );
 
-               $this->setUserPerm( 'edituserjs' );
-               $result = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, 'edituserjs' );
+               $result = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'bogus', $this->user, $this->title );
                $this->assertEquals( $resultUserJs, $result );
 
-               $this->setUserPerm( '' );
-               $result = $this->permissionManager
+               $this->overrideUserPermissions( $this->user );
+               $result = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'patrol', $this->user, $this->title );
                $this->assertEquals( reset( $resultPatrol[0] ), reset( $result[0] ) );
 
-               $this->setUserPerm( [ 'edituserjs', 'edituserjson', 'editusercss' ] );
-               $result = $this->permissionManager
+               $this->overrideUserPermissions( $this->user, [ 'edituserjs', 'edituserjson', 'editusercss' ] );
+               $result = MediaWikiServices::getInstance()->getPermissionManager()
                        ->getPermissionErrors( 'bogus', $this->user, $this->title );
                $this->assertEquals( [ [ 'badaccess-group0' ] ], $result );
        }
@@ -777,16 +817,16 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
 
                $this->setTitle( NS_MAIN );
                $this->title->mRestrictionsLoaded = true;
-               $this->setUserPerm( "edit" );
+               $this->overrideUserPermissions( $this->user, "edit" );
                $this->title->mRestrictions = [ "bogus" => [ 'bogus', "sysop", "protect", "" ] ];
 
                $this->assertEquals( [],
-                       $this->permissionManager->getPermissionErrors( 'edit',
-                               $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()
+                               ->getPermissionErrors( 'edit', $this->user, $this->title ) );
 
                $this->assertEquals( true,
-                       $this->permissionManager->userCan( 'edit', $this->user, $this->title,
-                               PermissionManager::RIGOR_QUICK ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()
+                               ->userCan( 'edit', $this->user, $this->title, PermissionManager::RIGOR_QUICK ) );
 
                $this->title->mRestrictions = [ "edit" => [ 'bogus', "sysop", "protect", "" ],
                        "bogus" => [ 'bogus', "sysop", "protect", "" ] ];
@@ -795,81 +835,81 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                        [ 'protectedpagetext', 'bogus', 'bogus' ],
                        [ 'protectedpagetext', 'editprotected', 'bogus' ],
                        [ 'protectedpagetext', 'protect', 'bogus' ] ],
-                       $this->permissionManager->getPermissionErrors( 'bogus',
-                               $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
+                               'bogus', $this->user, $this->title ) );
                $this->assertEquals( [ [ 'protectedpagetext', 'bogus', 'edit' ],
                        [ 'protectedpagetext', 'editprotected', 'edit' ],
                        [ 'protectedpagetext', 'protect', 'edit' ] ],
-                       $this->permissionManager->getPermissionErrors( 'edit',
-                               $this->user, $this->title ) );
-               $this->setUserPerm( "" );
+                       MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
+                               'edit', $this->user, $this->title ) );
+               $this->overrideUserPermissions( $this->user );
                $this->assertEquals( [ [ 'badaccess-group0' ],
                        [ 'protectedpagetext', 'bogus', 'bogus' ],
                        [ 'protectedpagetext', 'editprotected', 'bogus' ],
                        [ 'protectedpagetext', 'protect', 'bogus' ] ],
-                       $this->permissionManager->getPermissionErrors( 'bogus',
-                               $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
+                               'bogus', $this->user, $this->title ) );
                $this->assertEquals( [ [ 'badaccess-groups', "*, [[$prefix:Users|Users]]", 2 ],
                        [ 'protectedpagetext', 'bogus', 'edit' ],
                        [ 'protectedpagetext', 'editprotected', 'edit' ],
                        [ 'protectedpagetext', 'protect', 'edit' ] ],
-                       $this->permissionManager->getPermissionErrors( 'edit',
-                               $this->user, $this->title ) );
-               $this->setUserPerm( [ "edit", "editprotected" ] );
+                       MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
+                               'edit', $this->user, $this->title ) );
+               $this->overrideUserPermissions( $this->user, [ "edit", "editprotected" ] );
                $this->assertEquals( [ [ 'badaccess-group0' ],
                        [ 'protectedpagetext', 'bogus', 'bogus' ],
                        [ 'protectedpagetext', 'protect', 'bogus' ] ],
-                       $this->permissionManager->getPermissionErrors( 'bogus',
-                               $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
+                               'bogus', $this->user, $this->title ) );
                $this->assertEquals( [
                        [ 'protectedpagetext', 'bogus', 'edit' ],
                        [ 'protectedpagetext', 'protect', 'edit' ] ],
-                       $this->permissionManager->getPermissionErrors( 'edit',
-                               $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
+                               'edit', $this->user, $this->title ) );
 
                $this->title->mCascadeRestriction = true;
-               $this->setUserPerm( "edit" );
+               $this->overrideUserPermissions( $this->user, "edit" );
 
                $this->assertEquals( false,
-                       $this->permissionManager->userCan( 'bogus', $this->user, $this->title,
-                               PermissionManager::RIGOR_QUICK ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()
+                               ->userCan( 'bogus', $this->user, $this->title, PermissionManager::RIGOR_QUICK ) );
 
                $this->assertEquals( false,
-                       $this->permissionManager->userCan( 'edit', $this->user, $this->title,
-                               PermissionManager::RIGOR_QUICK ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->userCan(
+                               'edit', $this->user, $this->title, PermissionManager::RIGOR_QUICK ) );
 
                $this->assertEquals( [ [ 'badaccess-group0' ],
                        [ 'protectedpagetext', 'bogus', 'bogus' ],
                        [ 'protectedpagetext', 'editprotected', 'bogus' ],
                        [ 'protectedpagetext', 'protect', 'bogus' ] ],
-                       $this->permissionManager->getPermissionErrors( 'bogus',
-                               $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
+                               'bogus', $this->user, $this->title ) );
                $this->assertEquals( [ [ 'protectedpagetext', 'bogus', 'edit' ],
                        [ 'protectedpagetext', 'editprotected', 'edit' ],
                        [ 'protectedpagetext', 'protect', 'edit' ] ],
-                       $this->permissionManager->getPermissionErrors( 'edit',
-                               $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
+                               'edit', $this->user, $this->title ) );
 
-               $this->setUserPerm( [ "edit", "editprotected" ] );
+               $this->overrideUserPermissions( $this->user, [ "edit", "editprotected" ] );
                $this->assertEquals( false,
-                       $this->permissionManager->userCan( 'bogus', $this->user, $this->title,
-                               PermissionManager::RIGOR_QUICK ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->userCan(
+                               'bogus', $this->user, $this->title, PermissionManager::RIGOR_QUICK ) );
 
                $this->assertEquals( false,
-                       $this->permissionManager->userCan( 'edit', $this->user, $this->title,
-                               PermissionManager::RIGOR_QUICK ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->userCan(
+                               'edit', $this->user, $this->title, PermissionManager::RIGOR_QUICK ) );
 
                $this->assertEquals( [ [ 'badaccess-group0' ],
                        [ 'protectedpagetext', 'bogus', 'bogus' ],
                        [ 'protectedpagetext', 'protect', 'bogus' ],
                        [ 'protectedpagetext', 'protect', 'bogus' ] ],
-                       $this->permissionManager->getPermissionErrors( 'bogus',
-                               $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
+                               'bogus', $this->user, $this->title ) );
                $this->assertEquals( [ [ 'protectedpagetext', 'bogus', 'edit' ],
                        [ 'protectedpagetext', 'protect', 'edit' ],
                        [ 'protectedpagetext', 'protect', 'edit' ] ],
-                       $this->permissionManager->getPermissionErrors( 'edit',
-                               $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
+                               'edit', $this->user, $this->title ) );
        }
 
        /**
@@ -877,7 +917,7 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
         */
        public function testCascadingSourcesRestrictions() {
                $this->setTitle( NS_MAIN, "test page" );
-               $this->setUserPerm( [ "edit", "bogus" ] );
+               $this->overrideUserPermissions( $this->user, [ "edit", "bogus" ] );
 
                $this->title->mCascadeSources = [
                        Title::makeTitle( NS_MAIN, "Bogus" ),
@@ -888,17 +928,21 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                ];
 
                $this->assertEquals( false,
-                       $this->permissionManager->userCan( 'bogus', $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->userCan(
+                               'bogus', $this->user, $this->title ) );
                $this->assertEquals( [
                        [ "cascadeprotected", 2, "* [[:Bogus]]\n* [[:UnBogus]]\n", 'bogus' ],
                        [ "cascadeprotected", 2, "* [[:Bogus]]\n* [[:UnBogus]]\n", 'bogus' ],
                        [ "cascadeprotected", 2, "* [[:Bogus]]\n* [[:UnBogus]]\n", 'bogus' ] ],
-                       $this->permissionManager->getPermissionErrors( 'bogus', $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
+                               'bogus', $this->user, $this->title ) );
 
                $this->assertEquals( true,
-                       $this->permissionManager->userCan( 'edit', $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->userCan(
+                               'edit', $this->user, $this->title ) );
                $this->assertEquals( [],
-                       $this->permissionManager->getPermissionErrors( 'edit', $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
+                               'edit', $this->user, $this->title ) );
        }
 
        /**
@@ -907,7 +951,7 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
         * @covers \MediaWiki\Permissions\PermissionManager::checkActionPermissions
         */
        public function testActionPermissions() {
-               $this->setUserPerm( [ "createpage" ] );
+               $this->overrideUserPermissions( $this->user, [ "createpage" ] );
                $this->setTitle( NS_MAIN, "test page" );
                $this->title->mTitleProtection['permission'] = '';
                $this->title->mTitleProtection['user'] = $this->user->getId();
@@ -916,75 +960,85 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                $this->title->mCascadeRestriction = false;
 
                $this->assertEquals( [ [ 'titleprotected', 'Useruser', 'test' ] ],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'create', $this->user, $this->title ) );
                $this->assertEquals( false,
-                       $this->permissionManager->userCan( 'create', $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->userCan(
+                               'create', $this->user, $this->title ) );
 
                $this->title->mTitleProtection['permission'] = 'editprotected';
-               $this->setUserPerm( [ 'createpage', 'protect' ] );
+               $this->overrideUserPermissions( $this->user, [ 'createpage', 'protect' ] );
                $this->assertEquals( [ [ 'titleprotected', 'Useruser', 'test' ] ],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'create', $this->user, $this->title ) );
                $this->assertEquals( false,
-                       $this->permissionManager->userCan( 'create', $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->userCan(
+                               'create', $this->user, $this->title ) );
 
-               $this->setUserPerm( [ 'createpage', 'editprotected' ] );
+               $this->overrideUserPermissions( $this->user, [ 'createpage', 'editprotected' ] );
                $this->assertEquals( [],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'create', $this->user, $this->title ) );
                $this->assertEquals( true,
-                       $this->permissionManager->userCan( 'create', $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->userCan(
+                               'create', $this->user, $this->title ) );
 
-               $this->setUserPerm( [ 'createpage' ] );
+               $this->overrideUserPermissions( $this->user, [ 'createpage' ] );
                $this->assertEquals( [ [ 'titleprotected', 'Useruser', 'test' ] ],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'create', $this->user, $this->title ) );
                $this->assertEquals( false,
-                       $this->permissionManager->userCan( 'create', $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->userCan(
+                               'create', $this->user, $this->title ) );
 
                $this->setTitle( NS_MEDIA, "test page" );
-               $this->setUserPerm( [ "move" ] );
+               $this->overrideUserPermissions( $this->user, [ "move" ] );
                $this->assertEquals( false,
-                       $this->permissionManager->userCan( 'move', $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->userCan(
+                               'move', $this->user, $this->title ) );
                $this->assertEquals( [ [ 'immobile-source-namespace', 'Media' ] ],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'move', $this->user, $this->title ) );
 
                $this->setTitle( NS_HELP, "test page" );
                $this->assertEquals( [],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'move', $this->user, $this->title ) );
                $this->assertEquals( true,
-                       $this->permissionManager->userCan( 'move', $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->userCan(
+                               'move', $this->user, $this->title ) );
 
                $this->title->mInterwiki = "no";
                $this->assertEquals( [ [ 'immobile-source-page' ] ],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'move', $this->user, $this->title ) );
                $this->assertEquals( false,
-                       $this->permissionManager->userCan( 'move', $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->userCan(
+                               'move', $this->user, $this->title ) );
 
                $this->setTitle( NS_MEDIA, "test page" );
                $this->assertEquals( false,
-                       $this->permissionManager->userCan( 'move-target', $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->userCan(
+                               'move-target', $this->user, $this->title ) );
                $this->assertEquals( [ [ 'immobile-target-namespace', 'Media' ] ],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
 
                $this->setTitle( NS_HELP, "test page" );
                $this->assertEquals( [],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
                $this->assertEquals( true,
-                       $this->permissionManager->userCan( 'move-target', $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->userCan(
+                               'move-target', $this->user, $this->title ) );
 
                $this->title->mInterwiki = "no";
                $this->assertEquals( [ [ 'immobile-target-page' ] ],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
                $this->assertEquals( false,
-                       $this->permissionManager->userCan( 'move-target', $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->userCan(
+                               'move-target', $this->user, $this->title ) );
        }
 
        /**
@@ -997,10 +1051,7 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                        'wgBlockDisablesLogin' => false,
                ] );
 
-               $this->overrideMwServices();
-               $this->permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
-
-               $this->setUserPerm( [
+               $this->overrideUserPermissions( $this->user, [
                        'createpage',
                        'edit',
                        'move',
@@ -1013,24 +1064,32 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
 
                # $wgEmailConfirmToEdit only applies to 'edit' action
                $this->assertEquals( [],
-                       $this->permissionManager->getPermissionErrors( 'move-target',
-                               $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
+                               'move-target', $this->user, $this->title ) );
                $this->assertContains( [ 'confirmedittext' ],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'edit', $this->user, $this->title ) );
 
                $this->setMwGlobals( 'wgEmailConfirmToEdit', false );
                $this->overrideMwServices();
-               $this->permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+               $this->overrideUserPermissions( $this->user, [
+                       'createpage',
+                       'edit',
+                       'move',
+                       'rollback',
+                       'patrol',
+                       'upload',
+                       'purge'
+               ] );
 
                $this->assertNotContains( [ 'confirmedittext' ],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'edit', $this->user, $this->title ) );
 
                # $wgEmailConfirmToEdit && !$user->isEmailConfirmed() && $action != 'createaccount'
                $this->assertEquals( [],
-                       $this->permissionManager->getPermissionErrors( 'move-target',
-                               $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
+                               'move-target', $this->user, $this->title ) );
 
                global $wgLang;
                $prev = time();
@@ -1049,13 +1108,13 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                        '[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1',
                        'Useruser', null, 'infinite', '127.0.8.1',
                        $wgLang->timeanddate( wfTimestamp( TS_MW, $prev ), true ) ] ],
-                       $this->permissionManager->getPermissionErrors( 'move-target',
-                               $this->user, $this->title ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
+                               'move-target', $this->user, $this->title ) );
 
-               $this->assertEquals( false, $this->permissionManager
+               $this->assertEquals( false, MediaWikiServices::getInstance()->getPermissionManager()
                        ->userCan( 'move-target', $this->user, $this->title ) );
                // quickUserCan should ignore user blocks
-               $this->assertEquals( true, $this->permissionManager
+               $this->assertEquals( true, MediaWikiServices::getInstance()->getPermissionManager()
                        ->userCan( 'move-target', $this->user, $this->title,
                                PermissionManager::RIGOR_QUICK ) );
 
@@ -1074,7 +1133,7 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                        '[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1',
                        'Useruser', null, '23:00, 31 December 1969', '127.0.8.1',
                        $wgLang->timeanddate( wfTimestamp( TS_MW, $now ), true ) ] ],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
                # $action != 'read' && $action != 'createaccount' && $user->isBlockedFrom( $this )
                #   $user->blockedFor() == ''
@@ -1096,22 +1155,22 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                        $wgLang->timeanddate( wfTimestamp( TS_MW, $now ), true ) ] ];
 
                $this->assertEquals( $errors,
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'edit', $this->user, $this->title ) );
                $this->assertEquals( $errors,
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
                $this->assertEquals( $errors,
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'rollback', $this->user, $this->title ) );
                $this->assertEquals( $errors,
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'patrol', $this->user, $this->title ) );
                $this->assertEquals( $errors,
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'upload', $this->user, $this->title ) );
                $this->assertEquals( [],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'purge', $this->user, $this->title ) );
 
                // partial block message test
@@ -1126,22 +1185,22 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                ] );
 
                $this->assertEquals( [],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'edit', $this->user, $this->title ) );
                $this->assertEquals( [],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
                $this->assertEquals( [],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'rollback', $this->user, $this->title ) );
                $this->assertEquals( [],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'patrol', $this->user, $this->title ) );
                $this->assertEquals( [],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'upload', $this->user, $this->title ) );
                $this->assertEquals( [],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'purge', $this->user, $this->title ) );
 
                $this->user->mBlock->setRestrictions( [
@@ -1154,22 +1213,22 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                        $wgLang->timeanddate( wfTimestamp( TS_MW, $now ), true ) ] ];
 
                $this->assertEquals( $errors,
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'edit', $this->user, $this->title ) );
                $this->assertEquals( $errors,
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
                $this->assertEquals( $errors,
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'rollback', $this->user, $this->title ) );
                $this->assertEquals( $errors,
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'patrol', $this->user, $this->title ) );
                $this->assertEquals( [],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'upload', $this->user, $this->title ) );
                $this->assertEquals( [],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'purge', $this->user, $this->title ) );
 
                // Test no block.
@@ -1177,7 +1236,7 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                $this->user->mBlock = null;
 
                $this->assertEquals( [],
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'edit', $this->user, $this->title ) );
        }
 
@@ -1228,7 +1287,7 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                        $wgLang->timeanddate( wfTimestamp( TS_MW, $now ), true ) ] ];
 
                $this->assertEquals( $errors,
-                       $this->permissionManager
+                       MediaWikiServices::getInstance()->getPermissionManager()
                                ->getPermissionErrors( 'tester', $this->user, $this->title ) );
        }
 
@@ -1243,7 +1302,7 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                //$this->assertSame( '', $user->blockedBy(), 'sanity check' );
                //$this->assertSame( '', $user->blockedFor(), 'sanity check' );
                //$this->assertFalse( (bool)$user->isHidden(), 'sanity check' );
-               $this->assertFalse( $this->permissionManager
+               $this->assertFalse( MediaWikiServices::getInstance()->getPermissionManager()
                        ->isBlockedFrom( $user, $ut ), 'sanity check' );
 
                // Block the user
@@ -1264,7 +1323,8 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                //$this->assertSame( $blocker->getName(), $user->blockedBy() );
                //$this->assertSame( 'Because', $user->blockedFor() );
                //$this->assertTrue( (bool)$user->isHidden() );
-               $this->assertTrue( $this->permissionManager->isBlockedFrom( $user, $ut ) );
+               $this->assertTrue( MediaWikiServices::getInstance()->getPermissionManager()
+                       ->isBlockedFrom( $user, $ut ) );
 
                // Unblock
                $block->delete();
@@ -1275,7 +1335,8 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                //$this->assertSame( '', $user->blockedBy() );
                //$this->assertSame( '', $user->blockedFor() );
                //$this->assertFalse( (bool)$user->isHidden() );
-               $this->assertFalse( $this->permissionManager->isBlockedFrom( $user, $ut ) );
+               $this->assertFalse( MediaWikiServices::getInstance()->getPermissionManager()
+                       ->isBlockedFrom( $user, $ut ) );
        }
 
        /**
@@ -1325,7 +1386,8 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                $block->insert();
 
                try {
-                       $this->assertSame( $expect, $this->permissionManager->isBlockedFrom( $user, $title ) );
+                       $this->assertSame( $expect, MediaWikiServices::getInstance()->getPermissionManager()
+                               ->isBlockedFrom( $user, $title ) );
                } finally {
                        $block->delete();
                }
@@ -1408,4 +1470,187 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                ];
        }
 
+       /**
+        * @covers \MediaWiki\Permissions\PermissionManager::getUserPermissions
+        */
+       public function testGetUserPermissions() {
+               $user = $this->getTestUser( [ 'unittesters' ] )->getUser();
+               $rights = MediaWikiServices::getInstance()->getPermissionManager()
+                       ->getUserPermissions( $user );
+               $this->assertContains( 'runtest', $rights );
+               $this->assertNotContains( 'writetest', $rights );
+               $this->assertNotContains( 'modifytest', $rights );
+               $this->assertNotContains( 'nukeworld', $rights );
+       }
+
+       /**
+        * @covers \MediaWiki\Permissions\PermissionManager::getUserPermissions
+        */
+       public function testGetUserPermissionsHooks() {
+               $user = $this->getTestUser( [ 'unittesters', 'testwriters' ] )->getUser();
+               $userWrapper = TestingAccessWrapper::newFromObject( $user );
+
+               $rights = MediaWikiServices::getInstance()->getPermissionManager()
+                       ->getUserPermissions( $user );
+               $this->assertContains( 'test', $rights, 'sanity check' );
+               $this->assertContains( 'runtest', $rights, 'sanity check' );
+               $this->assertContains( 'writetest', $rights, 'sanity check' );
+               $this->assertNotContains( 'nukeworld', $rights, 'sanity check' );
+
+               // Add a hook manipluating the rights
+               $this->mergeMwGlobalArrayValue( 'wgHooks', [ 'UserGetRights' => [ function ( $user, &$rights ) {
+                       $rights[] = 'nukeworld';
+                       $rights = array_diff( $rights, [ 'writetest' ] );
+               } ] ] );
+
+               $this->overrideMwServices();
+               $rights = MediaWikiServices::getInstance()->getPermissionManager()
+                       ->getUserPermissions( $user );
+               $this->assertContains( 'test', $rights );
+               $this->assertContains( 'runtest', $rights );
+               $this->assertNotContains( 'writetest', $rights );
+               $this->assertContains( 'nukeworld', $rights );
+
+               // Add a Session that limits rights
+               $mock = $this->getMockBuilder( stdClass::class )
+                       ->setMethods( [ 'getAllowedUserRights', 'deregisterSession', 'getSessionId' ] )
+                       ->getMock();
+               $mock->method( 'getAllowedUserRights' )->willReturn( [ 'test', 'writetest' ] );
+               $mock->method( 'getSessionId' )->willReturn(
+                       new SessionId( str_repeat( 'X', 32 ) )
+               );
+               $session = TestUtils::getDummySession( $mock );
+               $mockRequest = $this->getMockBuilder( FauxRequest::class )
+                       ->setMethods( [ 'getSession' ] )
+                       ->getMock();
+               $mockRequest->method( 'getSession' )->willReturn( $session );
+               $userWrapper->mRequest = $mockRequest;
+
+               $this->overrideMwServices();
+               $rights = MediaWikiServices::getInstance()->getPermissionManager()
+                       ->getUserPermissions( $user );
+               $this->assertContains( 'test', $rights );
+               $this->assertNotContains( 'runtest', $rights );
+               $this->assertNotContains( 'writetest', $rights );
+               $this->assertNotContains( 'nukeworld', $rights );
+       }
+
+       /**
+        * @covers \MediaWiki\Permissions\PermissionManager::getGroupPermissions
+        */
+       public function testGroupPermissions() {
+               $rights = MediaWikiServices::getInstance()->getPermissionManager()
+                       ->getGroupPermissions( [ 'unittesters' ] );
+               $this->assertContains( 'runtest', $rights );
+               $this->assertNotContains( 'writetest', $rights );
+               $this->assertNotContains( 'modifytest', $rights );
+               $this->assertNotContains( 'nukeworld', $rights );
+
+               $rights = MediaWikiServices::getInstance()->getPermissionManager()
+                       ->getGroupPermissions( [ 'unittesters', 'testwriters' ] );
+               $this->assertContains( 'runtest', $rights );
+               $this->assertContains( 'writetest', $rights );
+               $this->assertContains( 'modifytest', $rights );
+               $this->assertNotContains( 'nukeworld', $rights );
+       }
+
+       /**
+        * @covers \MediaWiki\Permissions\PermissionManager::getGroupPermissions
+        */
+       public function testRevokePermissions() {
+               $rights = MediaWikiServices::getInstance()->getPermissionManager()
+                       ->getGroupPermissions( [ 'unittesters', 'formertesters' ] );
+               $this->assertNotContains( 'runtest', $rights );
+               $this->assertNotContains( 'writetest', $rights );
+               $this->assertNotContains( 'modifytest', $rights );
+               $this->assertNotContains( 'nukeworld', $rights );
+       }
+
+       /**
+        * @dataProvider provideGetGroupsWithPermission
+        * @covers \MediaWiki\Permissions\PermissionManager::getGroupsWithPermission
+        */
+       public function testGetGroupsWithPermission( $expected, $right ) {
+               $result = MediaWikiServices::getInstance()->getPermissionManager()
+                       ->getGroupsWithPermission( $right );
+               sort( $result );
+               sort( $expected );
+
+               $this->assertEquals( $expected, $result, "Groups with permission $right" );
+       }
+
+       public static function provideGetGroupsWithPermission() {
+               return [
+                       [
+                               [ 'unittesters', 'testwriters' ],
+                               'test'
+                       ],
+                       [
+                               [ 'unittesters' ],
+                               'runtest'
+                       ],
+                       [
+                               [ 'testwriters' ],
+                               'writetest'
+                       ],
+                       [
+                               [ 'testwriters' ],
+                               'modifytest'
+                       ],
+               ];
+       }
+
+       /**
+        * @covers \MediaWiki\Permissions\PermissionManager::userHasRight
+        */
+       public function testUserHasRight() {
+               $result = MediaWikiServices::getInstance()->getPermissionManager()->userHasRight(
+                       $this->getTestUser( 'unittesters' )->getUser(),
+                       'test'
+               );
+               $this->assertTrue( $result );
+
+               $result = MediaWikiServices::getInstance()->getPermissionManager()->userHasRight(
+                       $this->getTestUser( 'formertesters' )->getUser(),
+                       'runtest'
+               );
+               $this->assertFalse( $result );
+
+               $result = MediaWikiServices::getInstance()->getPermissionManager()->userHasRight(
+                       $this->getTestUser( 'formertesters' )->getUser(),
+                       ''
+               );
+               $this->assertTrue( $result );
+       }
+
+       /**
+        * @covers \MediaWiki\Permissions\PermissionManager::groupHasPermission
+        */
+       public function testGroupHasPermission() {
+               $result = MediaWikiServices::getInstance()->getPermissionManager()->groupHasPermission(
+                       'unittesters',
+                       'test'
+               );
+               $this->assertTrue( $result );
+
+               $result = MediaWikiServices::getInstance()->getPermissionManager()->groupHasPermission(
+                       'formertesters',
+                       'runtest'
+               );
+               $this->assertFalse( $result );
+       }
+
+       /**
+        * @covers \MediaWiki\Permissions\PermissionManager::isEveryoneAllowed
+        */
+       public function testIsEveryoneAllowed() {
+               $result = MediaWikiServices::getInstance()->getPermissionManager()
+                                                                  ->isEveryoneAllowed( 'editmyoptions' );
+               $this->assertTrue( $result );
+
+               $result = MediaWikiServices::getInstance()->getPermissionManager()
+                                                                  ->isEveryoneAllowed( 'test' );
+               $this->assertFalse( $result );
+       }
+
 }
index 7501167..d05217f 100644 (file)
@@ -1551,6 +1551,8 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                                ],
                        ]
                );
+               // TODO: this one is necessary to pass globals changes to PermissionManger
+               $this->overrideMwServices();
                $user = $this->getTestUser( $userGroups )->getUser();
 
                $this->assertSame(
@@ -1604,6 +1606,8 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                                ],
                        ]
                );
+               // TODO: this one is necessary to pass globals changes to PermissionManger
+               $this->overrideMwServices();
                $user = $this->getTestUser( $userGroups )->getUser();
                $revision = new Revision( [ 'deleted' => $bitField ], 0, $this->testPage->getTitle() );
 
index ebd8dbd..04addab 100644 (file)
@@ -15,7 +15,7 @@ class TemplateCategoriesTest extends MediaWikiLangTestCase {
         */
        public function testTemplateCategories() {
                $user = new User();
-               $user->mRights = [ 'createpage', 'edit', 'purge', 'delete' ];
+               $this->overrideUserPermissions( $user, [ 'createpage', 'edit', 'purge', 'delete' ] );
 
                $title = Title::newFromText( "Categorized from template" );
                $page = WikiPage::factory( $title );
index e09546e..fcf4b20 100644 (file)
@@ -75,16 +75,6 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
                $this->overrideMwServices();
        }
 
-       protected function setUserPerm( $perm ) {
-               // Setting member variables is evil!!!
-
-               if ( is_array( $perm ) ) {
-                       $this->user->mRights = $perm;
-               } else {
-                       $this->user->mRights = [ $perm ];
-               }
-       }
-
        protected function setTitle( $ns, $title = "Main_Page" ) {
                $this->title = Title::makeTitle( $ns, $title );
        }
@@ -114,139 +104,139 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
 
                $this->setUser( 'anon' );
                $this->setTitle( NS_TALK );
-               $this->setUserPerm( "createtalk" );
+               $this->overrideUserPermissions( $this->user, "createtalk" );
                $res = $this->title->getUserPermissionsErrors( 'create', $this->user );
                $this->assertEquals( [], $res );
 
                $this->setTitle( NS_TALK );
-               $this->setUserPerm( "createpage" );
+               $this->overrideUserPermissions( $this->user, "createpage" );
                $res = $this->title->getUserPermissionsErrors( 'create', $this->user );
                $this->assertEquals( [ [ "nocreatetext" ] ], $res );
 
                $this->setTitle( NS_TALK );
-               $this->setUserPerm( "" );
+               $this->overrideUserPermissions( $this->user, "" );
                $res = $this->title->getUserPermissionsErrors( 'create', $this->user );
                $this->assertEquals( [ [ 'nocreatetext' ] ], $res );
 
                $this->setTitle( NS_MAIN );
-               $this->setUserPerm( "createpage" );
+               $this->overrideUserPermissions( $this->user, "createpage" );
                $res = $this->title->getUserPermissionsErrors( 'create', $this->user );
                $this->assertEquals( [], $res );
 
                $this->setTitle( NS_MAIN );
-               $this->setUserPerm( "createtalk" );
+               $this->overrideUserPermissions( $this->user, "createtalk" );
                $res = $this->title->getUserPermissionsErrors( 'create', $this->user );
                $this->assertEquals( [ [ 'nocreatetext' ] ], $res );
 
                $this->setUser( $this->userName );
                $this->setTitle( NS_TALK );
-               $this->setUserPerm( "createtalk" );
+               $this->overrideUserPermissions( $this->user, "createtalk" );
                $res = $this->title->getUserPermissionsErrors( 'create', $this->user );
                $this->assertEquals( [], $res );
 
                $this->setTitle( NS_TALK );
-               $this->setUserPerm( "createpage" );
+               $this->overrideUserPermissions( $this->user, "createpage" );
                $res = $this->title->getUserPermissionsErrors( 'create', $this->user );
                $this->assertEquals( [ [ 'nocreate-loggedin' ] ], $res );
 
                $this->setTitle( NS_TALK );
-               $this->setUserPerm( "" );
+               $this->overrideUserPermissions( $this->user );
                $res = $this->title->getUserPermissionsErrors( 'create', $this->user );
                $this->assertEquals( [ [ 'nocreate-loggedin' ] ], $res );
 
                $this->setTitle( NS_MAIN );
-               $this->setUserPerm( "createpage" );
+               $this->overrideUserPermissions( $this->user, "createpage" );
                $res = $this->title->getUserPermissionsErrors( 'create', $this->user );
                $this->assertEquals( [], $res );
 
                $this->setTitle( NS_MAIN );
-               $this->setUserPerm( "createtalk" );
+               $this->overrideUserPermissions( $this->user, "createtalk" );
                $res = $this->title->getUserPermissionsErrors( 'create', $this->user );
                $this->assertEquals( [ [ 'nocreate-loggedin' ] ], $res );
 
                $this->setTitle( NS_MAIN );
-               $this->setUserPerm( "" );
+               $this->overrideUserPermissions( $this->user );
                $res = $this->title->getUserPermissionsErrors( 'create', $this->user );
                $this->assertEquals( [ [ 'nocreate-loggedin' ] ], $res );
 
                $this->setUser( 'anon' );
                $this->setTitle( NS_USER, $this->userName . '' );
-               $this->setUserPerm( "" );
+               $this->overrideUserPermissions( $this->user );
                $res = $this->title->getUserPermissionsErrors( 'move', $this->user );
                $this->assertEquals( [ [ 'cant-move-user-page' ], [ 'movenologintext' ] ], $res );
 
                $this->setTitle( NS_USER, $this->userName . '/subpage' );
-               $this->setUserPerm( "" );
+               $this->overrideUserPermissions( $this->user );
                $res = $this->title->getUserPermissionsErrors( 'move', $this->user );
                $this->assertEquals( [ [ 'movenologintext' ] ], $res );
 
                $this->setTitle( NS_USER, $this->userName . '' );
-               $this->setUserPerm( "move-rootuserpages" );
+               $this->overrideUserPermissions( $this->user, "move-rootuserpages" );
                $res = $this->title->getUserPermissionsErrors( 'move', $this->user );
                $this->assertEquals( [ [ 'movenologintext' ] ], $res );
 
                $this->setTitle( NS_USER, $this->userName . '/subpage' );
-               $this->setUserPerm( "move-rootuserpages" );
+               $this->overrideUserPermissions( $this->user, "move-rootuserpages" );
                $res = $this->title->getUserPermissionsErrors( 'move', $this->user );
                $this->assertEquals( [ [ 'movenologintext' ] ], $res );
 
                $this->setTitle( NS_USER, $this->userName . '' );
-               $this->setUserPerm( "" );
+               $this->overrideUserPermissions( $this->user, "" );
                $res = $this->title->getUserPermissionsErrors( 'move', $this->user );
                $this->assertEquals( [ [ 'cant-move-user-page' ], [ 'movenologintext' ] ], $res );
 
                $this->setTitle( NS_USER, $this->userName . '/subpage' );
-               $this->setUserPerm( "" );
+               $this->overrideUserPermissions( $this->user, "" );
                $res = $this->title->getUserPermissionsErrors( 'move', $this->user );
                $this->assertEquals( [ [ 'movenologintext' ] ], $res );
 
                $this->setTitle( NS_USER, $this->userName . '' );
-               $this->setUserPerm( "move-rootuserpages" );
+               $this->overrideUserPermissions( $this->user, "move-rootuserpages" );
                $res = $this->title->getUserPermissionsErrors( 'move', $this->user );
                $this->assertEquals( [ [ 'movenologintext' ] ], $res );
 
                $this->setTitle( NS_USER, $this->userName . '/subpage' );
-               $this->setUserPerm( "move-rootuserpages" );
+               $this->overrideUserPermissions( $this->user, "move-rootuserpages" );
                $res = $this->title->getUserPermissionsErrors( 'move', $this->user );
                $this->assertEquals( [ [ 'movenologintext' ] ], $res );
 
                $this->setUser( $this->userName );
                $this->setTitle( NS_FILE, "img.png" );
-               $this->setUserPerm( "" );
+               $this->overrideUserPermissions( $this->user );
                $res = $this->title->getUserPermissionsErrors( 'move', $this->user );
                $this->assertEquals( [ [ 'movenotallowedfile' ], [ 'movenotallowed' ] ], $res );
 
                $this->setTitle( NS_FILE, "img.png" );
-               $this->setUserPerm( "movefile" );
+               $this->overrideUserPermissions( $this->user, "movefile" );
                $res = $this->title->getUserPermissionsErrors( 'move', $this->user );
                $this->assertEquals( [ [ 'movenotallowed' ] ], $res );
 
                $this->setUser( 'anon' );
                $this->setTitle( NS_FILE, "img.png" );
-               $this->setUserPerm( "" );
+               $this->overrideUserPermissions( $this->user );
                $res = $this->title->getUserPermissionsErrors( 'move', $this->user );
                $this->assertEquals( [ [ 'movenotallowedfile' ], [ 'movenologintext' ] ], $res );
 
                $this->setTitle( NS_FILE, "img.png" );
-               $this->setUserPerm( "movefile" );
+               $this->overrideUserPermissions( $this->user, "movefile" );
                $res = $this->title->getUserPermissionsErrors( 'move', $this->user );
                $this->assertEquals( [ [ 'movenologintext' ] ], $res );
 
                $this->setUser( $this->userName );
-               $this->setUserPerm( "move" );
+               $this->overrideUserPermissions( $this->user, "move" );
                $this->runGroupPermissions( 'move', [ [ 'movenotallowedfile' ] ] );
 
-               $this->setUserPerm( "" );
+               $this->overrideUserPermissions( $this->user );
                $this->runGroupPermissions(
                        'move',
                        [ [ 'movenotallowedfile' ], [ 'movenotallowed' ] ]
                );
 
                $this->setUser( 'anon' );
-               $this->setUserPerm( "move" );
+               $this->overrideUserPermissions( $this->user, "move" );
                $this->runGroupPermissions( 'move', [ [ 'movenotallowedfile' ] ] );
 
-               $this->setUserPerm( "" );
+               $this->overrideUserPermissions( $this->user );
                $this->runGroupPermissions(
                        'move',
                        [ [ 'movenotallowedfile' ], [ 'movenotallowed' ] ],
@@ -259,51 +249,51 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
 
                        $this->setTitle( NS_MAIN );
                        $this->setUser( 'anon' );
-                       $this->setUserPerm( "move" );
+                       $this->overrideUserPermissions( $this->user, "move" );
                        $this->runGroupPermissions( 'move', [] );
 
-                       $this->setUserPerm( "" );
+                       $this->overrideUserPermissions( $this->user, "" );
                        $this->runGroupPermissions( 'move', [ [ 'movenotallowed' ] ],
                                [ [ 'movenologintext' ] ] );
 
                        $this->setUser( $this->userName );
-                       $this->setUserPerm( "" );
+                       $this->overrideUserPermissions( $this->user, "" );
                        $this->runGroupPermissions( 'move', [ [ 'movenotallowed' ] ] );
 
-                       $this->setUserPerm( "move" );
+                       $this->overrideUserPermissions( $this->user, "move" );
                        $this->runGroupPermissions( 'move', [] );
 
                        $this->setUser( 'anon' );
-                       $this->setUserPerm( 'move' );
+                       $this->overrideUserPermissions( $this->user, 'move' );
                        $res = $this->title->getUserPermissionsErrors( 'move-target', $this->user );
                        $this->assertEquals( [], $res );
 
-                       $this->setUserPerm( '' );
+                       $this->overrideUserPermissions( $this->user );
                        $res = $this->title->getUserPermissionsErrors( 'move-target', $this->user );
                        $this->assertEquals( [ [ 'movenotallowed' ] ], $res );
                }
 
                $this->setTitle( NS_USER );
                $this->setUser( $this->userName );
-               $this->setUserPerm( [ "move", "move-rootuserpages" ] );
+               $this->overrideUserPermissions( $this->user, [ "move", "move-rootuserpages" ] );
                $res = $this->title->getUserPermissionsErrors( 'move-target', $this->user );
                $this->assertEquals( [], $res );
 
-               $this->setUserPerm( "move" );
+               $this->overrideUserPermissions( $this->user, "move" );
                $res = $this->title->getUserPermissionsErrors( 'move-target', $this->user );
                $this->assertEquals( [ [ 'cant-move-to-user-page' ] ], $res );
 
                $this->setUser( 'anon' );
-               $this->setUserPerm( [ "move", "move-rootuserpages" ] );
+               $this->overrideUserPermissions( $this->user, [ "move", "move-rootuserpages" ] );
                $res = $this->title->getUserPermissionsErrors( 'move-target', $this->user );
                $this->assertEquals( [], $res );
 
                $this->setTitle( NS_USER, "User/subpage" );
-               $this->setUserPerm( [ "move", "move-rootuserpages" ] );
+               $this->overrideUserPermissions( $this->user, [ "move", "move-rootuserpages" ] );
                $res = $this->title->getUserPermissionsErrors( 'move-target', $this->user );
                $this->assertEquals( [], $res );
 
-               $this->setUserPerm( "move" );
+               $this->overrideUserPermissions( $this->user, "move" );
                $res = $this->title->getUserPermissionsErrors( 'move-target', $this->user );
                $this->assertEquals( [], $res );
 
@@ -329,7 +319,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
                ];
 
                foreach ( [ "edit", "protect", "" ] as $action ) {
-                       $this->setUserPerm( null );
+                       $this->overrideUserPermissions( $this->user );
                        $this->assertEquals( $check[$action][0],
                                $this->title->getUserPermissionsErrors( $action, $this->user, true ) );
                        $this->assertEquals( $check[$action][0],
@@ -341,15 +331,19 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
                        $old = $wgGroupPermissions;
                        $wgGroupPermissions = [];
 
+                       $this->overrideMwServices();
+
                        $this->assertEquals( $check[$action][1],
                                $this->title->getUserPermissionsErrors( $action, $this->user, true ) );
                        $this->assertEquals( $check[$action][1],
                                $this->title->getUserPermissionsErrors( $action, $this->user, 'full' ) );
                        $this->assertEquals( $check[$action][1],
                                $this->title->getUserPermissionsErrors( $action, $this->user, 'secure' ) );
+
                        $wgGroupPermissions = $old;
+                       $this->overrideMwServices();
 
-                       $this->setUserPerm( $action );
+                       $this->overrideUserPermissions( $this->user, $action );
                        $this->assertEquals( $check[$action][2],
                                $this->title->getUserPermissionsErrors( $action, $this->user, true ) );
                        $this->assertEquals( $check[$action][2],
@@ -357,7 +351,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
                        $this->assertEquals( $check[$action][2],
                                $this->title->getUserPermissionsErrors( $action, $this->user, 'secure' ) );
 
-                       $this->setUserPerm( $action );
+                       $this->overrideUserPermissions( $this->user, $action );
                        $this->assertEquals( $check[$action][3],
                                $this->title->userCan( $action, $this->user, true ) );
                        $this->assertEquals( $check[$action][3],
@@ -373,23 +367,39 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
                        $result2 = $result;
                }
 
+               // XXX: there could be a better way to handle this, but since we need to
+               // override PermissionManager service each time globals are changed
+               // and in the same time we need to keep user permissions overrides from the outside
+               // the best we can do inside this method is to save & restore faked user perms
+
+               $userPermsOverrides = MediaWikiServices::getInstance()->getPermissionManager()
+                       ->getUserPermissions( $this->user );
+
                $wgGroupPermissions['autoconfirmed']['move'] = false;
                $wgGroupPermissions['user']['move'] = false;
+               $this->overrideMwServices();
+               $this->overrideUserPermissions( $this->user, $userPermsOverrides );
                $res = $this->title->getUserPermissionsErrors( $action, $this->user );
                $this->assertEquals( $result, $res );
 
                $wgGroupPermissions['autoconfirmed']['move'] = true;
                $wgGroupPermissions['user']['move'] = false;
+               $this->overrideMwServices();
+               $this->overrideUserPermissions( $this->user, $userPermsOverrides );
                $res = $this->title->getUserPermissionsErrors( $action, $this->user );
                $this->assertEquals( $result2, $res );
 
                $wgGroupPermissions['autoconfirmed']['move'] = true;
                $wgGroupPermissions['user']['move'] = true;
+               $this->overrideMwServices();
+               $this->overrideUserPermissions( $this->user, $userPermsOverrides );
                $res = $this->title->getUserPermissionsErrors( $action, $this->user );
                $this->assertEquals( $result2, $res );
 
                $wgGroupPermissions['autoconfirmed']['move'] = false;
                $wgGroupPermissions['user']['move'] = true;
+               $this->overrideMwServices();
+               $this->overrideUserPermissions( $this->user, $userPermsOverrides );
                $res = $this->title->getUserPermissionsErrors( $action, $this->user );
                $this->assertEquals( $result2, $res );
        }
@@ -409,42 +419,42 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
                        $this->title->getUserPermissionsErrors( 'bogus', $this->user ) );
 
                $this->setTitle( NS_MAIN );
-               $this->setUserPerm( 'bogus' );
+               $this->overrideUserPermissions( $this->user, 'bogus' );
                $this->assertEquals( [],
                        $this->title->getUserPermissionsErrors( 'bogus', $this->user ) );
 
                $this->setTitle( NS_MAIN );
-               $this->setUserPerm( '' );
+               $this->overrideUserPermissions( $this->user );
                $this->assertEquals( [ [ 'badaccess-group0' ] ],
                        $this->title->getUserPermissionsErrors( 'bogus', $this->user ) );
 
                $wgNamespaceProtection[NS_USER] = [ 'bogus' ];
 
                $this->setTitle( NS_USER );
-               $this->setUserPerm( '' );
+               $this->overrideUserPermissions( $this->user );
                $this->assertEquals( [ [ 'badaccess-group0' ],
                                [ 'namespaceprotected', 'User', 'bogus' ] ],
                        $this->title->getUserPermissionsErrors( 'bogus', $this->user ) );
 
                $this->setTitle( NS_MEDIAWIKI );
-               $this->setUserPerm( 'bogus' );
+               $this->overrideUserPermissions( $this->user, 'bogus' );
                $this->assertEquals( [ [ 'protectedinterface', 'bogus' ] ],
                        $this->title->getUserPermissionsErrors( 'bogus', $this->user ) );
 
                $this->setTitle( NS_MEDIAWIKI );
-               $this->setUserPerm( 'bogus' );
+               $this->overrideUserPermissions( $this->user, 'bogus' );
                $this->assertEquals( [ [ 'protectedinterface', 'bogus' ] ],
                        $this->title->getUserPermissionsErrors( 'bogus', $this->user ) );
 
                $wgNamespaceProtection = null;
 
-               $this->setUserPerm( 'bogus' );
+               $this->overrideUserPermissions( $this->user, 'bogus' );
                $this->assertEquals( [],
                        $this->title->getUserPermissionsErrors( 'bogus', $this->user ) );
                $this->assertEquals( true,
                        $this->title->userCan( 'bogus', $this->user ) );
 
-               $this->setUserPerm( '' );
+               $this->overrideUserPermissions( $this->user );
                $this->assertEquals( [ [ 'badaccess-group0' ] ],
                        $this->title->getUserPermissionsErrors( 'bogus', $this->user ) );
                $this->assertEquals( false,
@@ -645,39 +655,39 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
                $resultUserJs,
                $resultPatrol
        ) {
-               $this->setUserPerm( '' );
+               $this->overrideUserPermissions( $this->user );
                $result = $this->title->getUserPermissionsErrors( 'bogus', $this->user );
                $this->assertEquals( $resultNone, $result );
 
-               $this->setUserPerm( 'editmyusercss' );
+               $this->overrideUserPermissions( $this->user, 'editmyusercss' );
                $result = $this->title->getUserPermissionsErrors( 'bogus', $this->user );
                $this->assertEquals( $resultMyCss, $result );
 
-               $this->setUserPerm( 'editmyuserjson' );
+               $this->overrideUserPermissions( $this->user, 'editmyuserjson' );
                $result = $this->title->getUserPermissionsErrors( 'bogus', $this->user );
                $this->assertEquals( $resultMyJson, $result );
 
-               $this->setUserPerm( 'editmyuserjs' );
+               $this->overrideUserPermissions( $this->user, 'editmyuserjs' );
                $result = $this->title->getUserPermissionsErrors( 'bogus', $this->user );
                $this->assertEquals( $resultMyJs, $result );
 
-               $this->setUserPerm( 'editusercss' );
+               $this->overrideUserPermissions( $this->user, 'editusercss' );
                $result = $this->title->getUserPermissionsErrors( 'bogus', $this->user );
                $this->assertEquals( $resultUserCss, $result );
 
-               $this->setUserPerm( 'edituserjson' );
+               $this->overrideUserPermissions( $this->user, 'edituserjson' );
                $result = $this->title->getUserPermissionsErrors( 'bogus', $this->user );
                $this->assertEquals( $resultUserJson, $result );
 
-               $this->setUserPerm( 'edituserjs' );
+               $this->overrideUserPermissions( $this->user, 'edituserjs' );
                $result = $this->title->getUserPermissionsErrors( 'bogus', $this->user );
                $this->assertEquals( $resultUserJs, $result );
 
-               $this->setUserPerm( '' );
+               $this->overrideUserPermissions( $this->user );
                $result = $this->title->getUserPermissionsErrors( 'patrol', $this->user );
                $this->assertEquals( reset( $resultPatrol[0] ), reset( $result[0] ) );
 
-               $this->setUserPerm( [ 'edituserjs', 'edituserjson', 'editusercss' ] );
+               $this->overrideUserPermissions( $this->user, [ 'edituserjs', 'edituserjson', 'editusercss' ] );
                $result = $this->title->getUserPermissionsErrors( 'bogus', $this->user );
                $this->assertEquals( [ [ 'badaccess-group0' ] ], $result );
        }
@@ -697,7 +707,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
 
                $this->setTitle( NS_MAIN );
                $this->title->mRestrictionsLoaded = true;
-               $this->setUserPerm( "edit" );
+               $this->overrideUserPermissions( $this->user, "edit" );
                $this->title->mRestrictions = [ "bogus" => [ 'bogus', "sysop", "protect", "" ] ];
 
                $this->assertEquals( [],
@@ -720,7 +730,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
                                [ 'protectedpagetext', 'protect', 'edit' ] ],
                        $this->title->getUserPermissionsErrors( 'edit',
                                $this->user ) );
-               $this->setUserPerm( "" );
+               $this->overrideUserPermissions( $this->user );
                $this->assertEquals( [ [ 'badaccess-group0' ],
                                [ 'protectedpagetext', 'bogus', 'bogus' ],
                                [ 'protectedpagetext', 'editprotected', 'bogus' ],
@@ -733,7 +743,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
                                [ 'protectedpagetext', 'protect', 'edit' ] ],
                        $this->title->getUserPermissionsErrors( 'edit',
                                $this->user ) );
-               $this->setUserPerm( [ "edit", "editprotected" ] );
+               $this->overrideUserPermissions( $this->user, [ "edit", "editprotected" ] );
                $this->assertEquals( [ [ 'badaccess-group0' ],
                                [ 'protectedpagetext', 'bogus', 'bogus' ],
                                [ 'protectedpagetext', 'protect', 'bogus' ] ],
@@ -746,7 +756,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
                                $this->user ) );
 
                $this->title->mCascadeRestriction = true;
-               $this->setUserPerm( "edit" );
+               $this->overrideUserPermissions( $this->user, "edit" );
                $this->assertEquals( false,
                        $this->title->quickUserCan( 'bogus', $this->user ) );
                $this->assertEquals( false,
@@ -763,7 +773,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
                        $this->title->getUserPermissionsErrors( 'edit',
                                $this->user ) );
 
-               $this->setUserPerm( [ "edit", "editprotected" ] );
+               $this->overrideUserPermissions( $this->user, [ "edit", "editprotected" ] );
                $this->assertEquals( false,
                        $this->title->quickUserCan( 'bogus', $this->user ) );
                $this->assertEquals( false,
@@ -786,7 +796,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
         */
        public function testCascadingSourcesRestrictions() {
                $this->setTitle( NS_MAIN, "test page" );
-               $this->setUserPerm( [ "edit", "bogus" ] );
+               $this->overrideUserPermissions( $this->user, [ "edit", "bogus" ] );
 
                $this->title->mCascadeSources = [
                        Title::makeTitle( NS_MAIN, "Bogus" ),
@@ -816,7 +826,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
         * @covers \MediaWiki\Permissions\PermissionManager::checkActionPermissions
         */
        public function testActionPermissions() {
-               $this->setUserPerm( [ "createpage" ] );
+               $this->overrideUserPermissions( $this->user, [ "createpage" ] );
                $this->setTitle( NS_MAIN, "test page" );
                $this->title->mTitleProtection['permission'] = '';
                $this->title->mTitleProtection['user'] = $this->user->getId();
@@ -830,26 +840,26 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
                        $this->title->userCan( 'create', $this->user ) );
 
                $this->title->mTitleProtection['permission'] = 'editprotected';
-               $this->setUserPerm( [ 'createpage', 'protect' ] );
+               $this->overrideUserPermissions( $this->user, [ 'createpage', 'protect' ] );
                $this->assertEquals( [ [ 'titleprotected', 'Useruser', 'test' ] ],
                        $this->title->getUserPermissionsErrors( 'create', $this->user ) );
                $this->assertEquals( false,
                        $this->title->userCan( 'create', $this->user ) );
 
-               $this->setUserPerm( [ 'createpage', 'editprotected' ] );
+               $this->overrideUserPermissions( $this->user, [ 'createpage', 'editprotected' ] );
                $this->assertEquals( [],
                        $this->title->getUserPermissionsErrors( 'create', $this->user ) );
                $this->assertEquals( true,
                        $this->title->userCan( 'create', $this->user ) );
 
-               $this->setUserPerm( [ 'createpage' ] );
+               $this->overrideUserPermissions( $this->user, [ 'createpage' ] );
                $this->assertEquals( [ [ 'titleprotected', 'Useruser', 'test' ] ],
                        $this->title->getUserPermissionsErrors( 'create', $this->user ) );
                $this->assertEquals( false,
                        $this->title->userCan( 'create', $this->user ) );
 
                $this->setTitle( NS_MEDIA, "test page" );
-               $this->setUserPerm( [ "move" ] );
+               $this->overrideUserPermissions( $this->user, [ "move" ] );
                $this->assertEquals( false,
                        $this->title->userCan( 'move', $this->user ) );
                $this->assertEquals( [ [ 'immobile-source-namespace', 'Media' ] ],
@@ -897,7 +907,10 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
                ] );
                $this->overrideMwServices();
 
-               $this->setUserPerm( [ 'createpage', 'edit', 'move', 'rollback', 'patrol', 'upload', 'purge' ] );
+               $this->overrideUserPermissions(
+                       $this->user,
+                       [ 'createpage', 'edit', 'move', 'rollback', 'patrol', 'upload', 'purge' ]
+               );
                $this->setTitle( NS_HELP, "test page" );
 
                # $wgEmailConfirmToEdit only applies to 'edit' action
@@ -908,6 +921,10 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
 
                $this->setMwGlobals( 'wgEmailConfirmToEdit', false );
                $this->overrideMwServices();
+               $this->overrideUserPermissions(
+                       $this->user,
+                       [ 'createpage', 'edit', 'move', 'rollback', 'patrol', 'upload', 'purge' ]
+               );
 
                $this->assertNotContains( [ 'confirmedittext' ],
                        $this->title->getUserPermissionsErrors( 'edit', $this->user ) );
index d6c3401..a9f08ed 100644 (file)
@@ -355,7 +355,7 @@ class TitleTest extends MediaWikiTestCase {
 
                // New anonymous user with no rights
                $user = new User;
-               $user->mRights = [];
+               $this->overrideUserPermissions( $user, [] );
                $errors = $title->userCan( $action, $user );
 
                if ( is_bool( $expected ) ) {
index 5ad7736..4d977cb 100644 (file)
@@ -190,14 +190,14 @@ class ActionTest extends MediaWikiTestCase {
 
        public function testCanExecute() {
                $user = $this->getTestUser()->getUser();
-               $user->mRights = [ 'access' ];
+               $this->overrideUserPermissions( $user, 'access' );
                $action = Action::factory( 'access', $this->getPage(), $this->getContext() );
                $this->assertNull( $action->canExecute( $user ) );
        }
 
        public function testCanExecuteNoRight() {
                $user = $this->getTestUser()->getUser();
-               $user->mRights = [];
+               $this->overrideUserPermissions( $user, [] );
                $action = Action::factory( 'access', $this->getPage(), $this->getContext() );
 
                try {
@@ -209,7 +209,7 @@ class ActionTest extends MediaWikiTestCase {
 
        public function testCanExecuteRequiresUnblock() {
                $user = $this->getTestUser()->getUser();
-               $user->mRights = [];
+               $this->overrideUserPermissions( $user, [] );
 
                $page = $this->getExistingTestPage();
                $action = Action::factory( 'unblock', $page, $this->getContext() );
index 060834f..bae611b 100644 (file)
@@ -147,6 +147,8 @@ class ApiBlockTest extends ApiTestCase {
                $this->setMwGlobals( 'wgRevokePermissions',
                        [ 'user' => [ 'applychangetags' => true ] ] );
 
+               $this->overrideMwServices();
+
                $this->doBlock( [ 'tags' => 'custom tag' ] );
        }
 
@@ -157,6 +159,7 @@ class ApiBlockTest extends ApiTestCase {
                $this->mergeMwGlobalArrayValue( 'wgGroupPermissions',
                        [ 'sysop' => $newPermissions ] );
 
+               $this->overrideMwServices();
                $res = $this->doBlock( [ 'hidename' => '' ] );
 
                $dbw = wfGetDB( DB_MASTER );
@@ -206,6 +209,8 @@ class ApiBlockTest extends ApiTestCase {
                $this->setMwGlobals( 'wgRevokePermissions',
                        [ 'sysop' => [ 'blockemail' => true ] ] );
 
+               $this->overrideMwServices();
+
                $this->doBlock( [ 'noemail' => '' ] );
        }
 
index c68954c..3868723 100644 (file)
@@ -143,6 +143,7 @@ class ApiDeleteTest extends ApiTestCase {
                ChangeTags::defineTag( 'custom tag' );
                $this->setMwGlobals( 'wgRevokePermissions',
                        [ 'user' => [ 'applychangetags' => true ] ] );
+               $this->overrideMwServices();
 
                $this->editPage( $name, 'Some text' );
 
index 2045a13..a35613c 100644 (file)
@@ -39,6 +39,7 @@ class ApiEditPageTest extends ApiTestCase {
                        $this->tablesUsed,
                        [ 'change_tag', 'change_tag_def', 'logging' ]
                );
+               $this->overrideMwServices();
        }
 
        public function testEdit() {
@@ -1367,6 +1368,9 @@ class ApiEditPageTest extends ApiTestCase {
                ChangeTags::defineTag( 'custom tag' );
                $this->setMwGlobals( 'wgRevokePermissions',
                        [ 'user' => [ 'applychangetags' => true ] ] );
+               // Supply services with updated globals
+               $this->overrideMwServices();
+
                try {
                        $this->doApiRequestWithToken( [
                                'action' => 'edit',
@@ -1545,6 +1549,8 @@ class ApiEditPageTest extends ApiTestCase {
 
                $this->setMwGlobals( 'wgRevokePermissions',
                        [ 'user' => [ 'upload' => true ] ] );
+               // Supply services with updated globals
+               $this->overrideMwServices();
 
                $this->doApiRequestWithToken( [
                        'action' => 'edit',
@@ -1560,6 +1566,8 @@ class ApiEditPageTest extends ApiTestCase {
                        'The content you supplied exceeds the article size limit of 1 kilobyte.' );
 
                $this->setMwGlobals( 'wgMaxArticleSize', 1 );
+               // Supply services with updated globals
+               $this->overrideMwServices();
 
                $text = str_repeat( '!', 1025 );
 
@@ -1577,6 +1585,8 @@ class ApiEditPageTest extends ApiTestCase {
                        'The action you have requested is limited to users in the group: ' );
 
                $this->setMwGlobals( 'wgRevokePermissions', [ '*' => [ 'edit' => true ] ] );
+               // Supply services with updated globals
+               $this->overrideMwServices();
 
                $this->doApiRequestWithToken( [
                        'action' => 'edit',
@@ -1593,6 +1603,8 @@ class ApiEditPageTest extends ApiTestCase {
 
                $this->setMwGlobals( 'wgRevokePermissions',
                        [ 'user' => [ 'editcontentmodel' => true ] ] );
+               // Supply services with updated globals
+               $this->overrideMwServices();
 
                $this->doApiRequestWithToken( [
                        'action' => 'edit',
index a5518a1..6ffadb9 100644 (file)
@@ -141,6 +141,7 @@ class ApiMainTest extends ApiTestCase {
        public function testSetCacheModeUnrecognized() {
                $api = new ApiMain();
                $api->setCacheMode( 'unrecognized' );
+               $this->overrideMwServices();
                $this->assertSame(
                        'private',
                        TestingAccessWrapper::newFromObject( $api )->mCacheMode,
@@ -150,7 +151,7 @@ class ApiMainTest extends ApiTestCase {
 
        public function testSetCacheModePrivateWiki() {
                $this->setGroupPermissions( '*', 'read', false );
-
+               $this->overrideMwServices();
                $wrappedApi = TestingAccessWrapper::newFromObject( new ApiMain() );
                $wrappedApi->setCacheMode( 'public' );
                $this->assertSame( 'private', $wrappedApi->mCacheMode );
@@ -401,7 +402,7 @@ class ApiMainTest extends ApiTestCase {
                } else {
                        $user = new User();
                }
-               $user->mRights = $rights;
+               $this->overrideUserPermissions( $user, $rights );
                try {
                        $this->doApiRequest( [
                                'action' => 'query',
@@ -412,6 +413,7 @@ class ApiMainTest extends ApiTestCase {
                        $this->assertTrue( self::apiExceptionHasCode( $e, $error ),
                                "Error '{$e->getMessage()}' matched expected '$error'" );
                }
+               $this->overrideMwServices();
        }
 
        /**
@@ -704,6 +706,7 @@ class ApiMainTest extends ApiTestCase {
                        'You need read permission to use this module.' );
 
                $this->setGroupPermissions( '*', 'read', false );
+               $this->overrideMwServices();
 
                $main = new ApiMain( new FauxRequest( [ 'action' => 'query', 'meta' => 'siteinfo' ] ) );
                $main->execute();
@@ -727,6 +730,7 @@ class ApiMainTest extends ApiTestCase {
                $this->setExpectedException( ApiUsageException::class,
                        "You're not allowed to edit this wiki through the API." );
                $this->setGroupPermissions( '*', 'writeapi', false );
+               $this->overrideMwServices();
 
                $main = new ApiMain( new FauxRequest( [
                        'action' => 'edit',
index d880923..04a4d8f 100644 (file)
@@ -212,6 +212,7 @@ class ApiMoveTest extends ApiTestCase {
                ChangeTags::defineTag( 'custom tag' );
 
                $this->setGroupPermissions( 'user', 'applychangetags', false );
+               $this->overrideMwServices();
 
                $id = $this->createPage( $name );
 
@@ -294,6 +295,7 @@ class ApiMoveTest extends ApiTestCase {
                $name = ucfirst( __FUNCTION__ );
 
                $this->mergeMwGlobalArrayValue( 'wgNamespacesWithSubpages', [ NS_MAIN => true ] );
+               $this->overrideMwServices();
 
                $pages = [ $name, "$name/1", "$name/2", "Talk:$name", "Talk:$name/1", "Talk:$name/3" ];
                $ids = [];
@@ -379,6 +381,7 @@ class ApiMoveTest extends ApiTestCase {
                $name = ucfirst( __FUNCTION__ );
 
                $this->setGroupPermissions( 'sysop', 'suppressredirect', false );
+               $this->overrideMwServices();
 
                $id = $this->createPage( $name );
 
index 0011d7a..9c5268c 100644 (file)
@@ -206,6 +206,7 @@ class ApiParseTest extends ApiTestCase {
 
        public function testSuppressed() {
                $this->setGroupPermissions( 'sysop', 'viewsuppressed', true );
+               $this->overrideMwServices();
 
                $res = $this->doApiRequest( [
                        'action' => 'parse',
index c6ed8a7..2d627bf 100644 (file)
@@ -307,6 +307,7 @@ class ApiStashEditTest extends ApiTestCase {
 
                // Nor does the original one if they become a bot
                $user->addGroup( 'bot' );
+               MediaWikiServices::getInstance()->getPermissionManager()->invalidateUsersRightsCache();
                $this->assertFalse(
                        $this->doCheckCache( $user ),
                        "We assume bots don't have cache entries"
@@ -315,6 +316,7 @@ class ApiStashEditTest extends ApiTestCase {
                // But other groups are okay
                $user->removeGroup( 'bot' );
                $user->addGroup( 'sysop' );
+               MediaWikiServices::getInstance()->getPermissionManager()->invalidateUsersRightsCache();
                $this->assertInstanceOf( stdClass::class, $this->doCheckCache( $user ) );
        }
 
index a1754fa..18299da 100644 (file)
@@ -89,6 +89,7 @@ class ApiUnblockTest extends ApiTestCase {
                $this->setExpectedApiException( 'apierror-permissiondenied-unblock' );
 
                $this->setGroupPermissions( 'sysop', 'block', false );
+               $this->overrideMwServices();
 
                $this->doUnblock();
        }
@@ -141,6 +142,7 @@ class ApiUnblockTest extends ApiTestCase {
                ChangeTags::defineTag( 'custom tag' );
 
                $this->setGroupPermissions( 'user', 'applychangetags', false );
+               $this->overrideMwServices();
 
                $this->doUnblock( [ 'tags' => 'custom tag' ] );
        }
index a1bafed..ce2d8c8 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 
 use MediaWiki\Block\DatabaseBlock;
+use MediaWiki\MediaWikiServices;
 
 /**
  * @group API
@@ -36,6 +37,8 @@ class ApiUserrightsTest extends ApiTestCase {
                if ( $remove ) {
                        $this->mergeMwGlobalArrayValue( 'wgRemoveGroups', [ 'bureaucrat' => $remove ] );
                }
+
+               $this->overrideMwServices();
        }
 
        /**
@@ -75,6 +78,7 @@ class ApiUserrightsTest extends ApiTestCase {
                $res = $this->doApiRequestWithToken( $params );
 
                $user->clearInstanceCache();
+               MediaWikiServices::getInstance()->getPermissionManager()->invalidateUsersRightsCache();
                $this->assertSame( $expectedGroups, $user->getGroups() );
 
                $this->assertArrayNotHasKey( 'warnings', $res[0] );
@@ -217,6 +221,7 @@ class ApiUserrightsTest extends ApiTestCase {
                ChangeTags::defineTag( 'custom tag' );
 
                $this->setGroupPermissions( 'user', 'applychangetags', false );
+               $this->overrideMwServices();
 
                $this->doFailedRightsChange(
                        'You do not have permission to apply change tags along with your changes.',
index e6a1d38..ea45b19 100644 (file)
@@ -1420,6 +1420,7 @@ class AuthManagerTest extends \MediaWikiTestCase {
                $readOnlyMode->setReason( false );
 
                $this->setGroupPermissions( '*', 'createaccount', false );
+               $this->overrideMwServices();
                $status = $this->manager->checkAccountCreatePermissions( new \User );
                $this->assertFalse( $status->isOK() );
                $this->assertTrue( $status->hasMessage( 'badaccess-groups' ) );
@@ -1446,6 +1447,7 @@ class AuthManagerTest extends \MediaWikiTestCase {
                ];
                $block = new DatabaseBlock( $blockOptions );
                $block->insert();
+               $this->overrideMwServices();
                $status = $this->manager->checkAccountCreatePermissions( $user );
                $this->assertFalse( $status->isOK() );
                $this->assertTrue( $status->hasMessage( 'cantcreateaccount-text' ) );
@@ -2365,6 +2367,8 @@ class AuthManagerTest extends \MediaWikiTestCase {
                $this->mergeMwGlobalArrayValue( 'wgObjectCaches',
                        [ __METHOD__ => [ 'class' => 'HashBagOStuff' ] ] );
                $this->setMwGlobals( [ 'wgMainCacheType' => __METHOD__ ] );
+               // Supply services with updated globals
+               $this->overrideMwServices();
 
                // Set up lots of mocks...
                $mocks = [];
@@ -2549,6 +2553,7 @@ class AuthManagerTest extends \MediaWikiTestCase {
                // IP unable to create accounts
                $this->setGroupPermissions( '*', 'createaccount', false );
                $this->setGroupPermissions( '*', 'autocreateaccount', false );
+               $this->overrideMwServices();
                $session->clear();
                $user = \User::newFromName( $username );
                $this->hook( 'LocalUserCreated', $this->never() );
@@ -2585,6 +2590,7 @@ class AuthManagerTest extends \MediaWikiTestCase {
                $session->clear();
                $user = \User::newFromName( $username );
                $this->hook( 'LocalUserCreated', $this->never() );
+               $this->overrideMwServices();
                $ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, true );
                $this->unhook( 'LocalUserCreated' );
                $this->assertEquals( \Status::newFatal( 'ok' ), $ret );
index 34b2525..5c5ce5c 100644 (file)
@@ -4,6 +4,7 @@
  * @group Database
  */
 class ArticleTablesTest extends MediaWikiLangTestCase {
+
        /**
         * Make sure that T16404 doesn't strike again. We don't want
         * templatelinks based on the user language when {{int:}} is used, only the
@@ -16,7 +17,7 @@ class ArticleTablesTest extends MediaWikiLangTestCase {
                $title = Title::newFromText( 'T16404' );
                $page = WikiPage::factory( $title );
                $user = new User();
-               $user->mRights = [ 'createpage', 'edit', 'purge' ];
+               $this->overrideUserPermissions( $user, [ 'createpage', 'edit', 'purge' ] );
                $this->setContentLang( 'es' );
                $this->setUserLang( 'fr' );
 
index 3a3feee..ee6c227 100644 (file)
@@ -1374,6 +1374,7 @@ more stuff
 
                // Now, try the rollback
                $admin->addGroup( 'sysop' ); // Make the test user a sysop
+               MediaWikiServices::getInstance()->getPermissionManager()->invalidateUsersRightsCache();
                $token = $admin->getEditToken( 'rollback' );
                $errors = $page->doRollback(
                        $secondUser->getName(),
index e38d77b..9f45c02 100644 (file)
@@ -13,6 +13,7 @@ class LocalIdLookupTest extends MediaWikiTestCase {
                parent::setUp();
 
                $this->setGroupPermissions( 'local-id-lookup-test', 'hideuser', true );
+               $this->overrideMwServices();
        }
 
        public function addDBData() {
index 4862747..1dc282c 100644 (file)
@@ -46,6 +46,8 @@ class UserGroupMembershipTest extends MediaWikiTestCase {
                $this->userTester->addGroup( 'unittesters' );
                $this->expiryTime = wfTimestamp( TS_MW, time() + 100500 );
                $this->userTester->addGroup( 'testwriters', $this->expiryTime );
+
+               $this->overrideMwServices();
        }
 
        /**
index aa6ae48..2379bc2 100644 (file)
@@ -124,7 +124,7 @@ class UserTest extends MediaWikiTestCase {
                        $rights = array_diff( $rights, [ 'writetest' ] );
                } ] ] );
 
-               $userWrapper->mRights = null;
+               $this->overrideMwServices();
                $rights = $user->getRights();
                $this->assertContains( 'test', $rights );
                $this->assertContains( 'runtest', $rights );
@@ -146,7 +146,7 @@ class UserTest extends MediaWikiTestCase {
                $mockRequest->method( 'getSession' )->willReturn( $session );
                $userWrapper->mRequest = $mockRequest;
 
-               $userWrapper->mRights = null;
+               $this->overrideMwServices();
                $rights = $user->getRights();
                $this->assertContains( 'test', $rights );
                $this->assertNotContains( 'runtest', $rights );
@@ -924,9 +924,11 @@ class UserTest extends MediaWikiTestCase {
 
                $this->setMwGlobals( 'wgRateLimitsExcludedIPs', [] );
                $noRateLimitUser = $this->getMockBuilder( User::class )->disableOriginalConstructor()
-                       ->setMethods( [ 'getIP', 'getRights' ] )->getMock();
+                       ->setMethods( [ 'getIP', 'getId', 'getGroups' ] )->getMock();
                $noRateLimitUser->expects( $this->any() )->method( 'getIP' )->willReturn( '1.2.3.4' );
-               $noRateLimitUser->expects( $this->any() )->method( 'getRights' )->willReturn( [ 'noratelimit' ] );
+               $noRateLimitUser->expects( $this->any() )->method( 'getId' )->willReturn( 0 );
+               $noRateLimitUser->expects( $this->any() )->method( 'getGroups' )->willReturn( [] );
+               $this->overrideUserPermissions( $noRateLimitUser, 'noratelimit' );
                $this->assertFalse( $noRateLimitUser->isPingLimitable() );
        }