Use the new DatabaseVirtualDomains feature

Change-Id: I05b6361bd57ba6754bd308e04da1c635f95d042b
This commit is contained in:
Tim Starling 2023-10-26 14:44:54 +11:00
parent 70703bdce3
commit 6f32dafbc1
4 changed files with 25 additions and 75 deletions

View file

@ -7,25 +7,14 @@ The LoginNotify extension notifies you when someone logs into your account. It c
* Navigate to Special:Version on your wiki to verify that the extension is successfully installed. * Navigate to Special:Version on your wiki to verify that the extension is successfully installed.
#### Configuration parameters #### Configuration parameters
"@doc": "The number of failed login attempts to permit from a known IP before a notification is triggered.",
"LoginNotifyAttemptsKnownIP": 10 See extension.json.
"@doc": "The time-to-live of the count of failed login attempts from a known IP (from the time of the first failed attempt).",
"LoginNotifyExpiryKnownIP": 604800, To place the loginnotify_seen_net table in a shared database, use
"@doc": "The number of failed login attempts to permit from a new IP before a notification is triggered.",
"LoginNotifyAttemptsNewIP": 3, ```php
"@doc": "The time-to-live of the count of failed login attempts from a new IP (from the time of the first failed attempt).", $wgVirtualDomainsMapping['virtual-LoginNotify'] = [
"LoginNotifyExpiryNewIP": 1209600, 'db' => '<shared database name>'
"@doc": "Whether to trigger a notification after failed logins from known IPs.", ];
"LoginNotifyCheckKnownIPs": true, $wgLoginNotifyUseCentralId = true;
"@doc": "Whether to trigger a notification after successful logins from unknown IPs.", ```
"LoginNotifyEnableOnSuccess": true,
"@doc": "Override this to use a different secret than $wgSecretKey",
"LoginNotifySecretKey": null,
"@doc": "Expiry in seconds. Default is 180 days",
"LoginNotifyCookieExpire": 15552000,
"@doc": "Override to allow sharing login cookies between sites on different subdomains",
"LoginNotifyCookieDomain": null,
"@doc": "Maximum number of users (records) to track as having successfully logged in on a particular device.",
"LoginNotifyMaxCookieRecords": 6,
"@doc": "Set to false to disable caching IPs in memcache. Set to 0 to cache forever. Default 60 days.",
"LoginNotifyCacheLoginIPExpiry": 5184000

View file

