From 93b405ab9f69538546165c75a301c0c57a5359cf Mon Sep 17 00:00:00 2001
From: Camil Staps
Date: Tue, 26 Jul 2016 00:16:17 +0200
Subject: User authentication mechanism
---
README.md | 9 +-
classes/BusinessAdmin.php | 46 +++++++++
classes/constants.php | 5 +-
classes/user.php | 172 +++++++++++++++++++++++++++++++
include/about.php | 3 +-
include/assignments-edit.php | 1 +
include/assignments-new.php | 3 +-
include/assignments-overview.php | 2 +
include/assignments-view.php | 2 +
include/assignments.php | 3 +-
include/clients-edit.php | 3 +-
include/clients-new.php | 3 +-
include/clients-overview.php | 4 +-
include/clients-view.php | 2 +
include/clients.php | 3 +-
include/contacts-edit.php | 3 +-
include/contacts-new.php | 3 +-
include/contacts-overview.php | 4 +-
include/contacts.php | 3 +-
include/discounts-edit.php | 1 +
include/discounts-new.php | 1 +
include/discounts-overview.php | 2 +
include/discounts.php | 1 +
include/home.php | 5 +-
include/offers-edit.php | 3 +-
include/offers-new.php | 3 +-
include/offers-overview.php | 2 +
include/offers-view.php | 2 +
include/offers.php | 3 +-
include/settings.php | 84 +++++++++++++++
index.php | 1 +
install/index.php | 19 ++++
install/upgrade.php | 13 +++
login-ajax.php | 37 +++++++
login.php | 89 ++++++++++++++++
nav.php | 215 ++++++++++++++++++++-------------------
36 files changed, 629 insertions(+), 126 deletions(-)
create mode 100644 classes/user.php
create mode 100644 include/settings.php
create mode 100644 login-ajax.php
create mode 100644 login.php
diff --git a/README.md b/README.md
index fdcfd8e..6c81c39 100644
--- a/README.md
+++ b/README.md
@@ -33,11 +33,6 @@ git clone --recursive https://github.com/camilstaps/BusinessAdmin.git
* Naturally, you should have your server configured to run PHP files with a PHP
backend.
-* BusinessAdmin does not have a user management system. Anyone who has access
- to the URL, has access to the system and all its data. It's therefore
- necessary that you implement HTTP basic authentication. Refer to the
- documentation of your server for how to do that.
-
## Create a database
BusinessAdmin assumes a MySQL database is setup properly. This can be:
@@ -161,6 +156,10 @@ are listed by name and removal time. This way, you never really lose your file.
# Changelog
+### 0.4 (Jul 26, 2016)
+
+0.4 User authentication mechanism
+
### 0.3 (Jul 20, 2016)
0.3 Discounts
diff --git a/classes/BusinessAdmin.php b/classes/BusinessAdmin.php
index dc1f3e7..ce332ee 100644
--- a/classes/BusinessAdmin.php
+++ b/classes/BusinessAdmin.php
@@ -29,6 +29,52 @@ class BusinessAdmin {
// Getters and setters
//------------------------------------------------------------------------------
+ /**
+ * Get all user ids
+ *
+ * @see BusinessAdmin::getUsers() This funtion returns instances of the user class instead of just the ids
+ *
+ * @param PDO $pdo The PDO class for database connection
+ * @param string[] $where An array of WHERE clauses that will be AND-ed into a prepared statement
+ * @param mixed[] $variables An array of variables that should go into the prepared statement
+ *
+ * @throws PDOException Is something went wrong with the database
+ *
+ * @return int[] The ids
+ */
+ public static function getUserIds($pdo, $where = [], $variables = []) {
+ $ids = [];
+ $users = $pdo->prepare("SELECT `id` FROM `".constants::db_prefix."user`" . ((count($where) > 0) ? (" WHERE (" . implode(') AND (', $where) . ")") : ""));
+ $users->execute($variables);
+ $users = $users->fetchAll(PDO::FETCH_ASSOC);
+ foreach ($users as $user) {
+ $ids[] = $user['id'];
+ }
+ return $ids;
+ }
+
+ /**
+ * Get all users
+ *
+ * @see BusinessAdmin::getUserIds() This function returns just the ids of the users, and not instances of the user class
+ *
+ * @param PDO $pdo The PDO class for database connection
+ * @param string[] $where An array of WHERE clauses that will be AND-ed into a prepared statement
+ * @param mixed[] $variables An array of variables that should go into the prepared statement
+ *
+ * @throws PDOException If something went wrong with the database
+ *
+ * @return user[] An array indexed by id of instances of the user class
+ */
+ public static function getUsers($pdo, $where = [], $variables = []) {
+ $ids = self::getUserIds($pdo, $where, $variables);
+ $users = [];
+ foreach ($ids as $id) {
+ $users[$id] = new user($pdo, $id);
+ }
+ return $users;
+ }
+
/**
* Get all client ids
*
diff --git a/classes/constants.php b/classes/constants.php
index d16bde4..77f47b0 100644
--- a/classes/constants.php
+++ b/classes/constants.php
@@ -69,6 +69,9 @@ class constants {
/** @const fa_valuta see http://fontawesome.io/icons/#currency; the fa- postfix for valuta */
const fa_valuta = 'eur';
+ /** @const password_cost for the password_hash function. Run install?password_cost to benchmark your system */
+ const password_cost = 10;
+
/** @const version Version of BusinessAdmin. Don't change this yourself! */
- const version = '0.3';
+ const version = '0.4';
}
diff --git a/classes/user.php b/classes/user.php
new file mode 100644
index 0000000..261fa3d
--- /dev/null
+++ b/classes/user.php
@@ -0,0 +1,172 @@
+.
+ */
+
+/**
+ * An interface to the user table in the database
+ */
+class user {
+ /**
+ * @var pdo $pdo The PDO class for database communication
+ * @var int $id The id of the user
+ * @var string $username The username of the user
+ * @var string $password The (hashed) password of the user
+ */
+ protected $pdo, $id, $username, $password;
+
+ /**
+ * Hash a password
+ *
+ * @param string $password The password to be hashed
+ * @param int $cost The password cost
+ *
+ * @return string The hashed password
+ */
+ public static function hash($password, $cost=null) {
+ return password_hash(
+ $password,
+ PASSWORD_DEFAULT,
+ ['cost' => is_null($cost) ? constants::password_cost : $cost]
+ );
+ }
+
+ /**
+ * Create a new instance
+ *
+ * @param PDO $pdo The PDO class, to access the database
+ * @param int $id The id of the user to fetch
+ *
+ * @throws PDOException If something went wrong with the database
+ * @throws Exception If the user could not be found
+ */
+ public function __construct($pdo, $id) {
+ $this->pdo = $pdo;
+
+ $stmt = $this->pdo->prepare("SELECT * FROM `".constants::db_prefix."user` WHERE `id`=?");
+ $stmt->execute(array($id));
+ if ($stmt->rowCount() == 0) {
+ throw new Exception("The user with id '$id' could not be found.");
+ }
+ $user = $stmt->fetch(PDO::FETCH_ASSOC);
+
+ $this->id = $user['id'];
+ $this->username = $user['username'];
+ $this->password = $user['password'];
+ }
+
+ //------------------------------------------------------------------------------
+ // Getters and setters
+ //------------------------------------------------------------------------------
+
+ /**
+ * Get the ID of the user
+ *
+ * @return int The ID
+ */
+ public function getId() {
+ return $this->id;
+ }
+
+ /**
+ * Get the username of the user
+ *
+ * @return string The username
+ */
+ public function getUsername() {
+ return $this->username;
+ }
+
+ /**
+ * Set the username of the user
+ *
+ * @param string $username The new username for the user
+ *
+ * @throws PDOException If something went wrong with the database
+ *
+ * @return bool True on succes, false on failure
+ */
+ public function setName($username) {
+ $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."user` SET `username`=? WHERE `id`=?");
+ $stmt->execute(array($username, $this->id));
+ if ($stmt->rowCount() == 1) {
+ $this->username = $username;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Set the password of the user
+ *
+ * @param string $password The new password for the user
+ *
+ * @throws PDOException If something went wrong with the database
+ *
+ * @return bool True on succes, false on failure
+ */
+ public function setPassword($password) {
+ $password = self::hash($password);
+ $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."user` SET `password`=? WHERE `id`=?");
+ $stmt->execute(array($password, $this->id));
+ if ($stmt->rowCount() == 1) {
+ $this->password = $password;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ //------------------------------------------------------------------------------
+ // Other functions
+ //------------------------------------------------------------------------------
+
+ /**
+ * Verify a password
+ *
+ * @param string $password The password to verify
+ *
+ * @return bool True iff the password can be accepted
+ */
+ public function verifyPassword($password) {
+ return password_verify($password, $this->password);
+ }
+
+ /**
+ * Remove this user from the database
+ *
+ * If this doesn't succeed (i.e. false is returned), that means the user was removed manually or by another instance of this class
+ *
+ * @throws PDOException If something went wrong with the database
+ *
+ * @return bool True on success, false on failure
+ */
+ public function delete() {
+ $stmt = $this->pdo->prepare("DELETE FROM `".constants::db_prefix."user` WHERE `id`=?");
+ $stmt->execute(array($this->id));
+ if ($stmt->rowCount() != 1) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+}
diff --git a/include/about.php b/include/about.php
index bc93e14..554a80f 100644
--- a/include/about.php
+++ b/include/about.php
@@ -18,6 +18,7 @@
*/
require_once('./index.php');
+require_once('./login.php');
require('./header.php');
?>
@@ -104,4 +105,4 @@ info@camilstaps.nl
\ No newline at end of file
+?>
diff --git a/include/assignments-edit.php b/include/assignments-edit.php
index 4faad64..b52311a 100644
--- a/include/assignments-edit.php
+++ b/include/assignments-edit.php
@@ -18,6 +18,7 @@
*/
require_once('./conf.php');
+require_once('./login-ajax.php');
$response = new response();
diff --git a/include/assignments-new.php b/include/assignments-new.php
index 2de3b1f..7898a42 100644
--- a/include/assignments-new.php
+++ b/include/assignments-new.php
@@ -18,6 +18,7 @@
*/
require_once('./conf.php');
+require_once('./login-ajax.php');
$response = new response();
@@ -42,4 +43,4 @@ try {
$response->success = false;
$response->message = "The assignment could not be created due to an error.";
}
-echo $response->getJson();
\ No newline at end of file
+echo $response->getJson();
diff --git a/include/assignments-overview.php b/include/assignments-overview.php
index 903a772..2de6858 100644
--- a/include/assignments-overview.php
+++ b/include/assignments-overview.php
@@ -16,6 +16,8 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
When you're done, it would be the neatest to remove the /install folder (even though this whole control panel should not be accessible for the public).
diff --git a/install/upgrade.php b/install/upgrade.php index 04cc03a..e145ba7 100644 --- a/install/upgrade.php +++ b/install/upgrade.php @@ -73,6 +73,19 @@ if (isset($_GET['upgrade'])) { } } + if (lower_version($_GET['upgrade'], '0.4')) { + try { + $_pdo->query("CREATE TABLE IF NOT EXISTS `".constants::db_prefix."user` ( + `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT, + `username` varchar(24) NOT NULL, + `password` varchar(255) NOT NULL, + PRIMARY KEY (`id`) + ) ENGINE=InnoDB DEFAULT CHARSET=latin1;"); + } catch (PDOException $e) { + echo "Altering the database structure failed with a PDOException ({$e->getCode()}): {$e->getMessage()}