mediawiki-extensions-OATHAuth/api/ApiOATHValidate.php
Bryan Davis 36c523ab23 Add an api action to validate an OATH token
Add a new internal action=oathvalidate Action API module that can be
used to validate an OATH token collected from a user. Using the module
requires the 'oathauth-api-all' permission introduced in I4884f6e.

Attempts to call the action for a given user are rate limited to only
allow 10 failures per minute using the new 'badoath' key.

The check is primarily useful as an internal network service in an
environment where MediaWiki and other applications are sharing the same
backing authentication store (e.g. LDAP) and the non-MediaWiki
applications would like to respect the OATH protections enabled on the
MediaWiki install.

Complete usage in an LDAP shared auth environment would look something
like:
* Authenticate a user with the LDAP server via auth-bind
* Call action=query&meta=oath as a privileged user to check for OATH
  protection.
* If OATH is active for the account, prompt the user for their current
  OATH token.
* Call action=oathvalidate as a privileged user to validate the token.
* If validation succeeds, complete authentication.
* If validation fails, do not authenticate the user.

Bug: T144712
Change-Id: I1b18d9f3b99364fc47c760bdfc2047c1cbb5c04a
2016-10-07 16:55:50 -07:00

112 lines
2.8 KiB
PHP

<?php
/**
* 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
*/
/**
* Validate an OATH token.
*
* @ingroup API
* @ingroup Extensions
*/
class ApiOATHValidate extends ApiBase {
public function execute() {
// Be extra paranoid about the data that is sent
$this->requirePostedParameters( [ 'totp', 'token' ] );
$params = $this->extractRequestParams();
if ( $params['user'] === null ) {
$params['user'] = $this->getUser()->getName();
}
if ( !$this->getUser()->isAllowed( 'oathauth-api-all' ) ) {
$this->dieUsage(
'You do not have permission to validate an OATH token',
'permissiondenied'
);
}
$user = User::newFromName( $params['user'] );
if ( $user === false ) {
$this->dieUsageMsg( [ 'noname', $params['user'] ] );
}
// Don't increase pingLimiter, just check for limit exceeded
if ( $user->pingLimiter( 'badoath', 0 ) ) {
$this->dieUsageMsg( 'actionthrottledtext' );
}
$result = [
ApiResult::META_BC_BOOLS => [ 'enabled', 'valid' ],
'enabled' => false,
'valid' => false,
];
if ( !$user->isAnon() ) {
$oathUser = OATHAuthHooks::getOATHUserRepository()
->findByUser( $user );
if ( $oathUser ) {
$key = $oathUser->getKey();
if ( $key !== null ) {
$result['enabled'] = true;
$result['valid'] = $key->verifyToken(
$params['totp'], $oathUser ) !== false;
}
}
}
if ( !$result['valid'] ) {
// Increase rate limit counter for failed request
$user->pingLimiter( 'badoath' );
}
$this->getResult()->addValue( null, $this->getModuleName(), $result );
}
public function getCacheMode( $params ) {
return 'private';
}
public function isInternal() {
return true;
}
public function needsToken() {
return 'csrf';
}
public function getAllowedParams() {
return [
'user' => [
ApiBase::PARAM_TYPE => 'user',
],
'totp' => [
ApiBase::PARAM_TYPE => 'string',
ApiBase::PARAM_REQUIRED => true,
],
];
}
protected function getExamplesMessages() {
return [
'action=oathvalidate&totp=123456&token=123ABC'
=> 'apihelp-oath-example-1',
'action=oathvalidate&user=Example&totp=123456&token=123ABC'
=> 'apihelp-oath-example-2',
];
}
}