commit 3bd26295ceee2eec1c228302288f4196539aff9f
parent cac54ffa874b7ef4e2ad59d336b3cd84a2429768
Author: dankert <openrat@jandankert.de>
Date: Mon, 7 Feb 2022 22:52:12 +0100
Password lock check is moved into "InternalAuth", because it must be called on all authentication requests.
Diffstat:
12 files changed, 80 insertions(+), 67 deletions(-)
diff --git a/modules/cms/action/login/LoginLoginAction.class.php b/modules/cms/action/login/LoginLoginAction.class.php
@@ -134,40 +134,6 @@ class LoginLoginAction extends LoginAction implements Method {
]
));
- // Increase fail counter
- $user = User::loadWithName($loginName,User::AUTH_TYPE_INTERNAL);
-
- if ( $authResult & Auth::STATUS_ACCOUNT_LOCKED ) {
- ;
- // the account is locked, so the login failed.
- // we are NOT informing the UI about this. The user is already informed about the lock.
- }
- else {
- // Increase password fail counter
- $user->increaseFailedPasswordCounter();
- // $user->passwordFailedCount is now at least 1.
-
- $lockAfter = Configuration::subset(['security','password'])->get('lock_after_fail_count',10);
- if ( $lockAfter && $user->passwordFailedCount % $lockAfter == 0 ) {
- // exponentially increase the lock duration.
- $factor = pow(2, intval($user->passwordFailedCount/$lockAfter) - 1 ) ;
- $lockedDuration = Configuration::subset(['security','password'])->get('lock_duration',120) * $factor * 60;
-
- $lockedUntil = Startup::getStartTime() + $lockedDuration;
- $user->passwordLockedUntil = $lockedUntil;
- $user->persist();
-
- // Inform the user about the lock.
- if ( $user->mail ) {
- $mail = new Mail( $user->mail,Messages::MAIL_PASSWORD_LOCKED_SUBJECT,Messages::MAIL_PASSWORD_LOCKED);
- $mail->setVar('username',$user->name);
- $mail->setVar('name',$user->getName() );
- $mail->setVar('until',date( \cms\base\Language::lang(Messages::DATE_FORMAT ), $lockedUntil ) );
- $mail->send();
- }
- }
- }
-
// Login failed.
throw new ValidationException('login_password',Messages::LOGIN_FAILED, ['name' => $loginName] );
}
@@ -184,7 +150,6 @@ class LoginLoginAction extends LoginAction implements Method {
$user = User::loadWithName($loginName, User::AUTH_TYPE_INTERNAL, null);
$user->setCurrent();
$user->updateLoginTimestamp();
- $user->resetFailedPasswordCounter();
if ($user->passwordAlgo != Password::bestAlgoAvailable())
// Re-Hash the password with a better hash algo.
diff --git a/modules/cms/auth/InternalAuth.class.php b/modules/cms/auth/InternalAuth.class.php
@@ -6,8 +6,10 @@ use cms\base\Configuration;
use cms\base\DB as Db;
use cms\base\Startup;
use cms\model\User;
+use language\Messages;
use LogicException;
use security\Password;
+use util\mail\Mail;
/**
* Authentifizierungsmodul für die interne Benutzerdatenbank.
@@ -48,15 +50,70 @@ SQL
// Pruefen ob Kennwort mit Datenbank uebereinstimmt.
if (!Password::check(User::pepperPassword($password), $row_user['password_hash'], $row_user['password_algo'])) {
+ // Password does NOT match.
+
+ // Increase password fail counter
+ $sql = Db::sql(<<<SQL
+UPDATE {{user}}
+ SET password_fail_count=password_fail_count+1
+ WHERE name={name}
+SQL
+ );
+ $sql->setString('name', $username);
+ $sql->execute();
+
+ $row_user['password_fail_count']++;
+
+ $lockAfter = Configuration::subset(['security','password'])->get('lock_after_fail_count',10);
+ if ( $lockAfter && $row_user['password_fail_count'] % $lockAfter == 0 ) {
+ // exponentially increase the lock duration.
+ $factor = pow(2, intval($row_user['password_fail_count']/$lockAfter) - 1 ) ;
+ $lockedDuration = Configuration::subset(['security','password'])->get('lock_duration',120) * $factor * 60;
+
+ $lockedUntil = Startup::getStartTime() + $lockedDuration;
+
+ $sql = Db::sql(<<<SQL
+UPDATE {{user}}
+ SET password_locked_until={locked_until}
+ WHERE name={name}
+SQL
+ );
+ $sql->setString('name' , $username );
+ $sql->setInt ('locked_until',$lockedUntil);
+ $sql->execute();
+
+ // Inform the user about the lock.
+ if ( $row_user['mail'] ) {
+ $mail = new Mail( $row_user['mail'],Messages::MAIL_PASSWORD_LOCKED_SUBJECT,Messages::MAIL_PASSWORD_LOCKED);
+ $mail->setVar('username',$row_user['name' ] );
+ $mail->setVar('name' ,$row_user['fullname'] );
+ $mail->setVar('until' ,date( \cms\base\Language::lang(Messages::DATE_FORMAT_FULL ), $lockedUntil ) );
+ $mail->send();
+ }
+ }
+ Db::get()->commit();
+
return Auth::STATUS_FAILED;
}
+ // Password match :)
+
+ // Clear password fail counter
+ $sql = Db::sql(<<<SQL
+UPDATE {{user}}
+ SET password_fail_count=0
+ WHERE name={name}
+SQL
+ );
+ $sql->setString('name', $username);
+ $sql->execute();
+
// Behandeln von Klartext-Kennwoertern (Igittigitt).
if ($row_user['password_algo'] == Password::ALGO_PLAIN) {
if (Configuration::subset(['security', 'password'] )->is('force_change_if_cleartext',true))
// Kennwort steht in der Datenbank im Klartext.
// Das Kennwort muss geaendert werden
- return Auth::STATUS_PW_EXPIRED;
+ return Auth::STATUS_FAILED + Auth::STATUS_PW_EXPIRED;
// Anderenfalls ist das Login zwar moeglich, aber das Kennwort wird automatisch neu gehasht, weil der beste Algo erzwungen wird.
// Das Klartextkennwort waere danach ueberschrieben.
diff --git a/modules/cms/model/User.class.php b/modules/cms/model/User.class.php
@@ -1162,18 +1162,6 @@ SQL
}
- public function increaseFailedPasswordCounter() {
- $this->passwordFailedCount++;
- $this->save();
- }
-
-
- public function resetFailedPasswordCounter() {
- $this->passwordFailedCount = 0;
- $this->save();
- }
-
-
public function getId()
{
return $this->userid;
diff --git a/modules/language/Language_CN.class.php b/modules/language/Language_CN.class.php
@@ -121,9 +121,10 @@ public function get() { return [
'CREATE_USER'=>'Creation-User',
'DATE_ANSI'=>'Date ANSI notation',
'DATE'=>'Date',
+'DATE_FORMAT_FULL'=>'m/d Y H:i',
'DATE_FORMAT'=>'m/d Y',
'DATE_FORMAT_TODAY'=>'H:i:s',
-'DATE_FORMAT_LONG'=>'l F jS Y, H:i',
+'DATE_FORMAT_LONG'=>'m/d Y H:i',
'DATE_LAST_MONTH'=>'Last month',
'DATE_LAST_YEAR'=>'Last year',
'DATE_MONTH10'=>'October',
diff --git a/modules/language/Language_DE.class.php b/modules/language/Language_DE.class.php
@@ -121,6 +121,7 @@ public function get() { return [
'CREATE_USER'=>'Erstellungsautor',
'DATE_ANSI'=>'Datum gemäß ANSI-Notation',
'DATE'=>'Datum',
+'DATE_FORMAT_FULL'=>'d.m.Y H:i',
'DATE_FORMAT'=>'d.m.Y',
'DATE_FORMAT_TODAY'=>'H:i',
'DATE_FORMAT_LONG'=>'{weekday}\, d. {month} Y \u\m H:i:s',
diff --git a/modules/language/Language_EN.class.php b/modules/language/Language_EN.class.php
@@ -121,9 +121,10 @@ public function get() { return [
'CREATE_USER'=>'Creation-User',
'DATE_ANSI'=>'Date ANSI notation',
'DATE'=>'Date',
+'DATE_FORMAT_FULL'=>'m/d Y H:i',
'DATE_FORMAT'=>'m/d Y',
'DATE_FORMAT_TODAY'=>'H:i:s',
-'DATE_FORMAT_LONG'=>'l F jS Y, H:i',
+'DATE_FORMAT_LONG'=>'m/d Y H:i',
'DATE_LAST_MONTH'=>'Last month',
'DATE_LAST_YEAR'=>'Last year',
'DATE_MONTH10'=>'October',
diff --git a/modules/language/Language_ES.class.php b/modules/language/Language_ES.class.php
@@ -121,9 +121,10 @@ public function get() { return [
'CREATE_USER'=>'Creationuser',
'DATE_ANSI'=>'Fechar la notación del ANSI',
'DATE'=>'Fechar',
+'DATE_FORMAT_FULL'=>'m/d Y H:i',
'DATE_FORMAT'=>'m/d Y',
-'DATE_FORMAT_TODAY'=>'H: i: s',
-'DATE_FORMAT_LONG'=>'l F jS Y, H:i',
+'DATE_FORMAT_TODAY'=>'H:i:s',
+'DATE_FORMAT_LONG'=>'m/d Y H:i',
'DATE_LAST_MONTH'=>'El mes pasado',
'DATE_LAST_YEAR'=>'El año pasado',
'DATE_MONTH10'=>'Octubre',
diff --git a/modules/language/Language_FR.class.php b/modules/language/Language_FR.class.php
@@ -121,9 +121,10 @@ public function get() { return [
'CREATE_USER'=>'Creationuser',
'DATE_ANSI'=>'Dater la notation de norme ANSI',
'DATE'=>'Dater',
+'DATE_FORMAT_FULL'=>'m/d Y H:i',
'DATE_FORMAT'=>'m/d Y',
-'DATE_FORMAT_TODAY'=>'H : i : s',
-'DATE_FORMAT_LONG'=>'l F jS Y, H:i',
+'DATE_FORMAT_TODAY'=>'H:i:s',
+'DATE_FORMAT_LONG'=>'m/d Y H:i',
'DATE_LAST_MONTH'=>'Le mois dernier',
'DATE_LAST_YEAR'=>'L\'année dernière',
'DATE_MONTH10'=>'Octobre',
diff --git a/modules/language/Language_IT.class.php b/modules/language/Language_IT.class.php
@@ -121,9 +121,10 @@ public function get() { return [
'CREATE_USER'=>'Creationuser',
'DATE_ANSI'=>'Date ANSI notation',
'DATE'=>'la notazione dell\'ANSI della data della data',
+'DATE_FORMAT_FULL'=>'m/d Y H:i',
'DATE_FORMAT'=>'m/d Y',
-'DATE_FORMAT_TODAY'=>'H: i:s',
-'DATE_FORMAT_LONG'=>'l F jS Y, H:i',
+'DATE_FORMAT_TODAY'=>'H:i:s',
+'DATE_FORMAT_LONG'=>'m/d Y H:i',
'DATE_LAST_MONTH'=>'Last month',
'DATE_LAST_YEAR'=>'l\'anno scorso',
'DATE_MONTH10'=>'di ottobre',
diff --git a/modules/language/Language_RU.class.php b/modules/language/Language_RU.class.php
@@ -121,9 +121,10 @@ public function get() { return [
'CREATE_USER'=>'Creationuser',
'DATE_ANSI'=>'Дата ANSI счисления',
'DATE'=>'Дата',
+'DATE_FORMAT_FULL'=>'m/d Y H:i',
'DATE_FORMAT'=>'m/d Y',
-'DATE_FORMAT_TODAY'=>'H: i:s',
-'DATE_FORMAT_LONG'=>'l F jS Y, H:i',
+'DATE_FORMAT_TODAY'=>'H:i:s',
+'DATE_FORMAT_LONG'=>'m/d Y H:i',
'DATE_LAST_MONTH'=>'За последний месяц За последний',
'DATE_LAST_YEAR'=>'Last year',
'DATE_MONTH10'=>'October',
diff --git a/modules/language/Messages.class.php b/modules/language/Messages.class.php
@@ -121,6 +121,7 @@ class Messages {
const CREATE_USER = 'CREATE_USER';
const DATE_ANSI = 'DATE_ANSI';
const DATE = 'DATE';
+ const DATE_FORMAT_FULL = 'DATE_FORMAT_FULL';
const DATE_FORMAT = 'DATE_FORMAT';
const DATE_FORMAT_TODAY = 'DATE_FORMAT_TODAY';
const DATE_FORMAT_LONG = 'DATE_FORMAT_LONG';
diff --git a/modules/language/language.yml b/modules/language/language.yml
@@ -481,23 +481,18 @@ DATE:
fr: Dater
it: "la notazione dell'ANSI della data della data"
ru: Дата
+DATE_FORMAT_FULL:
+ de: "d.m.Y H:i"
+ en: "m/d Y H:i"
DATE_FORMAT:
de: "d.m.Y"
en: "m/d Y"
- es: 'm/d Y'
- fr: 'm/d Y'
- it: "m/d Y"
- ru: 'm/d Y'
DATE_FORMAT_TODAY:
de: "H:i"
en: "H:i:s"
- es: "H: i: s"
- fr: "H : i : s"
- it: "H: i:s"
- ru: "H: i:s"
DATE_FORMAT_LONG:
de: '{weekday}\, d. {month} Y \u\m H:i:s'
- en: "l F jS Y, H:i"
+ en: "m/d Y H:i"
DATE_LAST_MONTH:
de: Letzter Monat
en: Last month