disable login for an increasing amount of time if credentials are wrong

This commit is contained in:
Uwe Steinmann 2020-05-20 10:51:47 +02:00
parent a2e07e34d5
commit fdacbd8c81
7 changed files with 66 additions and 6 deletions

View File

@ -333,6 +333,13 @@ class SeedDMS_Core_User { /* {{{ */
*/
var $_isDisabled;
/**
* @var string date till when the user is disabled
*
* @access protected
*/
var $_disabledUntil;
/**
* @var int number of login failures
*
@ -402,7 +409,7 @@ class SeedDMS_Core_User { /* {{{ */
* @param string $secret
* @param string $webauthn
*/
function __construct($id, $login, $pwd, $fullName, $email, $language, $theme, $comment, $role, $isHidden=0, $isDisabled=0, $pwdExpiration='', $loginFailures=0, $quota=0, $homeFolder=null, $secret='', $webauthn='') {
function __construct($id, $login, $pwd, $fullName, $email, $language, $theme, $comment, $role, $isHidden=0, $isDisabled=0, $pwdExpiration='', $loginFailures=0, $quota=0, $homeFolder=null, $secret='', $webauthn='', $disabledUntil=null) {
$this->_id = $id;
$this->_login = $login;
$this->_pwd = $pwd;
@ -414,6 +421,7 @@ class SeedDMS_Core_User { /* {{{ */
$this->_role = $role;
$this->_isHidden = $isHidden;
$this->_isDisabled = $isDisabled;
$this->_disabledUntil = $disabledUntil;
$this->_pwdExpiration = $pwdExpiration;
$this->_loginFailures = $loginFailures;
$this->_quota = $quota;
@ -463,7 +471,7 @@ class SeedDMS_Core_User { /* {{{ */
$classname = $dms->getClassname('role');
$role = $classname::getInstance($resArr['role'], $dms);
$user = new self($resArr["id"], $resArr["login"], $resArr["pwd"], $resArr["fullName"], $resArr["email"], $resArr["language"], $resArr["theme"], $resArr["comment"], $role, $resArr["hidden"], $resArr["disabled"], $resArr["pwdExpiration"], $resArr["loginfailures"], $resArr["quota"], $resArr["homefolder"], $resArr["secret"], $resArr["webauthn"]);
$user = new self($resArr["id"], $resArr["login"], $resArr["pwd"], $resArr["fullName"], $resArr["email"], $resArr["language"], $resArr["theme"], $resArr["comment"], $role, $resArr["hidden"], $resArr["disabled"], $resArr["pwdExpiration"], $resArr["loginfailures"], $resArr["quota"], $resArr["homefolder"], $resArr["secret"], $resArr["webauthn"], $resArr["disabledUntil"]);
$user->setDMS($dms);
return $user;
} /* }}} */
@ -491,7 +499,7 @@ class SeedDMS_Core_User { /* {{{ */
for ($i = 0; $i < count($resArr); $i++) {
/** @var SeedDMS_Core_User $user */
$role = $classname::getInstance($resArr[$i]['role'], $dms);
$user = new self($resArr[$i]["id"], $resArr[$i]["login"], $resArr[$i]["pwd"], $resArr[$i]["fullName"], $resArr[$i]["email"], (isset($resArr[$i]["language"])?$resArr[$i]["language"]:NULL), (isset($resArr[$i]["theme"])?$resArr[$i]["theme"]:NULL), $resArr[$i]["comment"], $role, $resArr[$i]["hidden"], $resArr[$i]["disabled"], $resArr[$i]["pwdExpiration"], $resArr[$i]["loginfailures"], $resArr[$i]["quota"], $resArr[$i]["homefolder"]);
$user = new self($resArr[$i]["id"], $resArr[$i]["login"], $resArr[$i]["pwd"], $resArr[$i]["fullName"], $resArr[$i]["email"], (isset($resArr[$i]["language"])?$resArr[$i]["language"]:NULL), (isset($resArr[$i]["theme"])?$resArr[$i]["theme"]:NULL), $resArr[$i]["comment"], $role, $resArr[$i]["hidden"], $resArr[$i]["disabled"], $resArr[$i]["pwdExpiration"], $resArr[$i]["loginfailures"], $resArr[$i]["quota"], $resArr[$i]["homefolder"], $resArr[$i]["disabledUntil"]);
$user->setDMS($dms);
$users[$i] = $user;
}
@ -827,6 +835,31 @@ class SeedDMS_Core_User { /* {{{ */
return true;
} /* }}} */
/**
* @param $disabledUntil ''|integer with seconds from now on|date time string
* @return bool
*/
function setDisabledUntil($disabledUntil) { /* {{{ */
$db = $this->_dms->getDB();
if(trim($disabledUntil) == '' || trim($disabledUntil) == 'never')
$queryStr = "UPDATE `tblUsers` SET `disabledUntil` = NULL WHERE `id` = " . $this->_id;
elseif(is_numeric($disabledUntil) && $disabledUntil < 10000)
$queryStr = "UPDATE `tblUsers` SET `disabledUntil` = " . $db->qstr(date('Y-m-d H:i:s', time()+(int)$disabledUntil)) . " WHERE `id` = " . $this->_id;
else
$queryStr = "UPDATE `tblUsers` SET `disabledUntil` = " . $db->qstr($disabledUntil) . " WHERE `id` = " . $this->_id;
if (!$db->getResult($queryStr))
return false;
$this->_disabledUntil = $disabledUntil;
return true;
} /* }}} */
/**
* @return null|string
*/
function getDisabledUntil() { return $this->_disabledUntil; }
/**
* @return bool|int
*/
@ -848,13 +881,18 @@ class SeedDMS_Core_User { /* {{{ */
$db = $this->_dms->getDB();
$this->_loginFailures = 0;
$queryStr = "UPDATE `tblUsers` SET `loginfailures` = " . $this->_loginFailures . " WHERE `id` = " . $this->_id;
$queryStr = "UPDATE `tblUsers` SET `loginfailures` = " . $this->_loginFailures . ", `disabledUntil` = NULL WHERE `id` = " . $this->_id;
if (!$db->getResult($queryStr))
return false;
return true;
} /* }}} */
/**
* @return integer
*/
function getLoginFailures() { return $this->_loginFailures; }
/**
* Calculate the disk space for all documents owned by the user
*

View File

@ -96,6 +96,12 @@ class SeedDMS_Controller_Login extends SeedDMS_Controller_Common {
return false;
}
// Check if account is temporarily disabled
if($settings->_loginDelay && $user->getDisabledUntil() > date('Y-m-d H:i:s')) {
$this->setErrorMsg("login_disabled_until_text");
return false;
}
// control admin IP address if required
if ($user->isAdmin() && ($_SERVER['REMOTE_ADDR'] != $settings->_adminIP ) && ( $settings->_adminIP != "") ){
$this->setErrorMsg("invalid_user_id");

View File

@ -60,11 +60,16 @@ class SeedDMS_DbAuthentication extends SeedDMS_Authentication {
// (and dangerous) for passwords to be sent via GET.
if (md5($password) != $user->getPwd() && !password_verify($password, $user->getPwd())) {
/* if counting of login failures is turned on, then increment its value */
$failures = $user->addLoginFailure();
if($settings->_loginFailure) {
$failures = $user->addLoginFailure();
if($failures >= $settings->_loginFailure)
$user->setDisabled(true);
}
if($settings->_loginDelay) {
if($failures > 1) {
$user->setDisabledUntil(($failures-1)*($failures-1)*3);
}
}
$user = false;
}
}

View File

@ -150,11 +150,16 @@ class SeedDMS_LdapAuthentication extends SeedDMS_Authentication {
}
} elseif($user) {
$userid = $user->getID();
$failures = $user->addLoginFailure();
if($settings->_loginFailure) {
$failures = $user->addLoginFailure();
if($failures >= $settings->_loginFailure)
$user->setDisabled(true);
}
if($settings->_loginDelay) {
if($failures > 1) {
$user->setDisabledUntil(($failures-1)*($failures-1)*3);
}
}
$user = false;
}
ldap_close($ds);

View File

@ -54,6 +54,8 @@ class Settings { /* {{{ */
var $_passwordHistory = 10;
// Number of failed logins before account is disabled
var $_loginFailure = 0;
// increase the login delay between logins after each failed login
var $_loginDelay = false;
// User id that is automatically logged if nobody is logged in
var $_autoLoginUser = 0;
// maximum amount of bytes a user may consume, 0 = unlimited
@ -599,6 +601,7 @@ class Settings { /* {{{ */
$this->_passwordExpiration = intval($tab["passwordExpiration"]);
$this->_passwordHistory = intval($tab["passwordHistory"]);
$this->_loginFailure = intval($tab["loginFailure"]);
$this->_loginDelay = Settings::boolVal($tab["loginDelay"]);
$this->_autoLoginUser = intval($tab["autoLoginUser"]);
$this->_quota = intval($tab["quota"]);
$this->_undelUserIds = strval($tab["undelUserIds"]);
@ -965,6 +968,7 @@ class Settings { /* {{{ */
$this->setXMLAttributValue($node, "passwordExpiration", $this->_passwordExpiration);
$this->setXMLAttributValue($node, "passwordHistory", $this->_passwordHistory);
$this->setXMLAttributValue($node, "loginFailure", $this->_loginFailure);
$this->setXMLAttributValue($node, "loginDelay", $this->_loginDelay);
$this->setXMLAttributValue($node, "autoLoginUser", $this->_autoLoginUser);
$this->setXMLAttributValue($node, "quota", $this->_quota);
$this->setXMLAttributValue($node, "undelUserIds", $this->_undelUserIds);

View File

@ -154,6 +154,7 @@ if ($action == "saveSettings")
$settings->_passwordExpiration = intval($_POST["passwordExpiration"]);
$settings->_passwordHistory = intval($_POST["passwordHistory"]);
$settings->_loginFailure = intval($_POST["loginFailure"]);
$settings->_loginDelay = getBoolValue("loginDelay");
$settings->_autoLoginUser = intval($_POST["autoLoginUser"]);
$settings->_quota = intval($_POST["quota"]);
$settings->_undelUserIds = strval($_POST["undelUserIds"]);

View File

@ -382,6 +382,7 @@ $this->showStartPaneContent('site', (!$currenttab || $currenttab == 'site'));
<?php $this->showConfigText('settings_passwordExpiration', 'passwordExpiration'); ?>
<?php $this->showConfigText('settings_passwordHistory', 'passwordHistory'); ?>
<?php $this->showConfigText('settings_loginFailure', 'loginFailure'); ?>
<?php $this->showConfigCheckbox('settings_loginDelay', 'loginDelay'); ?>
<?php $this->showConfigText('settings_autoLoginUser', 'autoLoginUser'); ?>
<?php $this->showConfigText('settings_quota', 'quota'); ?>
<?php $this->showConfigText('settings_undelUserIds', 'undelUserIds'); ?>