Add Special:VerifyOATHForUser to check if users have OATH enabled

Bug: T209749
Change-Id: Idbac3940b36ce21a0b40044482514a28c5fbd45f
This commit is contained in:
DannyS712 2020-02-15 08:57:20 +00:00
parent 1c69a4cc76
commit 130e649191
6 changed files with 185 additions and 7 deletions

View file

@ -12,7 +12,8 @@ $specialPageAliases = [];
$specialPageAliases['en'] = [ $specialPageAliases['en'] = [
'DisableOATHForUser' => [ 'DisableOATHForUser' ], 'DisableOATHForUser' => [ 'DisableOATHForUser' ],
'OATHManage' => [ 'Manage_Two-factor_authentication', 'OATH_Manage', 'OATHManage', 'OATHManage' => [ 'Manage_Two-factor_authentication', 'OATH_Manage', 'OATHManage',
'OATH', 'Two-factor_authentication', 'OATHAuth' ] 'OATH', 'Two-factor_authentication', 'OATHAuth' ],
'VerifyOATHForUser' => [ 'VerifyOATHForUser' ],
]; ];
/** Arabic (العربية) */ /** Arabic (العربية) */

View file

@ -90,12 +90,14 @@
}, },
"SpecialPages": { "SpecialPages": {
"DisableOATHForUser": "\\MediaWiki\\Extension\\OATHAuth\\Special\\DisableOATHForUser", "DisableOATHForUser": "\\MediaWiki\\Extension\\OATHAuth\\Special\\DisableOATHForUser",
"VerifyOATHForUser": "\\MediaWiki\\Extension\\OATHAuth\\Special\\VerifyOATHForUser",
"OATHManage": "\\MediaWiki\\Extension\\OATHAuth\\Special\\OATHManage" "OATHManage": "\\MediaWiki\\Extension\\OATHAuth\\Special\\OATHManage"
}, },
"AvailableRights": [ "AvailableRights": [
"oathauth-enable", "oathauth-enable",
"oathauth-api-all", "oathauth-api-all",
"oathauth-disable-for-user", "oathauth-disable-for-user",
"oathauth-verify-user",
"oathauth-view-log" "oathauth-view-log"
], ],
"GroupPermissions": { "GroupPermissions": {
@ -108,6 +110,7 @@
}, },
"sysop": { "sysop": {
"oathauth-disable-for-user": true, "oathauth-disable-for-user": true,
"oathauth-verify-user": true,
"oathauth-view-log": true "oathauth-view-log": true
} }
}, },

View file

