/**
* This serves as the entry point to the MediaWiki session handling system.
*
+ * Most methods here are for internal use by session handling code. Other callers
+ * should only use getGlobalSession and the methods of SessionManagerInterface;
+ * the rest of the functionality is exposed via MediaWiki\Session\Session methods.
+ *
+ * To provide custom session handling, implement a MediaWiki\Session\SessionProvider.
+ *
* @ingroup Session
* @since 1.27
+ * @see https://www.mediawiki.org/wiki/Manual:SessionManager_and_AuthManager
*/
final class SessionManager implements SessionManagerInterface {
/** @var SessionManager|null */
* @deprecated since 1.27, use MediaWiki\Auth\AuthManager::autoCreateUser instead
* @param User $user User to auto-create
* @return bool Success
+ * @codeCoverageIgnore
*/
public static function autoCreateUser( User $user ) {
- global $wgAuth, $wgDisableAuthManager;
-
- // @codeCoverageIgnoreStart
- if ( !$wgDisableAuthManager ) {
- wfDeprecated( __METHOD__, '1.27' );
- return \MediaWiki\Auth\AuthManager::singleton()->autoCreateUser(
- $user,
- \MediaWiki\Auth\AuthManager::AUTOCREATE_SOURCE_SESSSION,
- false
- )->isGood();
- }
- // @codeCoverageIgnoreEnd
-
- $logger = self::singleton()->logger;
-
- // Much of this code is based on that in CentralAuth
-
- // Try the local user from the slave DB
- $localId = User::idFromName( $user->getName() );
- $flags = 0;
-
- // Fetch the user ID from the master, so that we don't try to create the user
- // when they already exist, due to replication lag
- // @codeCoverageIgnoreStart
- if ( !$localId && wfGetLB()->getReaderIndex() != 0 ) {
- $localId = User::idFromName( $user->getName(), User::READ_LATEST );
- $flags = User::READ_LATEST;
- }
- // @codeCoverageIgnoreEnd
-
- if ( $localId ) {
- // User exists after all.
- $user->setId( $localId );
- $user->loadFromId( $flags );
- return false;
- }
-
- // Denied by AuthPlugin? But ignore AuthPlugin itself.
- if ( get_class( $wgAuth ) !== 'AuthPlugin' && !$wgAuth->autoCreate() ) {
- $logger->debug( __METHOD__ . ': denied by AuthPlugin' );
- $user->setId( 0 );
- $user->loadFromId();
- return false;
- }
-
- // Wiki is read-only?
- if ( wfReadOnly() ) {
- $logger->debug( __METHOD__ . ': denied by wfReadOnly()' );
- $user->setId( 0 );
- $user->loadFromId();
- return false;
- }
-
- $userName = $user->getName();
-
- // Check the session, if we tried to create this user already there's
- // no point in retrying.
- $session = self::getGlobalSession();
- $reason = $session->get( 'MWSession::AutoCreateBlacklist' );
- if ( $reason ) {
- $logger->debug( __METHOD__ . ": blacklisted in session ($reason)" );
- $user->setId( 0 );
- $user->loadFromId();
- return false;
- }
-
- // Is the IP user able to create accounts?
- $anon = new User;
- if ( !$anon->isAllowedAny( 'createaccount', 'autocreateaccount' )
- || $anon->isBlockedFromCreateAccount()
- ) {
- // Blacklist the user to avoid repeated DB queries subsequently
- $logger->debug( __METHOD__ . ': user is blocked from this wiki, blacklisting' );
- $session->set( 'MWSession::AutoCreateBlacklist', 'blocked', 600 );
- $session->persist();
- $user->setId( 0 );
- $user->loadFromId();
- return false;
- }
-
- // Check for validity of username
- if ( !User::isCreatableName( $userName ) ) {
- $logger->debug( __METHOD__ . ': Invalid username, blacklisting' );
- $session->set( 'MWSession::AutoCreateBlacklist', 'invalid username', 600 );
- $session->persist();
- $user->setId( 0 );
- $user->loadFromId();
- return false;
- }
-
- // Give other extensions a chance to stop auto creation.
- $user->loadDefaults( $userName );
- $abortMessage = '';
- if ( !\Hooks::run( 'AbortAutoAccount', [ $user, &$abortMessage ] ) ) {
- // In this case we have no way to return the message to the user,
- // but we can log it.
- $logger->debug( __METHOD__ . ": denied by hook: $abortMessage" );
- $session->set( 'MWSession::AutoCreateBlacklist', "hook aborted: $abortMessage", 600 );
- $session->persist();
- $user->setId( 0 );
- $user->loadFromId();
- return false;
- }
-
- // Make sure the name has not been changed
- if ( $user->getName() !== $userName ) {
- $user->setId( 0 );
- $user->loadFromId();
- throw new \UnexpectedValueException(
- 'AbortAutoAccount hook tried to change the user name'
- );
- }
-
- // Ignore warnings about master connections/writes...hard to avoid here
- \Profiler::instance()->getTransactionProfiler()->resetExpectations();
-
- $cache = \ObjectCache::getLocalClusterInstance();
- $backoffKey = wfMemcKey( 'MWSession', 'autocreate-failed', md5( $userName ) );
- if ( $cache->get( $backoffKey ) ) {
- $logger->debug( __METHOD__ . ': denied by prior creation attempt failures' );
- $user->setId( 0 );
- $user->loadFromId();
- return false;
- }
-
- // Checks passed, create the user...
- $from = isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : 'CLI';
- $logger->info( __METHOD__ . ': creating new user ({username}) - from: {url}',
- [
- 'username' => $userName,
- 'url' => $from,
- ] );
-
- try {
- // Insert the user into the local DB master
- $status = $user->addToDatabase();
- if ( !$status->isOK() ) {
- // @codeCoverageIgnoreStart
- // double-check for a race condition (T70012)
- $id = User::idFromName( $user->getName(), User::READ_LATEST );
- if ( $id ) {
- $logger->info( __METHOD__ . ': tried to autocreate existing user',
- [
- 'username' => $userName,
- ] );
- } else {
- $logger->error(
- __METHOD__ . ': failed with message ' . $status->getWikiText( false, false, 'en' ),
- [
- 'username' => $userName,
- ]
- );
- }
- $user->setId( $id );
- $user->loadFromId( User::READ_LATEST );
- return false;
- // @codeCoverageIgnoreEnd
- }
- } catch ( \Exception $ex ) {
- // @codeCoverageIgnoreStart
- $logger->error( __METHOD__ . ': failed with exception {exception}', [
- 'exception' => $ex,
- 'username' => $userName,
- ] );
- // Do not keep throwing errors for a while
- $cache->set( $backoffKey, 1, 600 );
- // Bubble up error; which should normally trigger DB rollbacks
- throw $ex;
- // @codeCoverageIgnoreEnd
- }
-
- # Notify AuthPlugin
- // @codeCoverageIgnoreStart
- $tmpUser = $user;
- $wgAuth->initUser( $tmpUser, true );
- if ( $tmpUser !== $user ) {
- $logger->warning( __METHOD__ . ': ' .
- get_class( $wgAuth ) . '::initUser() replaced the user object' );
- }
- // @codeCoverageIgnoreEnd
-
- # Notify hooks (e.g. Newuserlog)
- \Hooks::run( 'AuthPluginAutoCreate', [ $user ] );
- \Hooks::run( 'LocalUserCreated', [ $user, true ] );
-
- $user->saveSettings();
-
- # Update user count
- \DeferredUpdates::addUpdate( new \SiteStatsUpdate( 0, 0, 0, 0, 1 ) );
-
- # Watch user's userpage and talk page
- $user->addWatch( $user->getUserPage(), User::IGNORE_USER_RIGHTS );
-
- return true;
+ wfDeprecated( __METHOD__, '1.27' );
+ return \MediaWiki\Auth\AuthManager::singleton()->autoCreateUser(
+ $user,
+ \MediaWiki\Auth\AuthManager::AUTOCREATE_SOURCE_SESSION,
+ false
+ )->isGood();
}
/**
}
/**
- * Create a session corresponding to the passed SessionInfo
+ * Create a Session corresponding to the passed SessionInfo
* @private For use by a SessionProvider that needs to specially create its
- * own session.
+ * own Session. Most session providers won't need this.
* @param SessionInfo $info
* @param WebRequest $request
* @return Session
$session->resetId();
}
- \ScopedCallback::consume( $delay );
+ \Wikimedia\ScopedCallback::consume( $delay );
return $session;
}
/**
* Reset the internal caching for unit testing
+ * @protected Unit tests only
*/
public static function resetCache() {
if ( !defined( 'MW_PHPUNIT_TEST' ) ) {