MediaWiki  REL1_24
SpecialChangePassword.php
Go to the documentation of this file.
00001 <?php
00029 class SpecialChangePassword extends FormSpecialPage {
00030     protected $mUserName;
00031     protected $mDomain;
00032 
00033     // Optional Wikitext Message to show above the password change form
00034     protected $mPreTextMessage = null;
00035 
00036     // label for old password input
00037     protected $mOldPassMsg = null;
00038 
00039     public function __construct() {
00040         parent::__construct( 'ChangePassword', 'editmyprivateinfo' );
00041         $this->listed( false );
00042     }
00043 
00048     function execute( $par ) {
00049         $this->getOutput()->disallowUserJs();
00050 
00051         parent::execute( $par );
00052     }
00053 
00054     protected function checkExecutePermissions( User $user ) {
00055         parent::checkExecutePermissions( $user );
00056 
00057         if ( !$this->getRequest()->wasPosted() ) {
00058             $this->requireLogin( 'resetpass-no-info' );
00059         }
00060     }
00061 
00067     public function setChangeMessage( Message $msg ) {
00068         $this->mPreTextMessage = $msg;
00069     }
00070 
00076     public function setOldPasswordMessage( $msg ) {
00077         $this->mOldPassMsg = $msg;
00078     }
00079 
00080     protected function getFormFields() {
00081         $user = $this->getUser();
00082         $request = $this->getRequest();
00083 
00084         $oldpassMsg = $this->mOldPassMsg;
00085         if ( $oldpassMsg === null ) {
00086             $oldpassMsg = $user->isLoggedIn() ? 'oldpassword' : 'resetpass-temp-password';
00087         }
00088 
00089         $fields = array(
00090             'Name' => array(
00091                 'type' => 'info',
00092                 'label-message' => 'username',
00093                 'default' => $request->getVal( 'wpName', $user->getName() ),
00094             ),
00095             'Password' => array(
00096                 'type' => 'password',
00097                 'label-message' => $oldpassMsg,
00098             ),
00099             'NewPassword' => array(
00100                 'type' => 'password',
00101                 'label-message' => 'newpassword',
00102             ),
00103             'Retype' => array(
00104                 'type' => 'password',
00105                 'label-message' => 'retypenew',
00106             ),
00107         );
00108 
00109         if ( !$this->getUser()->isLoggedIn() ) {
00110             if ( !LoginForm::getLoginToken() ) {
00111                 LoginForm::setLoginToken();
00112             }
00113             $fields['LoginOnChangeToken'] = array(
00114                 'type' => 'hidden',
00115                 'label' => 'Change Password Token',
00116                 'default' => LoginForm::getLoginToken(),
00117             );
00118         }
00119 
00120         $extraFields = array();
00121         wfRunHooks( 'ChangePasswordForm', array( &$extraFields ) );
00122         foreach ( $extraFields as $extra ) {
00123             list( $name, $label, $type, $default ) = $extra;
00124             $fields[$name] = array(
00125                 'type' => $type,
00126                 'name' => $name,
00127                 'label-message' => $label,
00128                 'default' => $default,
00129             );
00130         }
00131 
00132         if ( !$user->isLoggedIn() ) {
00133             $fields['Remember'] = array(
00134                 'type' => 'check',
00135                 'label' => $this->msg( 'remembermypassword' )
00136                         ->numParams(
00137                             ceil( $this->getConfig()->get( 'CookieExpiration' ) / ( 3600 * 24 ) )
00138                         )->text(),
00139                 'default' => $request->getVal( 'wpRemember' ),
00140             );
00141         }
00142 
00143         return $fields;
00144     }
00145 
00146     protected function alterForm( HTMLForm $form ) {
00147         $form->setId( 'mw-resetpass-form' );
00148         $form->setTableId( 'mw-resetpass-table' );
00149         $form->setWrapperLegendMsg( 'resetpass_header' );
00150         $form->setSubmitTextMsg(
00151             $this->getUser()->isLoggedIn()
00152                 ? 'resetpass-submit-loggedin'
00153                 : 'resetpass_submit'
00154         );
00155         $form->addButton( 'wpCancel', $this->msg( 'resetpass-submit-cancel' )->text() );
00156         $form->setHeaderText( $this->msg( 'resetpass_text' )->parseAsBlock() );
00157         if ( $this->mPreTextMessage instanceof Message ) {
00158             $form->addPreText( $this->mPreTextMessage->parseAsBlock() );
00159         }
00160         $form->addHiddenFields(
00161             $this->getRequest()->getValues( 'wpName', 'wpDomain', 'returnto', 'returntoquery' ) );
00162     }
00163 
00164     public function onSubmit( array $data ) {
00165         global $wgAuth;
00166 
00167         $request = $this->getRequest();
00168 
00169         if ( $request->getCheck( 'wpLoginToken' ) ) {
00170             // This comes from Special:Userlogin when logging in with a temporary password
00171             return false;
00172         }
00173 
00174         if ( !$this->getUser()->isLoggedIn()
00175             && $request->getVal( 'wpLoginOnChangeToken' ) !== LoginForm::getLoginToken()
00176         ) {
00177             // Potential CSRF (bug 62497)
00178             return false;
00179         }
00180 
00181         if ( $request->getCheck( 'wpCancel' ) ) {
00182             $titleObj = Title::newFromText( $request->getVal( 'returnto' ) );
00183             if ( !$titleObj instanceof Title ) {
00184                 $titleObj = Title::newMainPage();
00185             }
00186             $query = $request->getVal( 'returntoquery' );
00187             $this->getOutput()->redirect( $titleObj->getFullURL( $query ) );
00188 
00189             return true;
00190         }
00191 
00192         try {
00193             $this->mUserName = $request->getVal( 'wpName', $this->getUser()->getName() );
00194             $this->mDomain = $wgAuth->getDomain();
00195 
00196             if ( !$wgAuth->allowPasswordChange() ) {
00197                 throw new ErrorPageError( 'changepassword', 'resetpass_forbidden' );
00198             }
00199 
00200             $this->attemptReset( $data['Password'], $data['NewPassword'], $data['Retype'] );
00201 
00202             return true;
00203         } catch ( PasswordError $e ) {
00204             return $e->getMessage();
00205         }
00206     }
00207 
00208     public function onSuccess() {
00209         if ( $this->getUser()->isLoggedIn() ) {
00210             $this->getOutput()->wrapWikiMsg(
00211                 "<div class=\"successbox\">\n$1\n</div>",
00212                 'changepassword-success'
00213             );
00214             $this->getOutput()->returnToMain();
00215         } else {
00216             $request = $this->getRequest();
00217             LoginForm::setLoginToken();
00218             $token = LoginForm::getLoginToken();
00219             $data = array(
00220                 'action' => 'submitlogin',
00221                 'wpName' => $this->mUserName,
00222                 'wpDomain' => $this->mDomain,
00223                 'wpLoginToken' => $token,
00224                 'wpPassword' => $request->getVal( 'wpNewPassword' ),
00225             ) + $request->getValues( 'wpRemember', 'returnto', 'returntoquery' );
00226             $login = new LoginForm( new DerivativeRequest( $request, $data, true ) );
00227             $login->setContext( $this->getContext() );
00228             $login->execute( null );
00229         }
00230     }
00231 
00238     protected function attemptReset( $oldpass, $newpass, $retype ) {
00239         $isSelf = ( $this->mUserName === $this->getUser()->getName() );
00240         if ( $isSelf ) {
00241             $user = $this->getUser();
00242         } else {
00243             $user = User::newFromName( $this->mUserName );
00244         }
00245 
00246         if ( !$user || $user->isAnon() ) {
00247             throw new PasswordError( $this->msg( 'nosuchusershort', $this->mUserName )->text() );
00248         }
00249 
00250         if ( $newpass !== $retype ) {
00251             wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'badretype' ) );
00252             throw new PasswordError( $this->msg( 'badretype' )->text() );
00253         }
00254 
00255         $throttleCount = LoginForm::incLoginThrottle( $this->mUserName );
00256         if ( $throttleCount === true ) {
00257             $lang = $this->getLanguage();
00258             $throttleInfo = $this->getConfig()->get( 'PasswordAttemptThrottle' );
00259             throw new PasswordError( $this->msg( 'changepassword-throttled' )
00260                 ->params( $lang->formatDuration( $throttleInfo['seconds'] ) )
00261                 ->text()
00262             );
00263         }
00264 
00265         // @todo Make these separate messages, since the message is written for both cases
00266         if ( !$user->checkTemporaryPassword( $oldpass ) && !$user->checkPassword( $oldpass ) ) {
00267             wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'wrongpassword' ) );
00268             throw new PasswordError( $this->msg( 'resetpass-wrong-oldpass' )->text() );
00269         }
00270 
00271         // User is resetting their password to their old password
00272         if ( $oldpass === $newpass ) {
00273             throw new PasswordError( $this->msg( 'resetpass-recycled' )->text() );
00274         }
00275 
00276         // Do AbortChangePassword after checking mOldpass, so we don't leak information
00277         // by possibly aborting a new password before verifying the old password.
00278         $abortMsg = 'resetpass-abort-generic';
00279         if ( !wfRunHooks( 'AbortChangePassword', array( $user, $oldpass, $newpass, &$abortMsg ) ) ) {
00280             wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'abortreset' ) );
00281             throw new PasswordError( $this->msg( $abortMsg )->text() );
00282         }
00283 
00284         // Please reset throttle for successful logins, thanks!
00285         if ( $throttleCount ) {
00286             LoginForm::clearLoginThrottle( $this->mUserName );
00287         }
00288 
00289         try {
00290             $user->setPassword( $newpass );
00291             wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'success' ) );
00292         } catch ( PasswordError $e ) {
00293             wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'error' ) );
00294             throw new PasswordError( $e->getMessage() );
00295         }
00296 
00297         if ( $isSelf ) {
00298             // This is needed to keep the user connected since
00299             // changing the password also modifies the user's token.
00300             $remember = $this->getRequest()->getCookie( 'Token' ) !== null;
00301             $user->setCookies( null, null, $remember );
00302         }
00303         $user->resetPasswordExpiration();
00304         $user->saveSettings();
00305     }
00306 
00307     public function requiresUnblock() {
00308         return false;
00309     }
00310 
00311     protected function getGroupName() {
00312         return 'users';
00313     }
00314 }