BryanDavis has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/297936

Change subject: Cleanup localuser records when wiki is missing data
......................................................................

Cleanup localuser records when wiki is missing data

Under some (undefined) circumstances the localuser table can record that
a user has been attached to a wiki but the wiki's own db is missing
a record for the user. There is a maintenance script to find an cleanup
these dangling records, but that's not of much help for a user who is
affected by the dangling record as they will not be able to authenticate
to the effected wiki until the next time someone runs the script.

Add logic to catch this problem in the most likely places and proactively
clean up the dangling attachment record. The cleanup is done by running
a job which cleans up the record in a safe manner and clears caches as
appropriate.

Bug: T119736
Change-Id: I3d219cfff0dc835faa72d5fe72a80e57235dcb04
---
M extension.json
A includes/CentralAuthUnattachUserJob.php
M includes/CentralAuthUser.php
A includes/LocalUserNotFoundException.php
4 files changed, 124 insertions(+), 8 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/CentralAuth 
refs/changes/36/297936/1

diff --git a/extension.json b/extension.json
index 769b703..2b149e9 100644
--- a/extension.json
+++ b/extension.json
@@ -70,7 +70,8 @@
                "LocalRenameUserJob": "LocalRenameUserJob",
                "LocalUserMergeJob": "LocalUserMergeJob",
                "LocalPageMoveJob": "LocalPageMoveJob",
