r19614 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r19613‎ | r19614 | r19615 >
Date:02:42, 24 January 2007
Author:brion
Status:old
Tags:
Comment:
* Trim down the 'migrateuser' table to just contain presence and username/id mappings; actual migration data such as passwords, email, and edit counts are fetched from the live database when required. This should better handle on-demand migration over a long period. (Will require that the table be updated properly on local user creation and renames; need to add that still. Also will need to fix up the foreign database grabbing functions so it pulls from the right database server for our live setup)
* Fix a total dumbass bug in automatic migration where it stopped looking at the first non-migratable wiki for each account
* Expand the password fields to tinyblobs to match the live use; this will allow future migration to different hash algos
Modified paths:
  • /trunk/extensions/CentralAuth/CentralAuthUser.php (modified) (history)
  • /trunk/extensions/CentralAuth/central-auth.sql (modified) (history)

Diff [purge]

Index: trunk/extensions/CentralAuth/CentralAuthUser.php
@@ -166,10 +166,6 @@
167167 'mu_dbname' => $dbname,
168168 'mu_local_id' => $row->user_id,
169169 'mu_name' => $row->user_name,
170 - 'mu_password' => $row->user_password,
171 - 'mu_email' => $row->user_email,
172 - 'mu_email_authenticated' => $row->user_email_authenticated,
173 - 'mu_editcount' => $row->user_editcount,
174170 ),
175171 __METHOD__,
176172 array( 'IGNORE' ) );
@@ -212,7 +208,7 @@
213209 * @fixme add some locking or something
214210 */
215211 function attemptAutoMigration() {
216 - $rows = $this->fetchUnattached();
 212+ $rows = $this->queryUnattached();
217213
218214 if( !$rows ) {
219215 wfDebugLog( 'CentralAuth',
@@ -227,33 +223,35 @@
228224 // We have to pick a master account
229225 // The winner is the one with the most edits, usually
230226 foreach( $rows as $row ) {
231 - if( $row->mu_editcount > $max ) {
 227+ if( $row['editCount'] > $max ) {
232228 $winner = $row;
233 - $max = $row->mu_editcount;
 229+ $max = $row['editCount'];
234230 }
235231 }
236232 if( !isset( $winner ) ) {
237 - var_dump( $rows );
238 - die();
 233+ throw new MWException( "Logic error in migration: " .
 234+ "Unable to determine primary account for $this->mName" );
239235 }
240236
241237 // If the primary account has an e-mail address set,
242238 // we can use it to match other accounts. If it doesn't,
243239 // we can't be sure that the other accounts with no mail
244240 // are the same person, so err on the side of caution.
245 - $winningMail = ($winner->mu_email == ''
 241+ $winningMail = ($winner['email'] == ''
246242 ? false
247 - : $winner->mu_email);
 243+ : $winner['email']);
248244
 245+ if( $this->mName == 'WikiSysop' ) { var_dump( $rows ); }
249246 foreach( $rows as $row ) {
250 - if( $row->mu_dbname == $winner->mu_dbname ) {
 247+ $local = $this->mName . "@" . $row['dbName'];
 248+ if( $row['dbName'] == $winner['dbName'] ) {
251249 // Primary account holder... duh
252250 $method = 'primary';
253 - } elseif( $row->mu_email === $winningMail ) {
 251+ } elseif( $row['email'] === $winningMail ) {
254252 // Same e-mail as primary means we know they could
255253 // reset their password, so we give them the account.
256254 $method = 'mail';
257 - } elseif( $row->mu_editcount == 0 ) {
 255+ } elseif( $row['editCount'] == 0 ) {
258256 // Unused accounts are fair game for reclaiming
259257 $method = 'empty';
260258 } else {
@@ -262,16 +260,18 @@
263261 // If the password matches, it will be automigrated
264262 // at next login. If no match, user will have to input
265263 // the conflicting password or deal with the conflict.
266 - break;
 264+ wfDebugLog( 'CentralAuth', "unresolvable $local" );
 265+ continue;
267266 }
268 - $attach[] = array( $row->mu_dbname, $row->mu_local_id, $method );
 267+ wfDebugLog( 'CentralAuth', "$method $local" );
 268+ $attach[] = array( $row['dbName'], $row['localId'], $method );
269269 }
270270
271271 $ok = $this->storeGlobalData(
272 - $winner->mu_local_id,
273 - $winner->mu_password,
274 - $winner->mu_email,
275 - $winner->mu_email_authenticated );
 272+ $winner['localId'],
 273+ $winner['password'],
 274+ $winner['email'],
 275+ $winner['emailAuthenticated'] );
276276
277277 if( !$ok ) {
278278 wfDebugLog( 'CentralAuth',
@@ -285,7 +285,7 @@
286286 } else {
287287 if( count( $rows ) == 1 ) {
288288 wfDebugLog( 'CentralAuth',
289 - "Singleton migration for '$this->mName' on $winner->mu_dbname" );
 289+ "Singleton migration for '$this->mName' on " . $winner['dbName'] );
290290 } else {
291291 wfDebugLog( 'CentralAuth',
292292 "Full automatic migration for '$this->mName'" );
@@ -312,7 +312,7 @@
313313 * @return bool true if all accounts are migrated at the end
314314 */
315315 function attemptPasswordMigration( $password, &$migrated=null, &$remaining=null ) {
316 - $rows = $this->fetchUnattached();
 316+ $rows = $this->queryUnattached();
317317
318318 if( count( $rows ) == 0 ) {
319319 wfDebugLog( 'CentralAuth',
@@ -325,15 +325,16 @@
326326
327327 // Look for accounts we can match by password
328328 foreach( $rows as $key => $row ) {
329 - if( $this->matchHash( $password, $row->mu_local_id, $row->mu_password ) ) {
 329+ $db = $row['dbName'];
 330+ if( $this->matchHash( $password, $row['localId'], $row['password'] ) ) {
330331 wfDebugLog( 'CentralAuth',
331 - "Attaching '$this->mName' on $row->mu_dbname by password" );
332 - $this->attach( $row->mu_dbname, $row->mu_local_id, 'password' );
333 - $migrated[] = $row->mu_dbname;
 332+ "Attaching '$this->mName' on $db by password" );
 333+ $this->attach( $db, $row['localId'], 'password' );
 334+ $migrated[] = $db;
334335 } else {
335336 wfDebugLog( 'CentralAuth',
336 - "No password match for '$this->mName' on $row->mu_dbname" );
337 - $remaining[] = $row->mu_dbname;
 337+ "No password match for '$this->mName' on $db" );
 338+ $remaining[] = $db;
338339 }
339340 }
340341
@@ -364,17 +365,17 @@
365366
366367 public function adminAttach( $list, &$migrated=null, &$remaining=null ) {
367368 $valid = $this->validateList( $list );
368 - $unattached = $this->fetchUnattached();
 369+ $unattached = $this->queryUnattached();
369370
370371 $migrated = array();
371372 $remaining = array();
372373
373374 foreach( $unattached as $row ) {
374 - if( in_array( $row->mu_dbname, $valid ) ) {
375 - $this->attach( $row->mu_dbname, $row->mu_local_id, 'admin' );
376 - $migrated[] = $row->mu_dbname;
 375+ if( in_array( $row['dbName'], $valid ) ) {
 376+ $this->attach( $row['dbName'], $row['localId'], 'admin' );
 377+ $migrated[] = $row['dbName'];
377378 } else {
378 - $remaining[] = $row->mu_dbname;
 379+ $remaining[] = $row['dbName'];
379380 }
380381 }
381382
@@ -573,9 +574,20 @@
574575
575576 $items = array();
576577 foreach( $rows as $row ) {
577 - $items[$row->mu_dbname] = array(
578 - 'dbName' => $row->mu_dbname,
579 - 'localId' => intval( $row->mu_local_id ),
 578+ $db = $row->mu_dbname;
 579+ $id = intval( $row->mu_local_id );
 580+ $userData = self::localUserData( $db, $id );
 581+ if( !is_object( $userData ) ) {
 582+ throw new MWException("Bad user row looking up local user #$id@$db");
 583+ }
 584+
 585+ $items[$db] = array(
 586+ 'dbName' => $db,
 587+ 'localId' => $id,
 588+ 'email' => $userData->user_email,
 589+ 'emailAuthenticated' => $userData->user_email_authenticated,
 590+ 'password' => $userData->user_password,
 591+ 'editCount' => $userData->user_editcount,
580592 );
581593 }
582594
@@ -583,6 +595,34 @@
584596 }
585597
586598 /**
 599+ * Fetch a row of user data needed for migration.
 600+ * @todo: work on multi-master clusters!
 601+ */
 602+ protected static function localUserData( $dbname, $id ) {
 603+ //$db = wfGetForeignDB( $dbname );
 604+ $db = wfGetDB( DB_MASTER );
 605+ $row = $db->selectRow( "`$dbname`.user",
 606+ array(
 607+ 'user_email',
 608+ 'user_email_authenticated',
 609+ 'user_password',
 610+ 'user_editcount' ),
 611+ array( 'user_id' => $id ),
 612+ __METHOD__ );
 613+
 614+ // Edit count field may not be initialized...
 615+ if( $row !== false && is_null( $row->user_editcount ) ) {
 616+ $row->user_editcount = $db->selectField(
 617+ "`$dbname`.revision",
 618+ 'COUNT(*)',
 619+ array( 'rev_user' => $id ),
 620+ __METHOD__ );
 621+ }
 622+
 623+ return $row;
 624+ }
 625+
 626+ /**
587627 * Find any remaining migration records for this username
588628 * which haven't gotten attached to some global account.
589629 */
Index: trunk/extensions/CentralAuth/central-auth.sql
@@ -17,7 +17,7 @@
1818
1919 -- Salt and hashed password
2020 gu_salt char(16), -- or should this be an int? usually the old user_id
21 - gu_password char(32),
 21+ gu_password tinyblob,
2222
2323 -- If true, this account cannot be used to log in on any wiki.
2424 gu_locked bool not null default 0,
@@ -30,13 +30,12 @@
3131 gu_registration char(14) binary,
3232
3333 -- Random key for password resets
34 - gu_password_reset_key char(32),
 34+ gu_password_reset_key tinyblob,
3535 gu_password_reset_expiration char(14) binary,
3636
3737 primary key (gu_id),
3838 unique key (gu_name),
39 - key (gu_email),
40 - key (gu_password_reset_key)
 39+ key (gu_email)
4140 ) TYPE=InnoDB;
4241
4342
@@ -74,10 +73,13 @@
7574 unique key (lu_global_id, lu_dbname)
7675 ) TYPE=InnoDB;
7776
 77+
7878 -- Migration state table
7979 --
 80+-- Lists registered usernames on various wikis, used to optimize migration
 81+-- checks by only having to check dbs where the name is actually registered.
 82+--
 83+-- May be batch-initialized and/or lazy-initialized.
8084 -- Once migration is complete, this data can be ignored/discarded.
8185 --
8286 CREATE TABLE migrateuser (
@@ -90,23 +92,6 @@
9193 -- Username at migration time
9294 mu_name varchar(255) binary,
9395
94 - -- User'd old password hash; salt is lu_id
95 - mu_password varchar(255) binary,
96 -
97 - -- The user_email and user_email_authenticated state from local wiki
98 - mu_email varchar(255) binary,
99 - mu_email_authenticated char(14) binary,
100 -
101 - -- A count of revisions and/or other actions made during migration
102 - -- May be null if it hasn't yet been checked
103 - mu_editcount int,
104 -
105 - -- True if user was blocked...
106 - mu_blocked bool,
107 -
108 - -- True if user has admin privs...
109 - mu_admin bool,
110 -
11196 primary key (mu_dbname, mu_local_id),
11297 unique key (mu_dbname, mu_name),
11398 key (mu_name, mu_dbname)