API: Add action=validatepassword
authorBrad Jorsch <bjorsch@wikimedia.org>
Thu, 1 Dec 2016 22:29:29 +0000 (17:29 -0500)
committerGergő Tisza <gtisza@wikimedia.org>
Tue, 20 Dec 2016 00:01:00 +0000 (00:01 +0000)
This will allow for checking passwords against the wiki's password
policy from the account creation and password change forms.

Bug: T111303
Change-Id: I0de281483bd83e47d80aa1ea37149d14f2ae5ebd

RELEASE-NOTES-1.29
autoload.php
docs/hooks.txt
includes/api/ApiMain.php
includes/api/ApiValidatePassword.php [new file with mode: 0644]
includes/api/i18n/en.json
includes/api/i18n/qqq.json

index 3af1654..10b152d 100644 (file)
@@ -75,6 +75,8 @@ production.
   'stasherrors' rather than a 'stashfailed' text string.
 * action=watch reports 'errors' and 'warnings' instead of a single 'error', and
   no longer returns a 'message' on success.
+* Added action=validatepassword to validate passwords for the account creation
+  and password change forms.
 
 === Action API internal changes in 1.29 ===
 * New methods were added to ApiBase to handle errors and warnings using i18n
index 941b335..d85b679 100644 (file)
@@ -147,6 +147,7 @@ $wgAutoloadLocalClasses = [
        'ApiUpload' => __DIR__ . '/includes/api/ApiUpload.php',
        'ApiUsageException' => __DIR__ . '/includes/api/ApiUsageException.php',
        'ApiUserrights' => __DIR__ . '/includes/api/ApiUserrights.php',
+       'ApiValidatePassword' => __DIR__ . '/includes/api/ApiValidatePassword.php',
        'ApiWatch' => __DIR__ . '/includes/api/ApiWatch.php',
        'ArchivedFile' => __DIR__ . '/includes/filerepo/file/ArchivedFile.php',
        'ArrayDiffFormatter' => __DIR__ . '/includes/diff/ArrayDiffFormatter.php',
index 1ecc1f8..862f9f0 100644 (file)
@@ -592,6 +592,10 @@ Use this hook to extend action=tokens with new token types.
 &$tokenTypes: supported token types in format 'type' => callback function
   used to retrieve this type of tokens.
 
+'ApiValidatePassword': Called from ApiValidatePassword.
+$module: ApiValidatePassword instance.
+&$r: Result array.
+
 'Article::MissingArticleConditions': Before fetching deletion & move log entries
 to display a message of a non-existing page being deleted/moved, give extensions
 a chance to hide their (unrelated) log entries.
index 54679a8..4220fb8 100644 (file)
@@ -79,6 +79,7 @@ class ApiMain extends ApiBase {
                'tokens' => 'ApiTokens',
                'checktoken' => 'ApiCheckToken',
                'cspreport' => 'ApiCSPReport',
+               'validatepassword' => 'ApiValidatePassword',
 
                // Write modules
                'purge' => 'ApiPurge',
diff --git a/includes/api/ApiValidatePassword.php b/includes/api/ApiValidatePassword.php
new file mode 100644 (file)
index 0000000..6968523
--- /dev/null
@@ -0,0 +1,81 @@
+<?php
+
+use MediaWiki\Auth\AuthManager;
+
+/**
+ * @ingroup API
+ */
+class ApiValidatePassword extends ApiBase {
+
+       public function execute() {
+               $params = $this->extractRequestParams();
+
+               // For sanity
+               $this->requirePostedParameters( [ 'password' ] );
+
+               if ( $params['user'] !== null ) {
+                       $user = User::newFromName( $params['user'], 'creatable' );
+                       if ( !$user ) {
+                               $encParamName = $this->encodeParamName( 'user' );
+                               $this->dieWithError(
+                                       [ 'apierror-baduser', $encParamName, wfEscapeWikiText( $params['user'] ) ],
+                                       "baduser_{$encParamName}"
+                               );
+                       }
+
+                       if ( !$user->isAnon() || AuthManager::singleton()->userExists( $user->getName() ) ) {
+                               $this->dieWithError( 'userexists' );
+                       }
+
+                       $user->setEmail( (string)$params['email'] );
+                       $user->setRealName( (string)$params['realname'] );
+               } else {
+                       $user = $this->getUser();
+               }
+
+               $validity = $user->checkPasswordValidity( $params['password'] );
+               $r['validity'] = $validity->isGood() ? 'Good' : ( $validity->isOK() ? 'Change' : 'Invalid' );
+               $messages = array_merge(
+                       $this->getErrorFormatter()->arrayFromStatus( $validity, 'error' ),
+                       $this->getErrorFormatter()->arrayFromStatus( $validity, 'warning' )
+               );
+               if ( $messages ) {
+                       $r['validitymessages'] = $messages;
+               }
+
+               Hooks::run( 'ApiValidatePassword', [ $this, &$r ] );
+
+               $this->getResult()->addValue( null, $this->getModuleName(), $r );
+       }
+
+       public function mustBePosted() {
+               return true;
+       }
+
+       public function getAllowedParams() {
+               return [
+                       'password' => [
+                               ApiBase::PARAM_TYPE => 'password',
+                               ApiBase::PARAM_REQUIRED => true
+                       ],
+                       'user' => [
+                               ApiBase::PARAM_TYPE => 'user',
+                       ],
+                       'email' => null,
+                       'realname' => null,
+               ];
+       }
+
+       protected function getExamplesMessages() {
+               return [
+                       'action=validatepassword&password=foobar'
+                               => 'apihelp-validatepassword-example-1',
+                       'action=validatepassword&password=querty&user=Example'
+                               => 'apihelp-validatepassword-example-2',
+               ];
+       }
+
+       public function getHelpUrls() {
+               return 'https://www.mediawiki.org/wiki/API:Validatepassword';
+       }
+}
index d748894..f6eeffe 100644 (file)
        "apihelp-userrights-example-user": "Add user <kbd>FooBot</kbd> to group <kbd>bot</kbd>, and remove from groups <kbd>sysop</kbd> and <kbd>bureaucrat</kbd>.",
        "apihelp-userrights-example-userid": "Add the user with ID <kbd>123</kbd> to group <kbd>bot</kbd>, and remove from groups <kbd>sysop</kbd> and <kbd>bureaucrat</kbd>.",
 
+       "apihelp-validatepassword-description": "Validate a password against the wiki's password policies.\n\nValidity is reported as <samp>Good</samp> if the password is acceptable, <samp>Change</samp> if the password may be used for login but must be changed, or <samp>Invalid</samp> if the password is not usable.",
+       "apihelp-validatepassword-param-password": "Password to validate.",
+       "apihelp-validatepassword-param-user": "User name, for use when testing account creation. The named user must not exist.",
+       "apihelp-validatepassword-param-email": "Email address, for use when testing account creation.",
+       "apihelp-validatepassword-param-realname": "Real name, for use when testing account creation.",
+       "apihelp-validatepassword-example-1": "Validate the password <kbd>foobar</kbd> for the current user.",
+       "apihelp-validatepassword-example-2": "Validate the password <kbd>qwerty</kbd> for creating user <kbd>Example</kbd>.",
+
        "apihelp-watch-description": "Add or remove pages from the current user's watchlist.",
        "apihelp-watch-param-title": "The page to (un)watch. Use <var>$1titles</var> instead.",
        "apihelp-watch-param-unwatch": "If set the page will be unwatched rather than watched.",
index 2bdc64a..1fbc3d0 100644 (file)
        "apihelp-userrights-param-reason": "{{doc-apihelp-param|userrights|reason}}",
        "apihelp-userrights-example-user": "{{doc-apihelp-example|userrights}}",
        "apihelp-userrights-example-userid": "{{doc-apihelp-example|userrights}}",
+       "apihelp-validatepassword-description": "{{doc-apihelp-description|validatepassword}}",
+       "apihelp-validatepassword-param-email": "{{doc-apihelp-param|validatepassword|email}}",
+       "apihelp-validatepassword-param-password": "{{doc-apihelp-param|validatepassword|password}}",
+       "apihelp-validatepassword-param-realname": "{{doc-apihelp-param|validatepassword|realname}}",
+       "apihelp-validatepassword-param-user": "{{doc-apihelp-param|validatepassword|user}}",
+       "apihelp-validatepassword-example-1": "{{doc-apihelp-example|validatepassword}}",
+       "apihelp-validatepassword-example-2": "{{doc-apihelp-example|validatepassword}}",
        "apihelp-watch-description": "{{doc-apihelp-description|watch}}",
        "apihelp-watch-param-title": "{{doc-apihelp-param|watch|title}}",
        "apihelp-watch-param-unwatch": "{{doc-apihelp-param|watch|unwatch}}",