auth: Use IConnectionProvider instead of LoadBalancer

Bug: T330641
Change-Id: Ia0722050b66f1d4919dc5f99da0c77cc98f35d92
This commit is contained in:
Amir Sarabadani 2023-04-25 13:37:41 +02:00 committed by Lucas Werkmeister
parent c40084e898
commit c05c261491
12 changed files with 79 additions and 49 deletions

View file

@ -28,6 +28,12 @@ For notes on 1.40.x and older releases, see HISTORY.
* …
==== Changed configuration ====
* $wgAuthManagerAutoConfig When using this setting to modify the
authentication system in MediaWiki, the classes
TemporaryPasswordPrimaryAuthenticationProvider,
LocalPasswordPrimaryAuthenticationProvider and
EmailNotificationSecondaryAuthenticationProvider now require
DBLoadBalancerFactory, not DBLoadBalancer, as a service.
* …
==== Removed configuration ====

View file

@ -4376,8 +4376,8 @@ config-schema:
AuthManagerAutoConfig:
default:
preauth: { MediaWiki\Auth\ThrottlePreAuthenticationProvider: { class: MediaWiki\Auth\ThrottlePreAuthenticationProvider, sort: 0 } }
primaryauth: { MediaWiki\Auth\TemporaryPasswordPrimaryAuthenticationProvider: { class: MediaWiki\Auth\TemporaryPasswordPrimaryAuthenticationProvider, services: [DBLoadBalancer, UserOptionsLookup], args: [{ authoritative: false }], sort: 0 }, MediaWiki\Auth\LocalPasswordPrimaryAuthenticationProvider: { class: MediaWiki\Auth\LocalPasswordPrimaryAuthenticationProvider, services: [DBLoadBalancer], args: [{ authoritative: true }], sort: 100 } }
secondaryauth: { MediaWiki\Auth\CheckBlocksSecondaryAuthenticationProvider: { class: MediaWiki\Auth\CheckBlocksSecondaryAuthenticationProvider, sort: 0 }, MediaWiki\Auth\ResetPasswordSecondaryAuthenticationProvider: { class: MediaWiki\Auth\ResetPasswordSecondaryAuthenticationProvider, sort: 100 }, MediaWiki\Auth\EmailNotificationSecondaryAuthenticationProvider: { class: MediaWiki\Auth\EmailNotificationSecondaryAuthenticationProvider, services: [DBLoadBalancer], sort: 200 } }
primaryauth: { MediaWiki\Auth\TemporaryPasswordPrimaryAuthenticationProvider: { class: MediaWiki\Auth\TemporaryPasswordPrimaryAuthenticationProvider, services: [DBLoadBalancerFactory, UserOptionsLookup], args: [{ authoritative: false }], sort: 0 }, MediaWiki\Auth\LocalPasswordPrimaryAuthenticationProvider: { class: MediaWiki\Auth\LocalPasswordPrimaryAuthenticationProvider, services: [DBLoadBalancerFactory], args: [{ authoritative: true }], sort: 100 } }
secondaryauth: { MediaWiki\Auth\CheckBlocksSecondaryAuthenticationProvider: { class: MediaWiki\Auth\CheckBlocksSecondaryAuthenticationProvider, sort: 0 }, MediaWiki\Auth\ResetPasswordSecondaryAuthenticationProvider: { class: MediaWiki\Auth\ResetPasswordSecondaryAuthenticationProvider, sort: 100 }, MediaWiki\Auth\EmailNotificationSecondaryAuthenticationProvider: { class: MediaWiki\Auth\EmailNotificationSecondaryAuthenticationProvider, services: [DBLoadBalancerFactory], sort: 200 } }
type: object
mergeStrategy: array_plus_2d
description: |-

View file

