Add new convenience User method for authentication data change
authorGergő Tisza <gtisza@wikimedia.org>
Wed, 8 Jun 2016 20:08:45 +0000 (20:08 +0000)
committerGergő Tisza <gtisza@wikimedia.org>
Wed, 8 Jun 2016 21:19:11 +0000 (21:19 +0000)
Also update createAndPromote.php to use it so it can display errors.

Note that there are two possible approaches. The other is to
do the update for all requests for which the test passed,
even if some tests fail. The approach of the patch seems
more manageable from the caller's point of view
(either the operation was a success, or it failed and
nothing happened).

Change-Id: I86abed4b80472cd888337444fac0cbcb870b1246

includes/user/User.php
languages/i18n/en.json
languages/i18n/qqq.json
maintenance/changePassword.php
maintenance/createAndPromote.php

index 8ecf468..5eef0c2 100644 (file)
@@ -2560,23 +2560,16 @@ class User implements IDBAccessObject {
                                throw new LogicException( 'Cannot set a password for a user that is not in the database.' );
                        }
 
-                       $data = [
+                       $status = $this->changeAuthenticationData( [
                                'username' => $this->getName(),
                                'password' => $str,
                                'retype' => $str,
-                       ];
-                       $reqs = $manager->getAuthenticationRequests( AuthManager::ACTION_CHANGE, $this );
-                       $reqs = AuthenticationRequest::loadRequestsFromSubmission( $reqs, $data );
-                       foreach ( $reqs as $req ) {
-                               $status = $manager->allowsAuthenticationDataChange( $req );
-                               if ( !$status->isGood() ) {
-                                       \MediaWiki\Logger\LoggerFactory::getInstance( 'authentication' )
-                                               ->info( __METHOD__ . ': Password change rejected: ' . $status->getWikiText() );
-                                       return false;
-                               }
-                       }
-                       foreach ( $reqs as $req ) {
-                               $manager->changeAuthenticationData( $req );
+                       ] );
+                       if ( !$status->isGood() ) {
+                               \MediaWiki\Logger\LoggerFactory::getInstance( 'authentication' )
+                                       ->info( __METHOD__ . ': Password change rejected: '
+                                               . $status->getWikiText( null, null, 'en' ) );
+                               return false;
                        }
 
                        $this->setOption( 'watchlisttoken', false );
@@ -2587,6 +2580,45 @@ class User implements IDBAccessObject {
                return true;
        }
 
+       /**
+        * Changes credentials of the user.
+        *
+        * This is a convenience wrapper around AuthManager::changeAuthenticationData.
+        * Note that this can return a status that isOK() but not isGood() on certain types of failures,
+        * e.g. when no provider handled the change.
+        *
+        * @param array $data A set of authentication data in fieldname => value format. This is the
+        *   same data you would pass the changeauthenticationdata API - 'username', 'password' etc.
+        * @return Status
+        * @since 1.27
+        */
+       public function changeAuthenticationData( array $data ) {
+               global $wgDisableAuthManager;
+               if ( $wgDisableAuthManager ) {
+                       throw new LogicException( __METHOD__ . ' cannot be called when $wgDisableAuthManager '
+                               . 'is true' );
+               }
+
+               $manager = AuthManager::singleton();
+               $reqs = $manager->getAuthenticationRequests( AuthManager::ACTION_CHANGE, $this );
+               $reqs = AuthenticationRequest::loadRequestsFromSubmission( $reqs, $data );
+
+               $status = Status::newGood( 'ignored' );
+               foreach ( $reqs as $req ) {
+                       $status->merge( $manager->allowsAuthenticationDataChange( $req ), true );
+               }
+               if ( $status->getValue() === 'ignored' ) {
+                       $status->warning( 'authenticationdatachange-ignored' );
+               }
+
+               if ( $status->isGood() ) {
+                       foreach ( $reqs as $req ) {
+                               $manager->changeAuthenticationData( $req );
+                       }
+               }
+               return $status;
+       }
+
        /**
         * Get the user's current token.
         * @param bool $forceCreation Force the generation of a new token if the
index a028283..91d7541 100644 (file)
        "linkaccounts-success-text": "The account was linked.",
        "linkaccounts-submit": "Link accounts",
        "unlinkaccounts": "Unlink accounts",
-       "unlinkaccounts-success": "The account was unlinked."
+       "unlinkaccounts-success": "The account was unlinked.",
+       "authenticationdatachange-ignored": "The authentication data change was not handled. Maybe no provider was configured?"
 }
index ad9a372..ef5e819 100644 (file)
        "linkaccounts-success-text": "Text shown on top of the form after a successful action.",
        "linkaccounts-submit": "Text of the main submit button on [[Special:LinkAccounts]] (when there is one)",
        "unlinkaccounts": "Title of the special page [[Special:UnlinkAccounts]] which allows the user to remove linked remote accounts.",
-       "unlinkaccounts-success": "Account unlinking form success message"
+       "unlinkaccounts-success": "Account unlinking form success message",
+       "authenticationdatachange-ignored": "Shown when authentication data change was unsuccessful due to configuration problems."
 }
index 8687f81..a550d12 100644 (file)
@@ -41,6 +41,8 @@ class ChangePassword extends Maintenance {
        }
 
        public function execute() {
+               global $wgDisableAuthManager;
+
                if ( $this->hasOption( "user" ) ) {
                        $user = User::newFromName( $this->getOption( 'user' ) );
                } elseif ( $this->hasOption( "userid" ) ) {
@@ -51,8 +53,20 @@ class ChangePassword extends Maintenance {
                if ( !$user || !$user->getId() ) {
                        $this->error( "No such user: " . $this->getOption( 'user' ), true );
                }
+               $password = $this->getOption( 'password' );
                try {
-                       $user->setPassword( $this->getOption( 'password' ) );
+                       if ( $wgDisableAuthManager ) {
+                               $user->setPassword( $password );
+                       } else {
+                               $status = $user->changeAuthenticationData( [
+                                       'username' => $user->getName(),
+                                       'password' => $password,
+                                       'retype' => $password,
+                               ] );
+                               if ( !$status->isGood() ) {
+                                       throw new PasswordError( $status->getWikiText( null, null, 'en' ) );
+                               }
+                       }
                        $user->saveSettings();
                        $this->output( "Password set for " . $user->getName() . "\n" );
                } catch ( PasswordError $pwe ) {
index 848c2f7..3591b9c 100644 (file)
@@ -56,6 +56,8 @@ class CreateAndPromote extends Maintenance {
        }
 
        public function execute() {
+               global $wgDisableAuthManager;
+
                $username = $this->getArg( 0 );
                $password = $this->getArg( 1 );
                $force = $this->hasOption( 'force' );
@@ -120,7 +122,18 @@ class CreateAndPromote extends Maintenance {
                if ( $password ) {
                        # Try to set the password
                        try {
-                               $user->setPassword( $password );
+                               if ( $wgDisableAuthManager ) {
+                                       $user->setPassword( $password );
+                               } else {
+                                       $status = $user->changeAuthenticationData( [
+                                               'username' => $user->getName(),
+                                               'password' => $password,
+                                               'retype' => $password,
+                                       ] );
+                                       if ( !$status->isGood() ) {
+                                               throw new PasswordError( $status->getWikiText( null, null, 'en' ) );
+                                       }
+                               }
                                if ( $exists ) {
                                        $this->output( "Password set.\n" );
                                        $user->saveSettings();