mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/OATHAuth
synced 2024-11-11 17:01:13 +00:00
Send a notification when 2FA is disabled
Notify users when 2FA is disabled on their account in case something was fishy about it. This notification is a "system" notification that will be displayed in the web UI and sent over email. It can't be opted out of as a preference. The notification links to Special:Preferences, where users can see their 2FA status and re-enable it if they want. A secondary help link goes to [[mw:Help:Two-factor authentication]], but can be overridden by adjusting the "oathauth-notifications-disable-helplink" message. The notification text is different based on whether the user disabled 2FA on their own, or an admin used the special page or a maint script to do it. On Wikimedia wikis, we'll use the WikimediaMessages extension to customize the messages. The Echo (Notifications) extension is not required, this will gracefully do nothing if it's not enabled. Bug: T210075 Bug: T210963 Change-Id: I99077ea082b8483cc4fd77573a0d00fa98201f15
This commit is contained in:
parent
4cc5cbe4ad
commit
329c3133d6
|
@ -1,3 +1,17 @@
|
|||
<?php
|
||||
|
||||
return require __DIR__ . '/../vendor/mediawiki/mediawiki-phan-config/src/config.php';
|
||||
$cfg = require __DIR__ . '/../vendor/mediawiki/mediawiki-phan-config/src/config.php';
|
||||
$cfg['directory_list'] = array_merge(
|
||||
$cfg['directory_list'],
|
||||
[
|
||||
'../../extensions/Echo',
|
||||
]
|
||||
);
|
||||
$cfg['exclude_analysis_directory_list'] = array_merge(
|
||||
$cfg['exclude_analysis_directory_list'],
|
||||
[
|
||||
'../../extensions/Echo',
|
||||
]
|
||||
);
|
||||
|
||||
return $cfg;
|
||||
|
|
|
@ -46,7 +46,8 @@
|
|||
"GetPreferences": "main",
|
||||
"getUserPermissionsErrors": "main",
|
||||
"UserEffectiveGroups": "main",
|
||||
"UserGetRights": "main"
|
||||
"UserGetRights": "main",
|
||||
"BeforeCreateEchoEvent": "\\MediaWiki\\Extension\\OATHAuth\\Notifications\\Manager::onBeforeCreateEchoEvent"
|
||||
},
|
||||
"HookHandlers": {
|
||||
"main": {
|
||||
|
|
|
@ -82,6 +82,11 @@
|
|||
"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-invalidrequest": "Invalid request",
|
||||
"notification-header-oathauth-disable": "Two-factor authentication has been disabled on {{GENDER:$2|your account}}.",
|
||||
"notification-body-oathauth-disable": "If {{GENDER:$2|you}} did not do this, {{GENDER:$2|your account}} may have been compromised.",
|
||||
"notification-body-oathauth-disable-other": "If {{GENDER:$2|you}} did not request this, {{GENDER:$2|you}} should contact an administrator.",
|
||||
"oathauth-notifications-disable-help": "Help",
|
||||
"oathauth-notifications-disable-helplink": "mw:Special:MyLanguage/Help:Two-factor authentication",
|
||||
"oathauth-verify-enabled": "{{GENDER:$1|$1}} has two-factor authentication enabled.",
|
||||
"oathauth-verify-disabled": "{{GENDER:$1|$1}} does not have two-factor authentication enabled.",
|
||||
"oathauth-prefs-disabledgroups": "Disabled {{PLURAL:$1|group|groups}}:",
|
||||
|
|
|
@ -94,6 +94,11 @@
|
|||
"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-invalidrequest": "Generic error message that is displayed when request cannot be processed due to an unpredicted reason",
|
||||
"notification-header-oathauth-disable": "Notification header for when two-factor authentication has been disabled.\n$2 - Name of user for GENDER",
|
||||
"notification-body-oathauth-disable": "Notification body text for when two-factor authentication has been disabled.\n$2 - Name of user for GENDER",
|
||||
"notification-body-oathauth-disable-other": "Notification body text for when two-factor authentication has been disabled by an administrator or sysadmin.\n$2 - Name of user for GENDER.",
|
||||
"oathauth-notifications-disable-help": "Link text for the help link in the notification",
|
||||
"oathauth-notifications-disable-helplink": "{{notranslate}}",
|
||||
"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",
|
||||
"oathauth-prefs-disabledgroups": "Label on Special:Preferences for groups in which the user's membership has been disabled for a lack of two-factor authentication.\n$1 - Number of groups",
|
||||
|
|
|
@ -34,7 +34,7 @@ class DisableOATHAuthForUser extends Maintenance {
|
|||
$this->fatalError( "User $username doesn't have OATHAuth enabled!" );
|
||||
}
|
||||
|
||||
$repo->remove( $oathUser, 'Maintenance script' );
|
||||
$repo->remove( $oathUser, 'Maintenance script', false );
|
||||
// Kill all existing sessions. If this disable was social-engineered by an attacker,
|
||||
// the legitimate user will hopefully login again and notice that the second factor
|
||||
// is missing or different, and alert the operators.
|
||||
|
|
|
@ -65,7 +65,7 @@ class TOTPDisableForm extends OATHAuthOOUIHTMLForm implements IManageForm {
|
|||
}
|
||||
|
||||
$this->oathUser->setKeys();
|
||||
$this->oathRepo->remove( $this->oathUser, $this->getRequest()->getIP() );
|
||||
$this->oathRepo->remove( $this->oathUser, $this->getRequest()->getIP(), true );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
72
src/Notifications/DisablePresentationModel.php
Normal file
72
src/Notifications/DisablePresentationModel.php
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
/**
|
||||
* Copyright (C) 2022 Kunal Mehta <legoktm@debian.org>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
namespace MediaWiki\Extension\OATHAuth\Notifications;
|
||||
|
||||
use EchoEventPresentationModel;
|
||||
use SpecialPage;
|
||||
use Title;
|
||||
|
||||
class DisablePresentationModel extends EchoEventPresentationModel {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getIconType() {
|
||||
return 'site';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getPrimaryLink() {
|
||||
return [
|
||||
'url' => SpecialPage::getTitleFor( 'Preferences' )->getLocalURL(),
|
||||
'label' => $this->msg( 'oathauth-notifications-disable-primary' )->text()
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getSecondaryLinks() {
|
||||
$link = $this->msg( 'oathauth-notifications-disable-helplink' )->inContentLanguage();
|
||||
$title = Title::newFromText( $link->plain() );
|
||||
if ( !$title ) {
|
||||
// Invalid title, skip
|
||||
return [];
|
||||
}
|
||||
return [ [
|
||||
'url' => $title->getLocalURL(),
|
||||
'label' => $this->msg( 'oathauth-notifications-disable-help' )->text(),
|
||||
'icon' => 'help',
|
||||
] ];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getBodyMessage() {
|
||||
$self = $this->event->getExtraParam( 'self', true );
|
||||
$message = $this->event->getExtraParam( 'self', true )
|
||||
? 'notification-body-oathauth-disable'
|
||||
: 'notification-body-oathauth-disable-other';
|
||||
return $this->getMessageWithAgent( $message );
|
||||
}
|
||||
}
|
79
src/Notifications/Manager.php
Normal file
79
src/Notifications/Manager.php
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
/**
|
||||
* Copyright (C) 2022 Kunal Mehta <legoktm@debian.org>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
namespace MediaWiki\Extension\OATHAuth\Notifications;
|
||||
|
||||
use EchoEvent;
|
||||
use ExtensionRegistry;
|
||||
use MediaWiki\Extension\OATHAuth\OATHUser;
|
||||
use SpecialPage;
|
||||
|
||||
/**
|
||||
* Manages logic for configuring and sending out notifications with Echo
|
||||
*/
|
||||
class Manager {
|
||||
/**
|
||||
* Whether Echo is installed and can be used
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function isEnabled(): bool {
|
||||
return ExtensionRegistry::getInstance()->isLoaded( 'Echo' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a notification that 2FA has been disabled
|
||||
*
|
||||
* @param OATHUser $oUser
|
||||
* @param bool $self Whether they disabled it themselves
|
||||
*/
|
||||
public static function notifyDisabled( OATHUser $oUser, bool $self ) {
|
||||
if ( !self::isEnabled() ) {
|
||||
return;
|
||||
}
|
||||
EchoEvent::create( [
|
||||
'type' => 'oathauth-disable',
|
||||
'title' => SpecialPage::getTitleFor( 'Preferences' ),
|
||||
'agent' => $oUser->getUser(),
|
||||
'extra' => [
|
||||
'self' => $self,
|
||||
]
|
||||
] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook: BeforeCreateEchoEvent
|
||||
*
|
||||
* Configure our notification types. We don't register a category since
|
||||
* these are all "system" messages that cannot be disabled.
|
||||
*
|
||||
* @param array &$notifications
|
||||
*/
|
||||
public static function onBeforeCreateEchoEvent( &$notifications ) {
|
||||
$notifications['oathauth-disable'] = [
|
||||
'category' => 'system',
|
||||
'group' => 'negative',
|
||||
'section' => 'alert',
|
||||
'presentation-model' => DisablePresentationModel::class,
|
||||
'canNotifyAgent' => true,
|
||||
'user-locators' => [ 'EchoUserLocator::locateEventAgent' ],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -168,8 +168,9 @@ class OATHUserRepository {
|
|||
/**
|
||||
* @param OATHUser $user
|
||||
* @param string $clientInfo
|
||||
* @param bool $self Whether they disabled it themselves
|
||||
*/
|
||||
public function remove( OATHUser $user, $clientInfo ) {
|
||||
public function remove( OATHUser $user, $clientInfo, bool $self ) {
|
||||
$this->getDB( DB_PRIMARY )->delete(
|
||||
'oathauth_users',
|
||||
[ 'id' => MediaWikiServices::getInstance()
|
||||
|
@ -186,6 +187,7 @@ class OATHUserRepository {
|
|||
'user' => $userName,
|
||||
'clientip' => $clientInfo,
|
||||
] );
|
||||
Notifications\Manager::notifyDisabled( $user, $self );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -136,7 +136,7 @@ class DisableOATHForUser extends FormSpecialPage {
|
|||
}
|
||||
|
||||
$oathUser->disable();
|
||||
$this->userRepo->remove( $oathUser, $this->getRequest()->getIP() );
|
||||
$this->userRepo->remove( $oathUser, $this->getRequest()->getIP(), false );
|
||||
|
||||
$logEntry = new ManualLogEntry( 'oath', 'disable-other' );
|
||||
$logEntry->setPerformer( $this->getUser() );
|
||||
|
|
Loading…
Reference in a new issue