@ -6888,7 +6888,7 @@ class MainConfigSchema {
\MediaWiki\Auth\TemporaryPasswordPrimaryAuthenticationProvider::class => [
'class' => \MediaWiki\Auth\TemporaryPasswordPrimaryAuthenticationProvider::class,
'services' => [
'DBLoadBalancer',
'DBLoadBalancerFactory',
'UserOptionsLookup',
],
'args' => [ [
@ -6900,7 +6900,7 @@ class MainConfigSchema {
\MediaWiki\Auth\LocalPasswordPrimaryAuthenticationProvider::class => [
'class' => \MediaWiki\Auth\LocalPasswordPrimaryAuthenticationProvider::class,
'services' => [
'DBLoadBalancer',
'DBLoadBalancerFactory',
],
'args' => [ [
// Last one should be authoritative, or else the user will get
@ -6929,7 +6929,7 @@ class MainConfigSchema {
\MediaWiki\Auth\EmailNotificationSecondaryAuthenticationProvider::class => [
'class' => \MediaWiki\Auth\EmailNotificationSecondaryAuthenticationProvider::class,
'services' => [
'DBLoadBalancer',
'DBLoadBalancerFactory',
],
'sort' => 200,
],

View file

@ -3,7 +3,7 @@
namespace MediaWiki\Auth;
use MediaWiki\MainConfigNames;
use Wikimedia\Rdbms\ILoadBalancer;
use Wikimedia\Rdbms\IConnectionProvider;
/**
* Handles email notification / email address confirmation for account creation.
@ -17,20 +17,20 @@ class EmailNotificationSecondaryAuthenticationProvider
/** @var bool */
protected $sendConfirmationEmail;
/** @var ILoadBalancer */
private $loadBalancer;
/** @var IConnectionProvider */
private $dbProvider;
/**
* @param ILoadBalancer $loadBalancer
* @param IConnectionProvider $dbProvider
* @param array $params
* - sendConfirmationEmail: (bool) send an email asking the user to confirm their email
* address after a successful registration
*/
public function __construct( ILoadBalancer $loadBalancer, $params = [] ) {
public function __construct( IConnectionProvider $dbProvider, $params = [] ) {
if ( isset( $params['sendConfirmationEmail'] ) ) {
$this->sendConfirmationEmail = (bool)$params['sendConfirmationEmail'];
}
$this->loadBalancer = $loadBalancer;
$this->dbProvider = $dbProvider;
}
protected function postInitSetup() {
@ -53,7 +53,7 @@ class EmailNotificationSecondaryAuthenticationProvider
&& !$this->manager->getAuthenticationSessionData( 'no-email' )
) {
// TODO show 'confirmemail_oncreate'/'confirmemail_sendfailed' message
$this->loadBalancer->getConnectionRef( DB_PRIMARY )->onTransactionCommitOrIdle(
$this->dbProvider->getPrimaryDatabase()->onTransactionCommitOrIdle(
function () use ( $user ) {
$user = $user->getInstanceForUpdate();
$status = $user->sendConfirmationMail();

View file

@ -24,7 +24,7 @@ namespace MediaWiki\Auth;
use MediaWiki\MainConfigNames;
use MediaWiki\User\UserRigorOptions;
use User;
use Wikimedia\Rdbms\ILoadBalancer;
use Wikimedia\Rdbms\IConnectionProvider;
/**
* A primary authentication provider that uses the password field in the 'user' table.
@ -38,20 +38,20 @@ class LocalPasswordPrimaryAuthenticationProvider
/** @var bool If true, this instance is for legacy logins only. */
protected $loginOnly = false;
/** @var ILoadBalancer */
private $loadBalancer;
/** @var IConnectionProvider */
private $dbProvider;
/**
* @param ILoadBalancer $loadBalancer
* @param IConnectionProvider $dbProvider
* @param array $params Settings
* - loginOnly: If true, the local passwords are for legacy logins only:
* the local password will be invalidated when authentication is changed
* and new users will not have a valid local password set.
*/
public function __construct( ILoadBalancer $loadBalancer, $params = [] ) {
public function __construct( IConnectionProvider $dbProvider, $params = [] ) {
parent::__construct( $params );
$this->loginOnly = !empty( $params['loginOnly'] );
$this->loadBalancer = $loadBalancer;
$this->dbProvider = $dbProvider;
}
/**
@ -100,7 +100,7 @@ class LocalPasswordPrimaryAuthenticationProvider
return AuthenticationResponse::newAbstain();
}
$row = $this->loadBalancer->getConnection( DB_REPLICA )->newSelectQueryBuilder()
$row = $this->dbProvider->getReplicaDatabase()->newSelectQueryBuilder()
->select( [ 'user_id', 'user_password', 'user_password_expires' ] )
->from( 'user' )
->where( [ 'user_name' => $username ] )
@ -144,7 +144,7 @@ class LocalPasswordPrimaryAuthenticationProvider
$newHash = $this->getPasswordFactory()->newFromPlaintext( $req->password );
$fname = __METHOD__;
\DeferredUpdates::addCallableUpdate( function () use ( $newHash, $oldRow, $fname ) {
$dbw = $this->loadBalancer->getConnectionRef( DB_PRIMARY );
$dbw = $this->dbProvider->getPrimaryDatabase();
$dbw->update(
'user',
[ 'user_password' => $newHash->toString() ],
@ -170,7 +170,7 @@ class LocalPasswordPrimaryAuthenticationProvider
return false;
}
$row = $this->loadBalancer->getConnection( DB_REPLICA )->newSelectQueryBuilder()
$row = $this->dbProvider->getReplicaDatabase()->newSelectQueryBuilder()
->select( [ 'user_password' ] )
->from( 'user' )
->where( [ 'user_name' => $username ] )
@ -195,8 +195,9 @@ class LocalPasswordPrimaryAuthenticationProvider
return false;
}
[ $db, $options ] = \DBAccessObjectUtils::getDBOptions( $flags );
return (bool)$this->loadBalancer->getConnection( $db )->newSelectQueryBuilder()
[ $mode, $options ] = \DBAccessObjectUtils::getDBOptions( $flags );
$db = \DBAccessObjectUtils::getDBFromIndex( $this->dbProvider, $mode );
return (bool)$db->newSelectQueryBuilder()
->select( [ 'user_id' ] )
->from( 'user' )
->where( [ 'user_name' => $username ] )
@ -221,7 +222,7 @@ class LocalPasswordPrimaryAuthenticationProvider
$username = $this->userNameUtils->getCanonical( $req->username,
UserRigorOptions::RIGOR_USABLE );
if ( $username !== false ) {
$row = $this->loadBalancer->getConnection( DB_PRIMARY )->newSelectQueryBuilder()
$row = $this->dbProvider->getPrimaryDatabase()->newSelectQueryBuilder()
->select( [ 'user_id' ] )
->from( 'user' )
->where( [ 'user_name' => $username ] )
@ -264,7 +265,7 @@ class LocalPasswordPrimaryAuthenticationProvider
}
if ( $pwhash ) {
$dbw = $this->loadBalancer->getConnectionRef( DB_PRIMARY );
$dbw = $this->dbProvider->getPrimaryDatabase();
$dbw->update(
'user',
[

View file

@ -28,7 +28,7 @@ use MediaWiki\User\UserRigorOptions;
use SpecialPage;
use User;
use Wikimedia\IPUtils;
use Wikimedia\Rdbms\ILoadBalancer;
use Wikimedia\Rdbms\IConnectionProvider;
/**
* A primary authentication provider that uses the temporary password field in
@ -56,14 +56,14 @@ class TemporaryPasswordPrimaryAuthenticationProvider
/** @var bool */
protected $allowRequiringEmail = null;
/** @var ILoadBalancer */
private $loadBalancer;
/** @var IConnectionProvider */
private $dbProvider;
/** @var UserOptionsLookup */
private $userOptionsLookup;
/**
* @param ILoadBalancer $loadBalancer
* @param IConnectionProvider $dbProvider
* @param UserOptionsLookup $userOptionsLookup
* @param array $params
* - emailEnabled: (bool) must be true for the option to email passwords to be present
@ -72,7 +72,7 @@ class TemporaryPasswordPrimaryAuthenticationProvider
* be sent to the same user again
*/
public function __construct(
ILoadBalancer $loadBalancer,
IConnectionProvider $dbProvider,
UserOptionsLookup $userOptionsLookup,
$params = []
) {
@ -90,7 +90,7 @@ class TemporaryPasswordPrimaryAuthenticationProvider
if ( isset( $params['allowRequiringEmailForResets'] ) ) {
$this->allowRequiringEmail = $params['allowRequiringEmailForResets'];
}
$this->loadBalancer = $loadBalancer;
$this->dbProvider = $dbProvider;
$this->userOptionsLookup = $userOptionsLookup;
}
@ -149,7 +149,7 @@ class TemporaryPasswordPrimaryAuthenticationProvider
return AuthenticationResponse::newAbstain();
}
$row = $this->loadBalancer->getConnection( DB_REPLICA )->newSelectQueryBuilder()
$row = $this->dbProvider->getReplicaDatabase()->newSelectQueryBuilder()
->select( [ 'user_id', 'user_newpassword', 'user_newpass_time' ] )
->from( 'user' )
->where( [ 'user_name' => $username ] )
@ -194,7 +194,7 @@ class TemporaryPasswordPrimaryAuthenticationProvider
return false;
}
$row = $this->loadBalancer->getConnection( DB_REPLICA )->newSelectQueryBuilder()
$row = $this->dbProvider->getReplicaDatabase()->newSelectQueryBuilder()
->select( [ 'user_newpassword', 'user_newpass_time' ] )
->from( 'user' )
->where( [ 'user_name' => $username ] )
@ -220,8 +220,9 @@ class TemporaryPasswordPrimaryAuthenticationProvider
return false;
}
[ $db, $options ] = \DBAccessObjectUtils::getDBOptions( $flags );
return (bool)$this->loadBalancer->getConnection( $db )->newSelectQueryBuilder()
[ $mode, $options ] = \DBAccessObjectUtils::getDBOptions( $flags );
$db = \DBAccessObjectUtils::getDBFromIndex( $this->dbProvider, $mode );
return (bool)$db->newSelectQueryBuilder()
->select( [ 'user_id' ] )
->from( 'user' )
->where( [ 'user_name' => $username ] )
@ -247,7 +248,7 @@ class TemporaryPasswordPrimaryAuthenticationProvider
return \StatusValue::newGood( 'ignored' );
}
$row = $this->loadBalancer->getConnection( DB_PRIMARY )->newSelectQueryBuilder()
$row = $this->dbProvider->getPrimaryDatabase()->newSelectQueryBuilder()
->select( [ 'user_id', 'user_newpass_time' ] )
->from( 'user' )
->where( [ 'user_name' => $username ] )
@ -303,7 +304,7 @@ class TemporaryPasswordPrimaryAuthenticationProvider
return;
}
$dbw = $this->loadBalancer->getConnectionRef( DB_PRIMARY );
$dbw = $this->dbProvider->getPrimaryDatabase();
$sendMail = false;
if ( $req->action !== AuthManager::ACTION_REMOVE &&
@ -402,7 +403,7 @@ class TemporaryPasswordPrimaryAuthenticationProvider
if ( $mailpassword ) {
// Send email after DB commit
$this->loadBalancer->getConnectionRef( DB_PRIMARY )->onTransactionCommitOrIdle(
$this->dbProvider->getPrimaryDatabase()->onTransactionCommitOrIdle(
function () use ( $user, $creator, $req ) {
$this->sendNewAccountEmail( $user, $creator, $req->password );
},

View file

@ -903,7 +903,7 @@ return [
'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider' => [
'class' => 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider',
'services' => [
0 => 'DBLoadBalancer',
0 => 'DBLoadBalancerFactory',
1 => 'UserOptionsLookup',
],
'args' => [
@ -916,7 +916,7 @@ return [
'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider' => [
'class' => 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider',
'services' => [
0 => 'DBLoadBalancer',
0 => 'DBLoadBalancerFactory',
],
'args' => [
0 => [
@ -938,7 +938,7 @@ return [
'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider' => [
'class' => 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider',
'services' => [
0 => 'DBLoadBalancer',
0 => 'DBLoadBalancerFactory',
],
'sort' => 200,
],

View file

@ -21,6 +21,9 @@
* @ingroup Database
*/
use Wikimedia\Rdbms\IConnectionProvider;
use Wikimedia\Rdbms\IReadableDatabase;
/**
* Helper class for DAO classes
*
@ -78,4 +81,23 @@ class DBAccessObjectUtils implements IDBAccessObject {
return [ $index, $options, $fallbackIndex, $fallbackOptions ];
}
/**
* Takes $index from ::getDBOptions() and return proper Database object
*
* Use of this function (and getDBOptions) is discouraged.
*
* @param IConnectionProvider $dbProvider
* @param int $index either DB_REPLICA or DB_PRIMARY
* @return IReadableDatabase
*/
public static function getDBFromIndex( IConnectionProvider $dbProvider, int $index ): IReadableDatabase {
if ( $index === DB_PRIMARY ) {
return $dbProvider->getPrimaryDatabase();
} elseif ( $index === DB_REPLICA ) {
return $dbProvider->getReplicaDatabase();
} else {
throw new InvalidArgumentException( '$index must be either DB_REPLICA or DB_PRIMARY' );
}
}
}

View file

@ -110,7 +110,7 @@ class TestSetup {
[
'class' => MediaWiki\Auth\TemporaryPasswordPrimaryAuthenticationProvider::class,
'services' => [
'DBLoadBalancer',
'DBLoadBalancerFactory',
'UserOptionsLookup',
],
'args' => [ [
@ -120,7 +120,7 @@ class TestSetup {
[
'class' => MediaWiki\Auth\LocalPasswordPrimaryAuthenticationProvider::class,
'services' => [
'DBLoadBalancer',
'DBLoadBalancerFactory',
],
'args' => [ [
'authoritative' => true,

View file

@ -23,7 +23,7 @@ class EmailNotificationSecondaryAuthenticationProviderTest extends \MediaWikiInt
private function getProvider( array $options = [] ): EmailNotificationSecondaryAuthenticationProvider {
$services = $this->getServiceContainer();
$provider = new EmailNotificationSecondaryAuthenticationProvider(
$options['loadBalancer'] ?? $services->getDBLoadBalancer(),
$options['dbProvider'] ?? $services->getDBLoadBalancerFactory(),
$options // make things easier for tests by using the same options
);
$this->initProvider(

View file

@ -69,7 +69,7 @@ class LocalPasswordPrimaryAuthenticationProviderTest extends \MediaWikiIntegrati
$provider = $this->getMockBuilder( LocalPasswordPrimaryAuthenticationProvider::class )
->onlyMethods( [ 'checkPasswordValidity' ] )
->setConstructorArgs( [
$mwServices->getDBLoadBalancer(),
$mwServices->getDBLoadBalancerFactory(),
[ 'loginOnly' => $loginOnly ]
] )
->getMock();
@ -160,7 +160,7 @@ class LocalPasswordPrimaryAuthenticationProviderTest extends \MediaWikiIntegrati
$this->config->set( 'InvalidPasswordReset', true );
$provider = new LocalPasswordPrimaryAuthenticationProvider(
$this->getServiceContainer()->getDBLoadBalancer()
$this->getServiceContainer()->getDBLoadBalancerFactory()
);
$this->initProvider( $provider, $this->config, null, $this->manager );
$providerPriv = TestingAccessWrapper::newFromObject( $provider );

View file

@ -74,7 +74,7 @@ class TemporaryPasswordPrimaryAuthenticationProviderTest extends \MediaWikiInteg
$provider = $this->getMockBuilder( TemporaryPasswordPrimaryAuthenticationProvider::class )
->onlyMethods( $mockedMethods )
->setConstructorArgs( [
$mwServices->getDBLoadBalancer(),
$mwServices->getDBLoadBalancerFactory(),
$mwServices->getUserOptionsLookup(),
$params
] )
@ -131,7 +131,7 @@ class TemporaryPasswordPrimaryAuthenticationProviderTest extends \MediaWikiInteg
] );
$provider = new TemporaryPasswordPrimaryAuthenticationProvider(
$this->getServiceContainer()->getDBLoadBalancer(),
$this->getServiceContainer()->getDBLoadBalancerFactory(),
$this->getServiceContainer()->getUserOptionsLookup()
);
$providerPriv = TestingAccessWrapper::newFromObject( $provider );
@ -141,7 +141,7 @@ class TemporaryPasswordPrimaryAuthenticationProviderTest extends \MediaWikiInteg
$this->assertSame( 101, $providerPriv->passwordReminderResendTime );
$provider = new TemporaryPasswordPrimaryAuthenticationProvider(
$this->getServiceContainer()->getDBLoadBalancer(),
$this->getServiceContainer()->getDBLoadBalancerFactory(),
$this->getServiceContainer()->getUserOptionsLookup(),
[
'emailEnabled' => true,