@ -28,13 +28,17 @@
"oathauth-step4": "Step 4: Verification", "oathauth-step4": "Step 4: Verification",
"oathauth-entertoken": "Enter a code from your authentication device to verify:", "oathauth-entertoken": "Enter a code from your authentication device to verify:",
"oathauth-disable-for-user": "Disable two-factor authentication for a user", "oathauth-disable-for-user": "Disable two-factor authentication for a user",
"oathauth-verify-for-user": "Verify if a user has two-factor authentication enabled",
"right-oathauth-disable-for-user": "Disable two-factor authentication for a user", "right-oathauth-disable-for-user": "Disable two-factor authentication for a user",
"action-oathauth-disable-for-user": "disable two-factor authentication for a user", "action-oathauth-disable-for-user": "disable two-factor authentication for a user",
"right-oathauth-verify-user": "Verify whether a user has two-factor authentication enabled",
"action-oathauth-verify-user": "verify whether a user has two-factor authentication enabled",
"right-oathauth-view-log": "Access to log of two-factor authentication changes", "right-oathauth-view-log": "Access to log of two-factor authentication changes",
"action-oathauth-view-log": "access to log of two-factor authentication changes", "action-oathauth-view-log": "access to log of two-factor authentication changes",
"oathauth-disable-intro": "With great power, comes great responsibility", "oathauth-disable-intro": "With great power, comes great responsibility",
"oathauth-enteruser": "Username:", "oathauth-enteruser": "Username:",
"oathauth-enterreason": "Reason for disabling:", "oathauth-enterdisablereason": "Reason for disabling:",
"oathauth-enterverifyreason": "Reason for checking:",
"oathauth-user-not-does-not-have-oath-enabled": "User doesn't have two-factor authentication enabled, so nothing to disable", "oathauth-user-not-does-not-have-oath-enabled": "User doesn't have two-factor authentication enabled, so nothing to disable",
"right-oathauth-enable": "Enable two-factor authentication", "right-oathauth-enable": "Enable two-factor authentication",
"action-oathauth-enable": "enable two-factor authentication", "action-oathauth-enable": "enable two-factor authentication",
@ -52,6 +56,7 @@
"oath-log-name": "Two-factor authentication log", "oath-log-name": "Two-factor authentication log",
"oath-log-header": "These events track changes to users' two-factor authentication status.", "oath-log-header": "These events track changes to users' two-factor authentication status.",
"logentry-oath-disable-other": "$1 {{GENDER:$2|disabled}} the two-factor authentication of $3", "logentry-oath-disable-other": "$1 {{GENDER:$2|disabled}} the two-factor authentication of $3",
"logentry-oath-verify": "$1 {{GENDER:$2|checked}} if $3 had two-factor authentication enabled",
"oauthauth-ui-no-module": "None enabled", "oauthauth-ui-no-module": "None enabled",
"oathauth-module-invalid": "The OATHAuth module that the user has registered is invalid.", "oathauth-module-invalid": "The OATHAuth module that the user has registered is invalid.",
"oathauth-module-totp-label": "TOTP (one-time token)", "oathauth-module-totp-label": "TOTP (one-time token)",
@ -75,5 +80,7 @@
"oathauth-switch-method-warning-header": "Confirm switching to a different authentication method", "oathauth-switch-method-warning-header": "Confirm switching to a different authentication method",
"oathauth-switch-method-warning": "By switching to $2 two-factor authentication method, current method ($1) will be disabled, and all the data associated with the current authentication method will be deleted", "oathauth-switch-method-warning": "By switching to $2 two-factor authentication method, current method ($1) will be disabled, and all the data associated with the current authentication method will be deleted",
"oathauth-totp-disable-warning": "You will no longer be able to use the authentication device registered with this account. All scratch-tokens associated with this account will be invalidated.", "oathauth-totp-disable-warning": "You will no longer be able to use the authentication device registered with this account. All scratch-tokens associated with this account will be invalidated.",
"oathauth-invalidrequest": "Invalid request" "oathauth-invalidrequest": "Invalid request",
"oathauth-verify-enabled": "{{GENDER:$1|$1}} has two-factor authentication enabled.",
"oathauth-verify-disabled": "{{GENDER:$1|$1}} does not have two-factor authentication enabled."
} }

View file