@ -67,6 +67,9 @@
"ServiceWiringFiles": [ "ServiceWiringFiles": [
"includes/ServiceWiring.php" "includes/ServiceWiring.php"
], ],
"DatabaseVirtualDomains": [
"virtual-LoginNotify"
],
"config": { "config": {
"LoginNotifyAttemptsKnownIP": { "LoginNotifyAttemptsKnownIP": {
"description": "The number of failed login attempts to permit from a known IP before a notification is triggered.", "description": "The number of failed login attempts to permit from a known IP before a notification is triggered.",
@ -112,14 +115,6 @@
"description": "Set to false to disable caching IPs in memcache. Set to 0 to cache forever. Default 60 days.", "description": "Set to false to disable caching IPs in memcache. Set to 0 to cache forever. Default 60 days.",
"value": 5184000 "value": 5184000
}, },
"LoginNotifySeenDatabase": {
"description": "The database to store the loginnotify_seen_net table. This can be a shared database if CentralIdLookupProvider is configured to return a unique ID for the user.",
"value": null
},
"LoginNotifySeenCluster": {
"description": "The external cluster to store the loginnotify_seen_net table in. The default is to store it in the core database.",
"value": null
},
"LoginNotifyUseCheckUser": { "LoginNotifyUseCheckUser": {
"description": "Use the CheckUser cu_changes table if it is available. This is redundant with LoginNotify's own table, available with MediaWiki 1.41. Setting this to true will be deprecated in a later release. Defaults to true temporarily during WMF pilot.", "description": "Use the CheckUser cu_changes table if it is available. This is redundant with LoginNotify's own table, available with MediaWiki 1.41. Setting this to true will be deprecated in a later release. Defaults to true temporarily during WMF pilot.",
"value": true "value": true
@ -128,6 +123,10 @@
"description": "Use the loginnotify_seen_net table. This is redundant with LoginNotifyUseCheckUser although both can be enabled during migration. Defaults to false temporarily during WMF pilot.", "description": "Use the loginnotify_seen_net table. This is redundant with LoginNotifyUseCheckUser although both can be enabled during migration. Defaults to false temporarily during WMF pilot.",
"value": false "value": false
}, },
"LoginNotifyUseCentralId": {
"description": "Use central user IDs in the loginnotify_seen_net table. This should be set to true if the loginnotify_seen_net is in a shared database. CentralAuth should be installed and all users should be attached to it.",
"value": false
},
"LoginNotifySeenExpiry": { "LoginNotifySeenExpiry": {
"description": "The expiry time of data in the loginnotify_seen_net table, in seconds. This should be a multiple of LoginNotifyBucketSize. Default is 180 days.", "description": "The expiry time of data in the loginnotify_seen_net table, in seconds. This should be a multiple of LoginNotifyBucketSize. Default is 180 days.",
"value": 15552000 "value": 15552000

View file

@ -30,7 +30,6 @@ use WebRequest;
use Wikimedia\Assert\Assert; use Wikimedia\Assert\Assert;
use Wikimedia\IPUtils; use Wikimedia\IPUtils;
use Wikimedia\Rdbms\IDatabase; use Wikimedia\Rdbms\IDatabase;
use Wikimedia\Rdbms\ILoadBalancer;
use Wikimedia\Rdbms\IMaintainableDatabase; use Wikimedia\Rdbms\IMaintainableDatabase;
use Wikimedia\Rdbms\IReadableDatabase; use Wikimedia\Rdbms\IReadableDatabase;
use Wikimedia\Rdbms\LBFactory; use Wikimedia\Rdbms\LBFactory;
@ -55,11 +54,10 @@ class LoginNotify implements LoggerAwareInterface {
'LoginNotifyMaxCookieRecords', 'LoginNotifyMaxCookieRecords',
'LoginNotifySecretKey', 'LoginNotifySecretKey',
'LoginNotifySeenBucketSize', 'LoginNotifySeenBucketSize',
'LoginNotifySeenCluster',
'LoginNotifySeenDatabase',
'LoginNotifySeenExpiry', 'LoginNotifySeenExpiry',
'LoginNotifyUseCheckUser', 'LoginNotifyUseCheckUser',
'LoginNotifyUseSeenTable', 'LoginNotifyUseSeenTable',
'LoginNotifyUseCentralId',
'SecretKey', 'SecretKey',
'UpdateRowsPerQuery' 'UpdateRowsPerQuery'
]; ];
@ -418,8 +416,7 @@ class LoginNotify implements LoggerAwareInterface {
* @return IReadableDatabase * @return IReadableDatabase
*/ */
private function getSeenReplicaDb(): IReadableDatabase { private function getSeenReplicaDb(): IReadableDatabase {
$dbName = $this->config->get( 'LoginNotifySeenDatabase' ) ?? false; return $this->lbFactory->getReplicaDatabase( 'virtual-LoginNotify' );
return $this->getSeenLoadBalancer()->getConnection( DB_REPLICA, [], $dbName );
} }
/** /**
@ -428,33 +425,7 @@ class LoginNotify implements LoggerAwareInterface {
* @return IDatabase * @return IDatabase
*/ */
private function getSeenPrimaryDb(): IDatabase { private function getSeenPrimaryDb(): IDatabase {
$dbName = $this->config->get( 'LoginNotifySeenDatabase' ) ?? false; return $this->lbFactory->getPrimaryDatabase( 'virtual-LoginNotify' );
return $this->getSeenLoadBalancer()->getConnection( DB_PRIMARY, [], $dbName );
}
/**
* Is the database holding the loginnotify_seen_net table replicated to
* multiple servers?
*
* @return bool
*/
private function isSeenDbReplicated() {
return $this->getSeenLoadBalancer()->hasReplicaServers();
}
/**
* Get the LoadBalancer holding the loginnotify_seen_net table.
*
* @return ILoadBalancer
*/
private function getSeenLoadBalancer() {
$cluster = $this->config->get( 'LoginNotifySeenCluster' );
if ( $cluster ) {
return $this->lbFactory->getExternalLB( $cluster );
} else {
$dbName = $this->config->get( 'LoginNotifySeenDatabase' ) ?? false;
return $this->lbFactory->getMainLB( $dbName );
}
} }
/** /**
@ -497,7 +468,7 @@ class LoginNotify implements LoggerAwareInterface {
} }
/** /**
* If LoginNotifySeenDatabase is configured, indicating a shared table, * If LoginNotifyUseCentralId is true, indicating a shared table,
* get the central user ID. Otherwise, get the local user ID. * get the central user ID. Otherwise, get the local user ID.
* *
* If CentralAuth is not installed, $this->centralIdLookup will be a * If CentralAuth is not installed, $this->centralIdLookup will be a
@ -509,7 +480,7 @@ class LoginNotify implements LoggerAwareInterface {
* @return int * @return int
*/ */
private function getMaybeCentralId( User $user ) { private function getMaybeCentralId( User $user ) {
if ( ( $this->config->get( 'LoginNotifySeenDatabase' ) ?? false ) !== false ) { if ( $this->config->get( 'LoginNotifyUseCentralId' ) ) {
return $this->centralIdLookup->centralIdFromLocalUser( $user ); return $this->centralIdLookup->centralIdFromLocalUser( $user );
} else { } else {
return $user->getId(); return $user->getId();
@ -802,17 +773,9 @@ class LoginNotify implements LoggerAwareInterface {
// Insert a row // Insert a row
$dbw = $this->getSeenPrimaryDb(); $dbw = $this->getSeenPrimaryDb();
$isReplicated = $this->isSeenDbReplicated();
$fname = __METHOD__; $fname = __METHOD__;
$dbw->onTransactionCommitOrIdle( $dbw->onTransactionCommitOrIdle(
function () use ( $dbw, $id, $hash, $isReplicated, $fname ) { function () use ( $dbw, $id, $hash, $fname ) {
// Check if the user/hash is in the primary DB, as late as
// possible before the insert. (Trying to reduce the number of
// no-op queries in the binlog)
if ( $isReplicated && $this->userIsInCurrentSeenBucket( $id, $hash, true ) ) {
return;
}
$dbw->newInsertQueryBuilder() $dbw->newInsertQueryBuilder()
->insert( 'loginnotify_seen_net' ) ->insert( 'loginnotify_seen_net' )
->ignore() ->ignore()

View file

@ -38,10 +38,9 @@ class LoginNotifyTest extends MediaWikiIntegrationTestCase {
"LoginNotifyCookieDomain" => null, "LoginNotifyCookieDomain" => null,
"LoginNotifyMaxCookieRecords" => 6, "LoginNotifyMaxCookieRecords" => 6,
"LoginNotifyCacheLoginIPExpiry" => 60 * $day, "LoginNotifyCacheLoginIPExpiry" => 60 * $day,
'LoginNotifySeenCluster' => null,
"LoginNotifySeenDatabase" => null,
"LoginNotifyUseCheckUser" => false, "LoginNotifyUseCheckUser" => false,
"LoginNotifyUseSeenTable" => true, "LoginNotifyUseSeenTable" => true,
"LoginNotifyUseCentralId" => false,
"LoginNotifySeenExpiry" => 180 * $day, "LoginNotifySeenExpiry" => 180 * $day,
"LoginNotifySeenBucketSize" => 15 * $day, "LoginNotifySeenBucketSize" => 15 * $day,
"UpdateRowsPerQuery" => 100, "UpdateRowsPerQuery" => 100,