From 5d356b5c4ff383c26e213a494f034f2057dbbdad Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Thu, 13 Jun 2013 15:26:23 +0200 Subject: [PATCH] Adding counter for failed login attempts * Track failed login attempts of a user * Reset failed attempts as soon as the login succeeded Fixes #182 --- public/include/classes/user.class.php | 35 +++++++++++++++------------ sql/issue_182_accounts_upgrade.sql | 1 + 2 files changed, 20 insertions(+), 16 deletions(-) create mode 100644 sql/issue_182_accounts_upgrade.sql diff --git a/public/include/classes/user.class.php b/public/include/classes/user.class.php index 9d747d34..20ff072d 100644 --- a/public/include/classes/user.class.php +++ b/public/include/classes/user.class.php @@ -47,6 +47,9 @@ class User { public function getUserIp($id) { return $this->getSingle($id, 'loggedIp', 'id'); } + public function getUserFailed($id) { + return $this->getSingle($id, 'failed_logins', 'id'); + } public function getIdFromToken($token) { return $this->getSingle($token, 'id', 'token', 's'); } @@ -57,27 +60,23 @@ class User { return $this->getUserAdmin($id); } public function changeLocked($id) { - $field = array( - 'name' => 'is_locked', - 'type' => 'i', - 'value' => !$this->isLocked($id) - ); + $field = array('name' => 'is_locked', 'type' => 'i', 'value' => !$this->isLocked($id)); return $this->updateSingle($id, $field); } public function changeAdmin($id) { - $field = array( - 'name' => 'is_admin', - 'type' => 'i', - 'value' => !$this->isAdmin($id) - ); + $field = array('name' => 'is_admin', 'type' => 'i', 'value' => !$this->isAdmin($id)); return $this->updateSingle($id, $field); } public function setUserToken($id) { - $field = array( - 'name' => 'token', - 'type' => 's', - 'value' => hash('sha256', $id.time().$this->salt) - ); + $field = array('name' => 'token', 'type' => 's', 'value' => hash('sha256', $id.time().$this->salt)); + return $this->updateSingle($id, $field); + } + private function setUserFailed($id, $value) { + $field = array( 'name' => 'failed_logins', 'type' => 'i', 'value' => $value); + return $this->updateSingle($id, $field); + } + private function incUserFailed($id) { + $field = array( 'name' => 'failed_logins', 'type' => 'i', 'value' => $this->getUserFailed($id) + 1); return $this->updateSingle($id, $field); } private function setUserIp($id, $ip) { @@ -112,10 +111,14 @@ class User { } if ( $this->checkUserPassword($username, $password)) { $this->createSession($username); + $this->setUserFailed($this->getUserId($username), 0); $this->setUserIp($this->getUserId($username), $_SERVER['REMOTE_ADDR']); return true; } $this->setErrorMessage("Invalid username or password"); + if ($id = $this->getUserId($username)) + $this->incUserFailed($id); + return false; } @@ -213,7 +216,7 @@ class User { **/ private function updateSingle($id, $field) { $this->debug->append("STA " . __METHOD__, 4); - $stmt = $this->mysqli->prepare("UPDATE $this->table SET " . $field['name'] . " = ? WHERE id = ? LIMIT 1"); + $stmt = $this->mysqli->prepare("UPDATE $this->table SET `" . $field['name'] . "` = ? WHERE id = ? LIMIT 1"); if ($this->checkStmt($stmt) && $stmt->bind_param($field['type'].'i', $field['value'], $id) && $stmt->execute()) return true; $this->debug->append("Unable to update " . $field['name'] . " with " . $field['value'] . " for ID $id"); diff --git a/sql/issue_182_accounts_upgrade.sql b/sql/issue_182_accounts_upgrade.sql new file mode 100644 index 00000000..62266515 --- /dev/null +++ b/sql/issue_182_accounts_upgrade.sql @@ -0,0 +1 @@ +ALTER TABLE `accounts` ADD `failed_logins` INT( 5 ) UNSIGNED NULL DEFAULT '0' AFTER `is_locked` ;