@ -40,13 +40,17 @@
"oathauth-step4": "Label for step 4 information on Special:OATH", "oathauth-step4": "Label for step 4 information on Special:OATH",
"oathauth-entertoken": "Label on input field on Special:OATH asking user to enter token", "oathauth-entertoken": "Label on input field on Special:OATH asking user to enter token",
"oathauth-disable-for-user": "Title of the special page to disable other users' two-factor authentication (OATH)", "oathauth-disable-for-user": "Title of the special page to disable other users' two-factor authentication (OATH)",
"oathauth-verify-for-user": "Title of the special page to verify other users' two-factor authentication (OATH) status",
"right-oathauth-disable-for-user": "{{doc-right|oathauth-disable-for-user}}", "right-oathauth-disable-for-user": "{{doc-right|oathauth-disable-for-user}}",
"action-oathauth-disable-for-user": "{{doc-action|oathauth-disable-for-user}}", "action-oathauth-disable-for-user": "{{doc-action|oathauth-disable-for-user}}",
"right-oathauth-verify-user": "{{doc-right|oathauth-verify-user}}",
"action-oathauth-verify-user": "{{doc-action|oathauth-verify-user}}",
"right-oathauth-view-log": "{{doc-right|oathauth-view-log}}", "right-oathauth-view-log": "{{doc-right|oathauth-view-log}}",
"action-oathauth-view-log": "{{doc-action|oathauth-view-log}}", "action-oathauth-view-log": "{{doc-action|oathauth-view-log}}",
"oathauth-disable-intro": "Intro message for special to disable other users' two-factor authentication (OATH)", "oathauth-disable-intro": "Intro message for special to disable other users' two-factor authentication (OATH)",
"oathauth-enteruser": "Label for user field in special page to disable", "oathauth-enteruser": "Label for user field in special page to verify or disable two-factor authentication",
"oathauth-enterreason": "Label for field for reason in special page to disable", "oathauth-enterdisablereason": "Label for field for reason in special page to disable two-factor authentication",
"oathauth-enterverifyreason": "Label for field for reason in special page to verify two-factor authentication",
"oathauth-user-not-does-not-have-oath-enabled": "Error message when user does not have two-factor authentication (OATH) enabled", "oathauth-user-not-does-not-have-oath-enabled": "Error message when user does not have two-factor authentication (OATH) enabled",
"right-oathauth-enable": "{{doc-right|oathauth-enable}}", "right-oathauth-enable": "{{doc-right|oathauth-enable}}",
"action-oathauth-enable": "{{doc-action|oathauth-enable}}", "action-oathauth-enable": "{{doc-action|oathauth-enable}}",
@ -64,6 +68,7 @@
"oath-log-name": "The Special:Log log name that appears in the drop-down on the Special:Log page", "oath-log-name": "The Special:Log log name that appears in the drop-down on the Special:Log page",
"oath-log-header": "The Special:Log description that appears on the Special:Log page when you filter logs on this specific log name", "oath-log-header": "The Special:Log description that appears on the Special:Log page when you filter logs on this specific log name",
"logentry-oath-disable-other": "The template of the log entry message\n\n* <code>$1</code> is the person disabling the two-factor authentication.\n* <code>$2</code> is the user whose 2FA is being disabled.\n* <code>$3</code> is the user whose 2FA is being disabled (again).", "logentry-oath-disable-other": "The template of the log entry message\n\n* <code>$1</code> is the person disabling the two-factor authentication.\n* <code>$2</code> is the user whose 2FA is being disabled.\n* <code>$3</code> is the user whose 2FA is being disabled (again).",
"logentry-oath-verify": "The template of the log entry message\n\n* <code>$1</code> is the person verifying the two-factor authentication.\n* <code>$2</code> is the user whose 2FA is being verified.\n* <code>$3</code> is the user whose 2FA is being verified (again).",
"oauthauth-ui-no-module": "User preference value when no 2FA module is enabled", "oauthauth-ui-no-module": "User preference value when no 2FA module is enabled",
"oathauth-module-invalid": "Error message when the OATHAuth module registered by user is invalid", "oathauth-module-invalid": "Error message when the OATHAuth module registered by user is invalid",
"oathauth-module-totp-label": "User preference value when the TOTP module is enabled", "oathauth-module-totp-label": "User preference value when the TOTP module is enabled",
@ -87,5 +92,7 @@
"oathauth-switch-method-warning-header": "Page title for warning page when switching to an alternative 2FA method", "oathauth-switch-method-warning-header": "Page title for warning page when switching to an alternative 2FA method",
"oathauth-switch-method-warning": "Generic message warning the user of token/data loss when switching to an alternative method.\n$1 - Current method name, $2 - Name of the method that is being switched to", "oathauth-switch-method-warning": "Generic message warning the user of token/data loss when switching to an alternative method.\n$1 - Current method name, $2 - Name of the method that is being switched to",
"oathauth-totp-disable-warning": "TOTP specific warning message when disabling/switching to alternative 2FA method", "oathauth-totp-disable-warning": "TOTP specific warning message when disabling/switching to alternative 2FA method",
"oathauth-invalidrequest": "Generic error message that is displayed when request cannot be processed due to an unpredicted reason" "oathauth-invalidrequest": "Generic error message that is displayed when request cannot be processed due to an unpredicted reason",
"oathauth-verify-enabled": "Notice that a user has 2FA enabled, shown on success at [[Special:VerifyOATHForUser]].\n$1 - Name of user",
"oathauth-verify-disabled": "Notice that a user does not have 2FA enabled, shown on success at [[Special:VerifyOATHForUser]].\n$1 - Name of user"
} }

View file

