Merge "Introduce User::INVALID_TOKEN"
[lhc/web/wiklou.git] / includes / session / SessionManager.php
index 1c8686c..f03260f 100644 (file)
@@ -25,6 +25,7 @@ namespace MediaWiki\Session;
 
 use Psr\Log\LoggerInterface;
 use BagOStuff;
+use CachedBagOStuff;
 use Config;
 use FauxRequest;
 use Language;
@@ -54,7 +55,7 @@ final class SessionManager implements SessionManagerInterface {
        /** @var Config */
        private $config;
 
-       /** @var BagOStuff|null */
+       /** @var CachedBagOStuff|null */
        private $store;
 
        /** @var SessionProvider[] */
@@ -123,7 +124,8 @@ final class SessionManager implements SessionManagerInterface {
                                // Someone used session_id(), so we need to follow suit.
                                // Note this overwrites whatever session might already be
                                // associated with $request with the one for $id.
-                               self::$globalSession = self::singleton()->getSessionById( $id, false, $request );
+                               self::$globalSession = self::singleton()->getSessionById( $id, true, $request )
+                                       ?: $request->getSession();
                        }
                }
                return self::$globalSession;
@@ -164,11 +166,12 @@ final class SessionManager implements SessionManagerInterface {
                                        '$options[\'store\'] must be an instance of BagOStuff'
                                );
                        }
-                       $this->store = $options['store'];
+                       $store = $options['store'];
                } else {
-                       $this->store = \ObjectCache::getInstance( $this->config->get( 'SessionCacheType' ) );
-                       $this->store->setLogger( $this->logger );
+                       $store = \ObjectCache::getInstance( $this->config->get( 'SessionCacheType' ) );
+                       $store->setLogger( $this->logger );
                }
+               $this->store = $store instanceof CachedBagOStuff ? $store : new CachedBagOStuff( $store );
 
                register_shutdown_function( array( $this, 'shutdown' ) );
        }
@@ -177,15 +180,6 @@ final class SessionManager implements SessionManagerInterface {
                $this->logger = $logger;
        }
 
-       public function getPersistedSessionId( WebRequest $request ) {
-               $info = $this->getSessionInfoForRequest( $request );
-               if ( $info && $info->wasPersisted() ) {
-                       return $info->getId();
-               } else {
-                       return null;
-               }
-       }
-
        public function getSessionForRequest( WebRequest $request ) {
                $info = $this->getSessionInfoForRequest( $request );
 
@@ -197,7 +191,7 @@ final class SessionManager implements SessionManagerInterface {
                return $session;
        }
 
-       public function getSessionById( $id, $noEmpty = false, WebRequest $request = null ) {
+       public function getSessionById( $id, $create = false, WebRequest $request = null ) {
                if ( !self::validateSessionId( $id ) ) {
                        throw new \InvalidArgumentException( 'Invalid session ID' );
                }
@@ -217,7 +211,7 @@ final class SessionManager implements SessionManagerInterface {
                        }
                }
 
-               if ( !$noEmpty && $session === null ) {
+               if ( $create && $session === null ) {
                        $ex = null;
                        try {
                                $session = $this->getEmptySessionInternal( $request, $id );
@@ -226,11 +220,6 @@ final class SessionManager implements SessionManagerInterface {
                                        $ex->getMessage() );
                                $session = null;
                        }
-                       if ( $session === null ) {
-                               throw new \UnexpectedValueException(
-                                       'Can neither load the session nor create an empty session', 0, $ex
-                               );
-                       }
                }
 
                return $session;
@@ -496,10 +485,20 @@ final class SessionManager implements SessionManagerInterface {
                        // @codeCoverageIgnoreEnd
                }
 
+               # Notify AuthPlugin
+               $tmpUser = $user;
+               $wgAuth->initUser( $tmpUser, true );
+               if ( $tmpUser !== $user ) {
+                       $logger->warning( __METHOD__ . ': ' .
+                               get_class( $wgAuth ) . '::initUser() replaced the user object' );
+               }
+
                # Notify hooks (e.g. Newuserlog)
                \Hooks::run( 'AuthPluginAutoCreate', array( $user ) );
                \Hooks::run( 'LocalUserCreated', array( $user, true ) );
 
+               $user->saveSettings();
+
                # Update user count
                \DeferredUpdates::addUpdate( new \SiteStatsUpdate( 0, 0, 0, 0, 1 ) );
 
@@ -521,13 +520,6 @@ final class SessionManager implements SessionManagerInterface {
        public function preventSessionsForUser( $username ) {
                $this->preventUsers[$username] = true;
 
-               // Reset the user's token to kill existing sessions
-               $user = User::newFromName( $username );
-               if ( $user && $user->getToken() ) {
-                       $user->setToken( true );
-                       $user->saveSettings();
-               }
-
                // Instruct the session providers to kill any other sessions too.
                foreach ( $this->getProviders() as $provider ) {
                        $provider->preventSessionsForUser( $username );
@@ -662,7 +654,8 @@ final class SessionManager implements SessionManagerInterface {
         * @return bool Whether the session info matches the stored data (if any)
         */
        private function loadSessionInfoFromStore( SessionInfo &$info, WebRequest $request ) {
-               $blob = $this->store->get( wfMemcKey( 'MWSession', $info->getId() ) );
+               $key = wfMemcKey( 'MWSession', $info->getId() );
+               $blob = $this->store->get( $key );
 
                $newParams = array();
 
@@ -670,6 +663,7 @@ final class SessionManager implements SessionManagerInterface {
                        // Sanity check: blob must be an array, if it's saved at all
                        if ( !is_array( $blob ) ) {
                                $this->logger->warning( "Session $info: Bad data" );
+                               $this->store->delete( $key );
                                return false;
                        }
 
@@ -678,6 +672,7 @@ final class SessionManager implements SessionManagerInterface {
                                !isset( $blob['metadata'] ) || !is_array( $blob['metadata'] )
                        ) {
                                $this->logger->warning( "Session $info: Bad data structure" );
+                               $this->store->delete( $key );
                                return false;
                        }
 
@@ -692,6 +687,7 @@ final class SessionManager implements SessionManagerInterface {
                                !array_key_exists( 'provider', $metadata )
                        ) {
                                $this->logger->warning( "Session $info: Bad metadata" );
+                               $this->store->delete( $key );
                                return false;
                        }
 
@@ -701,6 +697,7 @@ final class SessionManager implements SessionManagerInterface {
                                $newParams['provider'] = $provider = $this->getProvider( $metadata['provider'] );
                                if ( !$provider ) {
                                        $this->logger->warning( "Session $info: Unknown provider, " . $metadata['provider'] );
+                                       $this->store->delete( $key );
                                        return false;
                                }
                        } elseif ( $metadata['provider'] !== (string)$provider ) {
@@ -799,6 +796,9 @@ final class SessionManager implements SessionManagerInterface {
                        if ( !empty( $metadata['forceHTTPS'] ) && !$info->forceHTTPS() ) {
                                $newParams['forceHTTPS'] = true;
                        }
+                       if ( !empty( $metadata['persisted'] ) && !$info->wasPersisted() ) {
+                               $newParams['persisted'] = true;
+                       }
 
                        if ( !$info->isIdSafe() ) {
                                $newParams['idIsSafe'] = true;