summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/OATHAuth/includes/auth/TOTPSecondaryAuthenticationProvider.php
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/extensions/OATHAuth/includes/auth/TOTPSecondaryAuthenticationProvider.php')
-rw-r--r--www/wiki/extensions/OATHAuth/includes/auth/TOTPSecondaryAuthenticationProvider.php121
1 files changed, 121 insertions, 0 deletions
diff --git a/www/wiki/extensions/OATHAuth/includes/auth/TOTPSecondaryAuthenticationProvider.php b/www/wiki/extensions/OATHAuth/includes/auth/TOTPSecondaryAuthenticationProvider.php
new file mode 100644
index 00000000..90d69cc3
--- /dev/null
+++ b/www/wiki/extensions/OATHAuth/includes/auth/TOTPSecondaryAuthenticationProvider.php
@@ -0,0 +1,121 @@
+<?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
+ */
+
+use MediaWiki\Auth\AbstractSecondaryAuthenticationProvider;
+use MediaWiki\Auth\AuthenticationRequest;
+use MediaWiki\Auth\AuthenticationResponse;
+use MediaWiki\Auth\AuthManager;
+
+/**
+ * AuthManager secondary authentication provider for TOTP second-factor authentication.
+ *
+ * After a successful primary authentication, requests a time-based one-time password
+ * (typically generated by a mobile app such as Google Authenticator) from the user.
+ *
+ * @see AuthManager
+ * @see https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm
+ */
+class TOTPSecondaryAuthenticationProvider extends AbstractSecondaryAuthenticationProvider {
+
+ /**
+ * @param string $action
+ * @param array $options
+ *
+ * @return array
+ */
+ public function getAuthenticationRequests( $action, array $options ) {
+ switch ( $action ) {
+ case AuthManager::ACTION_LOGIN:
+ // don't ask for anything initially so the second factor is on a separate screen
+ return [];
+ default:
+ return [];
+ }
+ }
+
+ /**
+ * If the user has enabled two-factor authentication, request a second factor.
+ *
+ * @param User $user
+ * @param array $reqs
+ *
+ * @return AuthenticationResponse
+ */
+ public function beginSecondaryAuthentication( $user, array $reqs ) {
+ $oathuser = OATHAuthHooks::getOATHUserRepository()->findByUser( $user );
+
+ if ( $oathuser->getKey() === null ) {
+ return AuthenticationResponse::newAbstain();
+ } else {
+ return AuthenticationResponse::newUI( [ new TOTPAuthenticationRequest() ],
+ wfMessage( 'oathauth-auth-ui' ), 'warning' );
+ }
+ }
+
+ /**
+ * Verify the second factor.
+ * @inheritDoc
+ */
+ public function continueSecondaryAuthentication( $user, array $reqs ) {
+ /** @var TOTPAuthenticationRequest $request */
+ $request = AuthenticationRequest::getRequestByClass( $reqs, TOTPAuthenticationRequest::class );
+ if ( !$request ) {
+ return AuthenticationResponse::newUI( [ new TOTPAuthenticationRequest() ],
+ wfMessage( 'oathauth-login-failed' ), 'error' );
+ }
+
+ $oathuser = OATHAuthHooks::getOATHUserRepository()->findByUser( $user );
+ /** @suppress PhanUndeclaredProperty */
+ $token = $request->OATHToken;
+
+ if ( $oathuser->getKey() === null ) {
+ $this->logger->warning( 'Two-factor authentication was disabled mid-authentication for '
+ . $user->getName() );
+ return AuthenticationResponse::newAbstain();
+ }
+
+ // Don't increase pingLimiter, just check for limit exceeded.
+ if ( $user->pingLimiter( 'badoath', 0 ) ) {
+ return AuthenticationResponse::newUI(
+ [ new TOTPAuthenticationRequest() ],
+ new Message(
+ 'oathauth-throttled',
+ // Arbitrary duration given here
+ [ Message::durationParam( 60 ) ]
+ ), 'error' );
+ }
+
+ if ( $oathuser->getKey()->verifyToken( $token, $oathuser ) ) {
+ return AuthenticationResponse::newPass();
+ } else {
+ return AuthenticationResponse::newUI( [ new TOTPAuthenticationRequest() ],
+ wfMessage( 'oathauth-login-failed' ), 'error' );
+ }
+ }
+
+ /**
+ * @param User $user
+ * @param User $creator
+ * @param array $reqs
+ *
+ * @return AuthenticationResponse
+ */
+ public function beginSecondaryAccountCreation( $user, $creator, array $reqs ) {
+ return AuthenticationResponse::newAbstain();
+ }
+}