Adding counter for failed login attempts

* Track failed login attempts of a user
* Reset failed attempts as soon as the login succeeded

Fixes #182
This commit is contained in:
Sebastian Grewe 2013-06-13 15:26:23 +02:00
parent 95f98b5f77
commit 5d356b5c4f
2 changed files with 20 additions and 16 deletions

View File

@ -47,6 +47,9 @@ class User {
public function getUserIp($id) { public function getUserIp($id) {
return $this->getSingle($id, 'loggedIp', 'id'); return $this->getSingle($id, 'loggedIp', 'id');
} }
public function getUserFailed($id) {
return $this->getSingle($id, 'failed_logins', 'id');
}
public function getIdFromToken($token) { public function getIdFromToken($token) {
return $this->getSingle($token, 'id', 'token', 's'); return $this->getSingle($token, 'id', 'token', 's');
} }
@ -57,27 +60,23 @@ class User {
return $this->getUserAdmin($id); return $this->getUserAdmin($id);
} }
public function changeLocked($id) { public function changeLocked($id) {
$field = array( $field = array('name' => 'is_locked', 'type' => 'i', 'value' => !$this->isLocked($id));
'name' => 'is_locked',
'type' => 'i',
'value' => !$this->isLocked($id)
);
return $this->updateSingle($id, $field); return $this->updateSingle($id, $field);
} }
public function changeAdmin($id) { public function changeAdmin($id) {
$field = array( $field = array('name' => 'is_admin', 'type' => 'i', 'value' => !$this->isAdmin($id));
'name' => 'is_admin',
'type' => 'i',
'value' => !$this->isAdmin($id)
);
return $this->updateSingle($id, $field); return $this->updateSingle($id, $field);
} }
public function setUserToken($id) { public function setUserToken($id) {
$field = array( $field = array('name' => 'token', 'type' => 's', 'value' => hash('sha256', $id.time().$this->salt));
'name' => 'token', return $this->updateSingle($id, $field);
'type' => 's', }
'value' => hash('sha256', $id.time().$this->salt) 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); return $this->updateSingle($id, $field);
} }
private function setUserIp($id, $ip) { private function setUserIp($id, $ip) {
@ -112,10 +111,14 @@ class User {
} }
if ( $this->checkUserPassword($username, $password)) { if ( $this->checkUserPassword($username, $password)) {
$this->createSession($username); $this->createSession($username);
$this->setUserFailed($this->getUserId($username), 0);
$this->setUserIp($this->getUserId($username), $_SERVER['REMOTE_ADDR']); $this->setUserIp($this->getUserId($username), $_SERVER['REMOTE_ADDR']);
return true; return true;
} }
$this->setErrorMessage("Invalid username or password"); $this->setErrorMessage("Invalid username or password");
if ($id = $this->getUserId($username))
$this->incUserFailed($id);
return false; return false;
} }
@ -213,7 +216,7 @@ class User {
**/ **/
private function updateSingle($id, $field) { private function updateSingle($id, $field) {
$this->debug->append("STA " . __METHOD__, 4); $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()) if ($this->checkStmt($stmt) && $stmt->bind_param($field['type'].'i', $field['value'], $id) && $stmt->execute())
return true; return true;
$this->debug->append("Unable to update " . $field['name'] . " with " . $field['value'] . " for ID $id"); $this->debug->append("Unable to update " . $field['name'] . " with " . $field['value'] . " for ID $id");

View File

@ -0,0 +1 @@
ALTER TABLE `accounts` ADD `failed_logins` INT( 5 ) UNSIGNED NULL DEFAULT '0' AFTER `is_locked` ;