@ -97,7 +97,7 @@ class DisableOATHForUser extends FormSpecialPage {
'reason' => [ 'reason' => [
'type' => 'text', 'type' => 'text',
'default' => '', 'default' => '',
'label-message' => 'oathauth-enterreason', 'label-message' => 'oathauth-enterdisablereason',
'name' => 'reason', 'name' => 'reason',
'required' => true, 'required' => true,
], ],

View file

@ -0,0 +1,160 @@
<?php
namespace MediaWiki\Extension\OATHAuth\Special;
use ConfigException;
use FormSpecialPage;
use HTMLForm;
use ManualLogEntry;
use MediaWiki\Extension\OATHAuth\IModule;
use MediaWiki\Extension\OATHAuth\OATHUserRepository;
use MediaWiki\Logger\LoggerFactory;
use MediaWiki\MediaWikiServices;
use MWException;
use User;
class VerifyOATHForUser extends FormSpecialPage {
private const OATHAUTH_IS_ENABLED = 'enabled';
private const OATHAUTH_NOT_ENABLED = 'disabled';
/** @var OATHUserRepository */
private $userRepo;
/** @var string */
private $enabledStatus;
/** @var string */
private $targetUser;
public function __construct() {
parent::__construct( 'VerifyOATHForUser', 'oathauth-verify-user' );
$this->userRepo = MediaWikiServices::getInstance()->getService( 'OATHUserRepository' );
}
public function doesWrites() {
return true;
}
/**
* @return string
*/
protected function getLoginSecurityLevel() {
return $this->getName();
}
/**
* @param HTMLForm $form
*/
public function alterForm( HTMLForm $form ) {
$form->setMessagePrefix( 'oathauth' );
$form->getOutput()->setPageTitle( $this->msg( 'oathauth-verify-for-user' ) );
}
/**
* @return string
*/
protected function getDisplayFormat() {
return 'ooui';
}
/**
* @return bool
*/
public function requiresUnblock() {
return true;
}
/**
* @param string $par
*/
public function execute( $par ) {
$this->getOutput()->disallowUserJs();
parent::execute( $par );
}
/**
* @return array[]
*/
protected function getFormFields() {
return [
'user' => [
'type' => 'user',
'default' => '',
'label-message' => 'oathauth-enteruser',
'name' => 'user',
'required' => true,
],
'reason' => [
'type' => 'text',
'default' => '',
'label-message' => 'oathauth-enterverifyreason',
'name' => 'reason',
'required' => true,
],
];
}
/**
* @param array $formData
* @return array|true
* @throws ConfigException
* @throws MWException
*/
public function onSubmit( array $formData ) {
$this->targetUser = $formData['user'];
$user = User::newFromName( $this->targetUser );
if ( !$user || $user->getId() === 0 ) {
return [ 'oathauth-user-not-found' ];
}
$oathUser = $this->userRepo->findByUser( $user );
if ( !( $oathUser->getModule() instanceof IModule ) ||
!$oathUser->getModule()->isEnabled( $oathUser ) ) {
$result = self::OATHAUTH_NOT_ENABLED;
} else {
$result = self::OATHAUTH_IS_ENABLED;
}
$this->enabledStatus = $result;
$logEntry = new ManualLogEntry( 'oath', 'verify' );
$logEntry->setPerformer( $this->getUser() );
$logEntry->setTarget( $user->getUserPage() );
$logEntry->setComment( $formData['reason'] );
$logEntry->insert();
LoggerFactory::getInstance( 'authentication' )->info(
'OATHAuth status checked for {usertarget} by {user} from {clientip}', [
'user' => $this->getUser()->getName(),
'usertarget' => $this->targetUser,
'clientip' => $this->getRequest()->getIP(),
]
);
return true;
}
/**
* @throws MWException
*/
public function onSuccess() {
switch ( $this->enabledStatus ) {
case self::OATHAUTH_IS_ENABLED:
$msg = 'oathauth-verify-enabled';
break;
case self::OATHAUTH_NOT_ENABLED:
$msg = 'oathauth-verify-disabled';
break;
default:
throw new MWException(
'Verification was successful but status is unknown'
);
}
$out = $this->getOutput();
$out->addBacklinkSubtitle( $this->getPageTitle() );
$out->addWikiMsg( $msg, $this->targetUser );
}
}