diff --git a/auth.php b/auth.php index b59420c..fa91355 100644 --- a/auth.php +++ b/auth.php @@ -79,9 +79,11 @@ class auth_plugin_emailotp extends auth_plugin_base { // OTP already generated and base credentials matches. if (isset($_SESSION[self::COMPONENT_NAME]) && $_SESSION[self::COMPONENT_NAME]['credentials'] === static::get_credentials($username)) { - return empty($password) - ? (bool) $this->redirect($username, notification::NOTIFY_INFO) - : password_verify($password, $_SESSION[self::COMPONENT_NAME]['password']); + if (empty($password)) { + return (bool) $this->redirect($username, notification::NOTIFY_INFO); + } else if (password_verify($password, $_SESSION[self::COMPONENT_NAME]['password'])) { + return true; + } } // OTP request - do not proceed on preventaccountcreation when user not exits. if (!isset($_SESSION[self::COMPONENT_NAME]) && empty($password) && ( @@ -96,6 +98,18 @@ class auth_plugin_emailotp extends auth_plugin_base { : notification::NOTIFY_ERROR ); } + // OTP exits but validation failed - reset if revoke threshold is set. + if (isset($_SESSION[self::COMPONENT_NAME])) { + $_SESSION[self::COMPONENT_NAME]['login_failed_count']++; + if (!empty($this->config->revokethreshold) && + $_SESSION[self::COMPONENT_NAME]['login_failed_count'] >= $this->config->revokethreshold) { + unset($_SESSION[self::COMPONENT_NAME]); + \core\notification::add( + (string)new lang_string('otpinvalidated', self::COMPONENT_NAME, null, $CFG->lang), + notification::NOTIFY_WARNING + ); + } + } return false; } @@ -181,6 +195,7 @@ class auth_plugin_emailotp extends auth_plugin_base { $_SESSION[self::COMPONENT_NAME] = array( 'credentials' => static::get_credentials($username), 'password' => password_hash($newpassword, PASSWORD_DEFAULT), + 'login_failed_count' => 0, ); $a = (object)array( 'username' => $username, diff --git a/lang/en/auth_emailotp.php b/lang/en/auth_emailotp.php index c401e0c..f4476ab 100644 --- a/lang/en/auth_emailotp.php +++ b/lang/en/auth_emailotp.php @@ -28,6 +28,12 @@ $string['otpgeneratedtext'] = 'One-time password for current session: {$a->passw $string['otpsentsuccess'] = 'One-time password was sent to given email.'; $string['otpsenterror'] = 'An error occurred while sending one-time password.'; $string['otpsentinfo'] = 'One-time password for current session was already generated and sent to email.'; +$string['otpinvalidated'] = 'Previously generated password has been revoked due to exceeding the login failure threshold.'; +$string['optperioderror'] = 'Minim period after which another password can be generated not preserved. Try again later.'; +$string['revokethreshold'] = 'Revoke threshold'; +$string['revokethreshold_help'] = 'Login failures limit causing revoke of the generated password (0 - unlimited).'; +$string['minrequestperiod'] = 'Minium period'; +$string['minrequestperiod_help'] = 'A time in seconds after which another password can be generated.'; $string['fieldsmapping'] = 'User profile fields mapping'; $string['fieldsmapping_pattern'] = 'Pattern'; $string['fieldsmapping_pattern_help'] = 'Capturing groups PCRE patttern.'; diff --git a/lang/pl/auth_emailotp.php b/lang/pl/auth_emailotp.php index 7f92af9..f1a8863 100644 --- a/lang/pl/auth_emailotp.php +++ b/lang/pl/auth_emailotp.php @@ -27,7 +27,13 @@ $string['otpgeneratedsubj'] = 'Hasło jednorazowe'; $string['otpgeneratedtext'] = 'Hasło jednorazowe dla bieżącej sesji: {$a->password}'; $string['otpsentsuccess'] = 'Hasło jednorazowe zostało wysłane na podany adres email.'; $string['otpsenterror'] = 'Wystąpił błąd podczas wysyłania hasła jednorazowego.'; -$string['otpsentinfo'] = 'Hasło jednorazowe dla bieżącej sesji już zostało wygenerowane i wyłane.'; +$string['otpsentinfo'] = 'Hasło jednorazowe dla bieżącej sesji już zostało wygenerowane i wysłane.'; +$string['otpinvalidated'] = 'Poprzednio wygenerowane hasło zostało unieważnione z powodu przekroczenia limitu niepoprawnych logowań.'; +$string['optperioderror'] = 'Nie zachowany minimalny odstęp, po którym kolejne hasło może być wygenerowane. Spróbuj ponownie później.'; +$string['revokethreshold'] = 'Próg nieważnienia'; +$string['revokethreshold_help'] = 'Limit nieudanych logowań unieważniających wygenerowane hasło (0 - bez limitu).'; +$string['minrequestperiod'] = 'Minimalny odstęp'; +$string['minrequestperiod_help'] = 'Czas w sekundach, po którym kolejne hasło może być wygenerowane.'; $string['fieldsmapping'] = 'Mapowanie pól profilu użytkownika'; $string['fieldsmapping_pattern'] = 'Wzorzec'; $string['fieldsmapping_pattern_help'] = 'Grupujące wyrażenie regularne PCRE.'; diff --git a/settings.php b/settings.php index 9a9dc22..1a10d61 100644 --- a/settings.php +++ b/settings.php @@ -52,6 +52,17 @@ if ($ADMIN->fulltree) { get_string('fieldsmapping_mapping', 'auth_emailotp'), get_string('fieldsmapping_mapping_help', 'auth_emailotp'), '', PARAM_RAW_TRIMMED)); + $settings->add(new admin_setting_heading('auth_emailotp/security', + new lang_string('security', 'admin'), '')); + + $settings->add(new admin_setting_configtext('auth_emailotp/revokethreshold', + get_string('revokethreshold', 'auth_emailotp'), + get_string('revokethreshold_help', 'auth_emailotp'), 3, PARAM_INT)); + + $settings->add(new admin_setting_configtext('auth_emailotp/minrequestperiod', + get_string('minrequestperiod', 'auth_emailotp'), + get_string('minrequestperiod_help', 'auth_emailotp'), 120, PARAM_INT)); + // Display locking / mapping of profile fields. $authplugin = get_auth_plugin('emailotp'); display_auth_lock_options($settings, $authplugin->authtype, $authplugin->userfields,