-               "CentralAuthCreateLocalAccountJob": 
"CentralAuthCreateLocalAccountJob"
+               "CentralAuthCreateLocalAccountJob": 
"CentralAuthCreateLocalAccountJob",
+               "CentralAuthUnattachUserJob": "CentralAuthUnattachUserJob"
        },
        "LogTypes": [
                "globalauth",
@@ -194,7 +195,9 @@
                "CentralAuthHooks": "includes/CentralAuthHooks.php",
                "CentralAuthPreAuthManagerHooks": 
"includes/CentralAuthPreAuthManagerHooks.php",
                "CentralAuthSuppressUserJob": "includes/SuppressUserJob.php",
+               "CentralAuthUnattachUserJob": 
"includes/CentralAuthUnattachUserJob.php",
                "CentralAuthCreateLocalAccountJob": 
"includes/CreateLocalAccountJob.php",
+               "LocalUserNotFoundException": 
"includes/LocalUserNotFoundException.php",
                "WikiSet": "includes/WikiSet.php",
                "SpecialCentralAutoLogin": 
"includes/specials/SpecialCentralAutoLogin.php",
                "CentralAuthUserArray": "includes/CentralAuthUserArray.php",
diff --git a/includes/CentralAuthUnattachUserJob.php 
b/includes/CentralAuthUnattachUserJob.php
new file mode 100644
index 0000000..760e27b
--- /dev/null
+++ b/includes/CentralAuthUnattachUserJob.php
@@ -0,0 +1,53 @@
+<?php
+/**
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * A job to unattach a user.
+ *
+ * @copyright © 2016 Wikimedia Foundation and contributors.
+ */
+class CentralAuthUnattachUserJob extends Job {
+
+       /**
+        * Constructor
+        *
+        * @param Title $title Associated title
+        * @param array $params Job parameters
+        */
+       public function __construct( $title, $params ) {
+               parent::__construct( 'CentralAuthUnattachUserJob', $title, 
$params );
+       }
+
+       /**
+        * Execute the job
+        *
+        * @return bool
+        */
+       public function run() {
+               $username = $this->params['username'];
+               $wiki = $this->params['wiki'];
+               $user = CentralAuthUser::getMasterInstanceByName( $username );
+               if ( $user->exists() ) {
+                       $user->adminUnattach( array( $wiki ) );
+               }
+               return true;
+       }
+}
diff --git a/includes/CentralAuthUser.php b/includes/CentralAuthUser.php
index 083400c..5d7eea2 100644
--- a/includes/CentralAuthUser.php
+++ b/includes/CentralAuthUser.php
@@ -1391,6 +1391,23 @@
        }
 
        /**
+        * Queue a job to unattach this user from a named wiki.
+        *
+        * @param string $wikiId
+        */
+       protected function queueAdminUnattachJob( $wikiId ) {
+               $job = Job::factory(
+                       'CentralAuthUnattachUserJob',
+                       Title::makeTitleSafe( NS_USER, $this->getName() ),
+                       array(
+                               'username' => $this->getName(),
+                               'wiki' => $wikiId,
+                       )
+               );
+               JobQueueGroup::singleton()->push( $job );
+       }
+
+       /**
         * Delete a global account and log what happened
         *
         * @param $reason string Reason for the deletion
@@ -2238,8 +2255,17 @@
                $wikis = $this->queryAttachedBasic();
 
                foreach ( $wikis as $wikiId => $_ ) {
-                       $localUser = $this->localUserData( $wikiId );
-                       $wikis[$wikiId] = array_merge( $wikis[$wikiId], 
$localUser );
+                       try {
+                               $localUser = $this->localUserData( $wikiId );
+                               $wikis[$wikiId] = array_merge( $wikis[$wikiId], 
$localUser );
+                       } catch (LocalUserNotFoundException $e) {
+                               // T119736: localuser table told us that the 
user was attached
+                               // from $wikiId but there is no data in the 
master or slaves
+                               // that corroborates that.
+                               unset( $wikis[$wikiId] );
+                               // Queue a job to delete the bogus attachment 
record.
+                               $this->queueAdminUnattachJob( $wikiId );
+                       }
                }
 
                $this->mAttachedInfo = $wikis;
@@ -2300,8 +2326,16 @@
 
                $items = array();
                foreach ( $wikiIDs as $wikiID ) {
-                       $data = $this->localUserData( $wikiID );
-                       $items[$wikiID] = $data;
+                       try {
+                               $data = $this->localUserData( $wikiID );
+                               $items[$wikiID] = $data;
+                       } catch ( LocalUserNotFoundException $e ) {
+                               // T119736: localuser table told us that the 
user was attached
+                               // from $wikiId but there is no data in the 
master or slaves
+                               // that corroborates that.
+                               // Queue a job to delete the bogus attachment 
record.
+                               $this->queueAdminUnattachJob( $wikiID );
+                       }
                }
 
                return $items;
@@ -2313,7 +2347,7 @@
         * Returns most data in the user and ipblocks tables, user groups, and 
editcount.
         *
         * @param $wikiID String
-        * @throws Exception if local user not found
+        * @throws LocalUserNotFoundException if local user not found
         * @return array
         */
        protected function localUserData( $wikiID ) {
@@ -2337,7 +2371,7 @@
                }
                if ( !$row ) {
                        $lb->reuseConnection( $db );
-                       throw new Exception( "Could not find local user data 
for {$this->mName}@{$wikiID}" );
+                       throw new LocalUserNotFoundException( "Could not find 
local user data for {$this->mName}@{$wikiID}" );
                }
 
                /** @var $row object */
@@ -2860,4 +2894,4 @@
        private function clearLocalUserCache( $wikiId, $userId ) {
                User::purge( $wikiId, $userId );
        }
-}
\ No newline at end of file
+}
diff --git a/includes/LocalUserNotFoundException.php 
b/includes/LocalUserNotFoundException.php
new file mode 100644
index 0000000..5f804f3
--- /dev/null
+++ b/includes/LocalUserNotFoundException.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * @copyright © 2016 Wikimedia Foundation and contributors
+ */
+class LocalUserNotFoundException extends Exception {
+}

-- 
To view, visit https://gerrit.wikimedia.org/r/297936
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I3d219cfff0dc835faa72d5fe72a80e57235dcb04
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/CentralAuth
Gerrit-Branch: master
Gerrit-Owner: BryanDavis <bda...@wikimedia.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to