From d58816c09edb3d1e2da2251ed4ea3a6657a1a06c Mon Sep 17 00:00:00 2001
From: Marius Cramer <m.cramer@pixcept.de>
Date: Tue, 18 Feb 2014 08:49:16 -0500
Subject: [PATCH] Removed code line from previous commit

---
 server/plugins-available/mongo_clientdb_plugin.inc.php |  831 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 831 insertions(+), 0 deletions(-)

diff --git a/server/plugins-available/mongo_clientdb_plugin.inc.php b/server/plugins-available/mongo_clientdb_plugin.inc.php
new file mode 100644
index 0000000..2f38112
--- /dev/null
+++ b/server/plugins-available/mongo_clientdb_plugin.inc.php
@@ -0,0 +1,831 @@
+<?php
+
+/*
+Copyright (c) 2007, Till Brehm, projektfarm Gmbh
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+    * Neither the name of ISPConfig nor the names of its contributors
+      may be used to endorse or promote products derived from this software without
+      specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * The MongoDB client plugin is used by ISPConfig to control the management of MongoDB.
+ * If handles everything from creating DBs/Users, update them or delete them.
+ */
+
+
+class mongo_clientdb_plugin {
+
+	/**
+	 * ISPConfig internal identifiers.
+	 */
+	var $plugin_name = 'mongo_clientdb_plugin';
+	var $class_name  = 'mongo_clientdb_plugin';
+
+
+	/**
+	 * This function is called during ISPConfig installation.
+	 * It determines if a symlink shall be created for this plugin.
+	 *
+	 * @return bool true if symlink should be created
+	 */
+	function onInstall() {
+		global $conf;
+		
+		if($conf['services']['db'] == true && class_exists('MongoClient')) {
+			return true;
+		} else {
+			return false;
+		}
+	}
+
+
+	/**
+	 * This function is called when the plugin is loaded.
+	 * Each plugin/module needs to register itself to ISPConfig events from which
+	 * it want to receive changes/get notified.
+	 *
+	 * Since this is a MongoDB plugin we are interested in DB changes and everything related
+	 * to it, like users.
+	 */
+	function onLoad() {
+		global $app;
+
+		//* Databases
+		$app->plugins->registerEvent('database_insert', $this->plugin_name, 'db_insert');
+		$app->plugins->registerEvent('database_update', $this->plugin_name, 'db_update');
+		$app->plugins->registerEvent('database_delete', $this->plugin_name, 'db_delete');
+
+		//* Database users
+		$app->plugins->registerEvent('database_user_insert', $this->plugin_name, 'db_user_insert');
+		$app->plugins->registerEvent('database_user_update', $this->plugin_name, 'db_user_update');
+		$app->plugins->registerEvent('database_user_delete', $this->plugin_name, 'db_user_delete');
+	}
+
+
+	/**
+	 * MongoDB
+	 * ------------------------------------------------------------------------
+	 * The following needs to be done before using this plugin:
+	 * - 1. install MongoDB server from 10gen sources (or another one with >= 2.4)
+	 * - 2. install php5-dev package (apt-get install php5-dev)
+	 * - 3. install mongo PECL extension (pecl install mongo)
+	 * - 4. enable mongo (echo "extension=mongo.so" > /etc/php5/mods-available/mongo.ini && php5enmod mongo)
+	 * - 5. create administrative user manager in Mongo (mongo -> use admin -> db.addUser({user: "root", pwd: "123456", roles: [ "userAdminAnyDatabase", "readWriteAnyDatabase", "dbAdminAnyDatabase", "clusterAdmin" ]}))
+	 * - 6. enable auth for Mongo (nano /etc/mongodb.conf -> auth = true)
+	 * - 7. restart MongoDB (service mongodb restart)
+	 *
+	 * Unlike MySQL, MongoDB manages users per database.
+	 * Therefor we cannot use one user for multiple databases. Instead, we have to add him each time via the admin user.
+	 */
+
+	/**
+	 * Stores the MongoDB connection.
+	 * @var object
+	 */
+	private $_connection = null;
+
+	/**
+	 * Stores the MongoDB admin user.
+	 * @var string
+	 */
+	const USER = "root";
+
+	/**
+	 * Stores the MongoDB admin password.
+	 * @var string
+	 */
+	const PW = "123456";
+
+	/**
+	 * Stores the MongoDB host address.
+	 * @var string
+	 */
+	const HOST = "127.0.0.1";
+
+	/**
+	 * Stores the MongoDB port.
+	 * @var int
+	 */
+	const PORT = 27017;
+
+	/**
+	 * Adds the user to given database.
+	 * If no connection exists, the user already exists or the database doesn't exist,
+	 * null is returned.
+	 *
+	 * @param string $db the database to use
+	 * @param array $user the user to add
+	 * @return bool true if user added
+	 */
+	private function addUser($db, $user) {
+		if ($this->isConnected() && !$this->userExists($db, $user)) {
+			$roles = "";
+
+			foreach ($user['roles'] as $index => $role) {
+				$roles .= "\"".$role."\"";
+
+				if ($index !== count($user['roles']) - 1) {
+					$roles .= ", ";
+				}
+			}
+
+			return $this->exec($db, "db.system.users.insert({ user: \"".$user['username']."\", pwd: \"".$user['password']."\", roles: [ ".$roles." ] })");
+			//return $this->exec($db, "db.addUser({ user: \"".$user['username']."\", pwd: \"".$user['password']."\", roles: [ ".$roles." ] })");
+		}
+
+		return null;
+	}
+
+	/**
+	 * Changes the users password in given DB.
+	 * If no connection exists, the user doesn't exist or the DB doesn't exist,
+	 * null is returned.
+	 *
+	 * @param string $db the database name
+	 * @param string $user the user to change
+	 * @param string $password the new password
+	 * @return bool true if password changes
+	 */
+	private function changePassword($db, $user, $password) {
+		if ($this->isConnected() && $this->dbExists($db) && $this->userExists($db, $user)) {
+			$old_user = $this->getUser($db, $user);
+
+			if ($this->dropUser($user, $db)) {
+				return $this->addUser($db, array(
+						'username' => $user,
+						'password' => $password,
+						'roles' => $old_user['roles']
+					));
+			}
+
+			return false;
+		}
+
+		return null;
+	}
+
+	/**
+	 * Connects to the server and authentificates.
+	 * If the authentificaten goes wrong or another error encounters,
+	 * false is returned.
+	 * If we already have an open connection we try to disconnect and connect again.
+	 * If this fails, false is returned.
+	 *
+	 * @return object $connection the MongoDB connection
+	 */
+	private function connect() {
+		try {
+			if ($this->isConnected() && !$this->disconnect()) {
+				return false;
+			}
+
+			$this->_connection = new MongoClient("mongodb://".self::USER.":".self::PW."@".self::HOST.":".self::PORT."/admin");
+
+			return $this->_connection;
+		} catch (MongoConnnectionException $e) {
+			$app->log('Unable to connect to MongoDB: '.$e, LOGLEVEL_ERROR);
+			$this->_connection = null;
+
+			return false;
+		}
+	}
+
+	/**
+	 * Checks if the database exists.
+	 * If no connection exists,
+	 * null is returned.
+	 *
+	 * @param string $db the database name
+	 * @return bool true if exists
+	 */
+	private function dbExists($db) {
+		if ($this->isConnected()) {
+			return in_array($db, $this->getDBs());
+		}
+
+		return null;
+	}
+
+	/**
+	 * Closes the MongoDB connection.
+	 * If no connection exists and nothing is done,
+	 * null is returned.
+	 *
+	 * @return bool true if closed
+	 */
+	private function disconnect() {
+		if ($this->isConnected()) {
+			$status = $this->_connection->close();
+
+			if ($status) {
+				$this->_connection = null;
+			}
+
+			return $status;
+		}
+
+		return null;
+	}
+
+	/**
+	 * Drops the given database.
+	 * If no connection exists or the database doesn't exist,
+	 * null is returned.
+	 *
+	 * @param string $db the database's to drop name
+	 */
+	private function dropDB($db) {
+		if ($this->isConnected() && $this->dbExists($db)) {
+			return (bool) $this->_connection->dropDB($db)['ok'];
+		}
+
+		return null;
+	}
+
+	/**
+	 * Drops the given user from database.
+	 * If no DB is defined, the user is dropped from all databases.
+	 * If there's an error when dropping the user from all DBs, an array containing the
+	 * names of the failed DBs is returned.
+	 * If no connection exists, the database doesn't exist or the user is not in DB,
+	 * null is returned.
+	 *
+	 * @param string $user the user to drop
+	 * @param string $db the database name
+	 * @return bool true if dropped
+	 */
+	private function dropUser($user, $db = null) {
+		if ($this->isConnected()) {
+			if ($db !== null && $this->dbExists($db) && $this->userExists($db, $user)) {
+				return $this->exec($db, "db.removeUser(\"".$user."\")");
+			} else {
+				$dbs = $this->getDBs();
+
+				if ((bool) $dbs) {
+					$failures = array();
+
+					foreach ($dbs as $db) {
+						$exists = $this->userExists($db, $user);
+
+						if ($exists) {
+							if (!$this->dropUser($user, $db)) {
+								$failures[] = $db;
+							}
+						}
+					}
+				}
+
+				return (bool) $failures ? $failures : true;
+			}
+		}
+
+		return null;
+	}
+
+	/**
+	 * Executed the command on the MongoDB server.
+	 * If no connection exists and thus nothing can be done,
+	 * null is returned.
+	 *
+	 * @param string $db the database to query
+	 * @param string $query the command to execute
+	 * @return array the result of the query
+	 */
+	private function exec($db, $query) {
+		if ($this->isConnected()) {
+			$db = $this->selectDB($db);
+			$result = $db->execute($query);
+
+			if ((bool) $result['ok']) {
+				return $result;
+			}
+
+			return false;
+		}
+
+		return null;
+	}
+
+	/**
+	 * Checks if the connection exists.
+	 *
+	 * @return true if connected
+	 */
+	private function isConnected() {
+		return $this->_connection !== null;
+	}
+
+	/**
+	 * Generates a MongoDB compatible password.
+	 *
+	 * @param string $user the username
+	 * @param string $password the user password
+	 * @return string the MD5 string
+	 */
+	private function generatePassword($user, $password) {
+		return md5($user.":mongo:".$password);
+	}
+
+	/**
+	 * Returns the databases found on connection.
+	 * If no connection exists and therefor no DBs can be found,
+	 * null is returned.
+	 *
+	 * @return array $names the databases's name
+	 */
+	private function getDBs() {
+		if ($this->isConnected()) {
+			$dbs = $this->_connection->listDBs();
+
+			if ((bool) $dbs && isset($dbs['databases'])) {
+				$names = array();
+
+				foreach ($dbs['databases'] as $db) {
+					$names[] = $db['name'];
+				}
+
+				return $names;
+			}
+		}
+
+		return null;
+	}
+
+	/**
+	 * Returns the user entry for given database.
+	 * If no connection exists, the database doesn't exist or the user doesn't exist
+	 * null is returned.
+	 *
+	 * @param string $db the database name
+	 * @param string $user the user to return
+	 * @return array $user the user in DB
+	 */
+	private function getUser($db, $user) {
+		if ($this->isConnected() && $this->dbExists($db) && $this->userExists($db, $user)) {
+			$result = $this->selectDB($db)->selectCollection("system.users")->find(array( 'user' => $user ));
+
+			// ugly fix to return user
+			foreach ($result as $user) {
+				return $user;
+			}
+		}
+
+		return null;
+	}
+
+	/**
+	 * Returns the users for given database.
+	 * If no connection exists or the database doesn't exist,
+	 * null is returned.
+	 *
+	 * @param string $db the database name
+	 * @return array $users the users in DB
+	 */
+	private function getUsers($db) {
+		if ($this->isConnected() && $this->dbExists($db)) {
+			$result = $this->selectDB($db)->selectCollection("system.users")->find();
+
+			$users = array();
+
+			foreach ($result as $record) {
+				$users[] = $record['user'];
+			}
+
+			return $users;
+		}
+
+		return null;
+	}
+
+	/**
+	 * Checks if the given user exists in given database.
+	 * If no connection exists or the given database doesn't exist
+	 * null is returned.
+	 *
+	 * @param string $db the database name
+	 * @param string $user the user to check
+	 * @return bool true if user exists
+	 */
+	private function userExists($db, $user) {
+		if ($this->isConnected() && $this->dbExists($db)) {
+			$users = $this->getUsers($db);
+
+			return in_array($user, $users);
+		}
+
+		return null;
+	}
+
+	/**
+	 * Renames the MongoDB database to provided name.
+	 * If no connection exists, the source DB doesn't exist or the target DB already exists,
+	 * null is returned.
+	 *
+	 * @param string $old_name the old database name
+	 * @param string $new_name the new database name
+	 * @return bool true if renamed
+	 */
+	private function renameDB($old_name, $new_name) {
+		if ($this->isConnected() && $this->dbExists($old_name) && !$this->dbExists($new_name)) {
+			if ($this->exec($old_name, "db.copyDatabase(\"".$old_name."\", \"".$new_name."\", \"".self::HOST."\", \"".self::USER."\", \"".self::PW."\")")) {
+				$this->dropDB($old_name);
+
+				return true;
+			}
+
+			return false;
+		}
+
+		return null;
+	}
+
+	/**
+	 * Switched the selected database.
+	 * MongoDB acts on a per-DB level (user management) and we always need to
+	 * ensure we have the right DB selected.
+	 * If no connection exists and thus nothing is done,
+	 * null is returned.
+	 *
+	 * @param string $db the database to use
+	 * @return object the MongoDB database object
+	 */
+	private function selectDB($db) {
+		if ($this->isConnected()) {
+			return $this->_connection->selectDB($db);
+		}
+
+		return null;
+	}
+
+
+	/**
+	 * This function is called when a DB is created from within the ISPConfig3 interface.
+	 * We need to create the DB and allow all users to connect to it that are choosen.
+	 * Since MongoDB doesn't create a DB before any data is stored in it, it's important
+	 * to store the users so it contains data -> is created.
+	 *
+	 * @param string $event_name the name of the event (insert, update, delete)
+	 * @param array $data the event data (old and new)
+	 * @return only if something is wrong
+	 */
+	function db_insert($event_name, $data) {
+		global $app, $conf;
+
+		// beside checking for MongoDB we also check if the DB is active because only then we add users
+		// -> MongoDB needs users to create the DB
+		if ($data['new']['type'] == 'mongo' && $data['new']['active'] == 'y') {
+			if ($this->connect() === false) {
+				$app->log("Unable to connect to MongoDB: Connecting using connect() failed.", LOGLEVEL_ERROR);
+				return;
+			}
+
+			$db_user = $app->db->queryOneRecord("SELECT `database_user`, `database_password_mongo` FROM `web_database_user` WHERE `database_user_id` = '" . intval($data['new']['database_user_id']) . "'");
+			$db_ro_user = $app->db->queryOneRecord("SELECT `database_user`, `database_password_mongo` FROM `web_database_user` WHERE `database_user_id` = '" . intval($data['new']['database_ro_user_id']) . "'");
+
+			$user = $db_user['database_user'];
+			$password = $db_user['database_password_mongo'];
+
+			$ro_user = $db_ro_user['database_user'];
+			$ro_password = $db_ro_user['database_password_mongo'];
+
+			$db = $data['new']['database_name'];
+
+			if ((bool) $db_user) {
+				if ($user == 'root') {
+					$app->log("User root not allowed for client databases", LOGLEVEL_WARNING);
+				} else {
+					if (!$this->addUser($db, array(
+								'username' => $user,
+								'password' => $password,
+								'roles' => array(
+									"readWrite",
+									"dbAdmin"
+								)
+							))) {
+						$app->log("Error while adding user: ".$user." to DB: ".$db, LOGLEVEL_WARNING);
+					}
+				}
+			}
+
+			if ($db_ro_user && $data['new']['database_user_id'] != $data['new']['database_ro_user_id']) {
+				if ($user == 'root') {
+					$app->log("User root not allowed for client databases", LOGLEVEL_WARNING);
+				} else {
+					if (!$this->addUser($db, array(
+								'username' => $ro_user,
+								'password' => $ro_password,
+								'roles' => array(
+									"read"
+								)
+							))) {
+						$app->log("Error while adding read-only user: ".$user." to DB: ".$db, LOGLEVEL_WARNING);
+					}
+				}
+			}
+
+			$this->disconnect();
+		}
+	}
+
+
+	/**
+	 * This function is called when a DB is updated from within the ISPConfig interface.
+	 * Updating the DB needs a lot of changes. First, we need to recheck all users that
+	 * have permissions to access the DB. Maybe we also need to rename the DB and change
+	 * it's type (MySQL, MongoDB etc.)...hard work here :)
+	 *
+	 * @param string $event_name the name of the event (insert, update, delete)
+	 * @param array $data the event data (old and new)
+	 * @return only if something is wrong
+	 */
+	function db_update($event_name, $data) {
+		global $app, $conf;
+
+		if ($data['old']['active'] == 'n' && $data['new']['active'] == 'n') {
+			return;
+		}
+
+		// currently switching from MongoDB <-> MySQL isn't supported
+		if ($data['old']['type'] == 'mongo' && $data['new']['type'] == 'mongo') {
+			if ($this->connect() === false) {
+				$app->log("Unable to connect to MongoDB: Connecting using connect() failed.", LOGLEVEL_ERROR);
+				return;
+			}
+
+			$db_user = $app->db->queryOneRecord("SELECT `database_user`, `database_password_mongo` FROM `web_database_user` WHERE `database_user_id` = '" . intval($data['new']['database_user_id']) . "'");
+			$db_ro_user = $app->db->queryOneRecord("SELECT `database_user`, `database_password_mongo` FROM `web_database_user` WHERE `database_user_id` = '" . intval($data['new']['database_ro_user_id']) . "'");
+
+			$user = $db_user['database_user'];
+			$password = $db_user['database_password_mongo'];
+
+			$ro_user = $db_ro_user['database_user'];
+			$ro_password = $db_ro_user['database_password_mongo'];
+
+			$db = $data['new']['database_name'];
+
+			// create the database user if database was disabled before
+			if ($data['new']['active'] == 'y' && $data['old']['active'] == 'n') {
+				// since MongoDB creates DBs on-the-fly we can use the db_insert method which takes care of adding
+				// users to a given DB
+				$this->db_insert($event_name, $data);
+			} else if ($data['new']['active'] == 'n' && $data['old']['active'] == 'y') {
+					$users = $this->getUsers($db);
+
+					if ((bool) $users) {
+						foreach ($users as $user) {
+							$this->dropUser($user, $db);
+						}
+					}
+				} else {
+				// selected user has changed -> drop old one
+				if ($data['new']['database_user_id'] != $data['old']['database_user_id']) {
+					$old_db_user = $app->db->queryOneRecord("SELECT `database_user`, `database_password_mongo` FROM `web_database_user` WHERE `database_user_id` = '" . intval($data['old']['database_user_id']) . "'");
+
+					if ((bool) $old_db_user) {
+						if ($old_db_user['database_user'] == 'root') {
+							$app->log("User root not allowed for client databases", LOGLEVEL_WARNING);
+						} else {
+							$this->dropUser($old_db_user['database_user'], $db);
+						}
+					}
+				}
+
+				// selected read-only user has changed -> drop old one
+				if ($data['new']['database_ro_user_id'] != $data['old']['database_ro_user_id']) {
+					$old_db_user = $app->db->queryOneRecord("SELECT `database_user`, `database_password_mongo` FROM `web_database_user` WHERE `database_user_id` = '" . intval($data['old']['database_ro_user_id']) . "'");
+
+					if ((bool) $old_db_user) {
+						if ($old_db_user['database_user'] == 'root') {
+							$app->log("User root not allowed for client databases", LOGLEVEL_WARNING);
+						} else {
+							$this->dropUser($old_db_user['database_user'], $db);
+						}
+					}
+				}
+
+				// selected user has changed -> add new one
+				if ($data['new']['database_user_id'] != $data['old']['database_user_id']) {
+					if ((bool) $db_user) {
+						if ($user == 'root') {
+							$app->log("User root not allowed for client databases", LOGLEVEL_WARNING);
+						} else {
+							$this->addUser($db, array(
+									'username' => $user,
+									'password' => $password,
+									'roles' => array(
+										"readWrite",
+										"dbAdmin"
+									)
+								));
+						}
+					}
+				}
+
+				// selected read-only user has changed -> add new one
+				if ($data['new']['database_ro_user_id'] != $data['old']['database_ro_user_iduser_id']) {
+					if ((bool) $db_ro_user && $data['new']['database_user_id'] != $data['new']['database_ro_user_id']) {
+						if ($ro_user == 'root') {
+							$app->log("User root not allowed for client databases", LOGLEVEL_WARNING);
+						} else {
+							$this->addUser($db, array(
+									'username' => $ro_user,
+									'password' => $ro_password,
+									'roles' => array(
+										"read"
+									)
+								));
+						}
+					}
+				}
+
+				// renamed?
+				/*
+				if ($data['old']['database_name'] != $data['new']['database_name']) {
+					$old_name = $data['old']['database_name'];
+					$new_name = $data['new']['database_name'];
+
+					if ($this->renameDB($oldName, $newName)) {
+						$app->log("Renamed MongoDB database: ".$old_name." -> ".$new_name, LOGLEVEL_DEBUG);
+					} else {
+						$app->log("Renaming MongoDB database failed: ".$old_name." -> ".$new_name, LOGLEVEL_WARNING);
+					}
+				}
+				*/
+			}
+
+			// switching from MySQL <-> Mongo isn't supported
+			// no idea what we should do here...would be best to permit in interface?
+
+			// remote access isn't supported by MongoDB (limiting to IP),
+			// we therefor don't listen for it's changes
+		}
+
+		$this->disconnect();
+	}
+
+
+	/**
+	 * This function is called when a DB is deleted from within the ISPConfig interface.
+	 * All we need to do is to delete the database.
+	 *
+	 * @param string $event_name the name of the event (insert, update, delete)
+	 * @param array $data the event data (old and new)
+	 * @return only if something is wrong
+	 */
+	function db_delete($event_name, $data) {
+		global $app, $conf;
+
+		if ($data['old']['type'] == 'mongo') {
+			if ($this->connect() === false) {
+				$app->log("Unable to connect to MongoDB: Connecting using connect() failed.", LOGLEVEL_ERROR);
+				return;
+			}
+
+			$db_to_drop = $data['old']['database_name'];
+
+			if ($this->dropDB($db_to_drop)) {
+				$app->log("Dropping MongoDB database: ".$db_to_drop, LOGLEVEL_DEBUG);
+			} else {
+				$app->log("Error while dropping MongoDB database: ".$db_to_drop, LOGLEVEL_WARNING);
+			}
+
+			$this->disconnect();
+		}
+	}
+
+
+	/**
+	 * This function is called when a user is inserted from within the ISPConfig interface.
+	 * Since users are separated from databases we don't do anything here.
+	 * As soon as an user is associated to a DB, we add him there.
+	 *
+	 * @param string $event_name the name of the event (insert, update, delete)
+	 * @param array $data the event data (old and new)
+	 */
+	function db_user_insert($event_name, $data) {}
+
+
+	/**
+	 * This function is called when a user is updated from within the ISPConfig interface.
+	 * The only thing we need to listen for here are password changes.
+	 * We than need to change those in all databases the user uses.
+	 *
+	 * @param string $event_name the name of the event (insert, update, delete)
+	 * @param array $data the event data (old and new)
+	 * @return only if something is wrong
+	 */
+	function db_user_update($event_name, $data) {
+		global $app, $conf;
+
+		if ($data['old']['database_user'] == $data['new']['database_user']
+			&& ($data['old']['database_password'] == $data['new']['database_password']
+				|| $data['new']['database_password'] == '')) {
+			return;
+		}
+
+		if ($this->connect() === false) {
+			$app->log("Unable to connect to MongoDB: Connecting using connect() failed.", LOGLEVEL_ERROR);
+			return;
+		}
+
+		if ($data['old']['database_user'] != $data['new']['database_user']) {
+			// username has changed
+			$dbs = $this->getDBs();
+
+			if ((bool) $dbs) {
+				foreach ($dbs as $db) {
+					if ($this->userExists($db, $data['old']['database_user'])) {
+						if (!$this->userExists($db, $data['new']['database_user'])) {
+							$user = $this->getUser($db, $data['old']['database_user']);
+
+							if ($this->dropUser($data['old']['database_user'], $db)) {
+								if ($this->addUser($db, array(
+											'username' => $data['new']['database_user'],
+											'password' => md5($data['new']['database_password_mongo']),
+											'roles' => $user['roles']
+										))) {
+									$app->log("Created user: ".$data['new']['database_user']." in DB: ".$db, LOGLEVEL_DEBUG);
+								} else {
+									$app->log("Couldn't create user: ".$data['new']['database_user']." in DB: ".$db, LOGLEVEL_WARNING);
+								}
+							} else {
+								$app->log("Couldn't drop user: ".$data['old']['database_user']." in DB: ".$db, LOGLEVEL_WARNING);
+							}
+						} else {
+							$app->log("User: ".$data['new']['database_user']." already exists in DB: ".$db, LOGLEVEL_WARNING);
+						}
+					}
+				}
+			}
+		}
+
+		if ($data['old']['database_password'] != $data['new']['database_password']
+			|| $data['old']['database_user'] != $data['new']['database_user']) {
+			// password only has changed
+			$dbs = $this->getDBs();
+
+			if ((bool) $dbs) {
+				foreach ($dbs as $db) {
+					if ($this->userExists($db, $data['new']['database_user'])) {
+						if ($this->changePassword($db, $data['new']['database_user'], md5($data['new']['database_password_mongo']))) {
+							$app->log("Changed user's: ".$data['new']['database_user']." password in DB: ".$db, LOGLEVEL_DEBUG);
+						} else {
+							$app->log("Couldn't change user's: ".$data['new']['database_user']." password in DB: ".$db, LOGLEVEL_WARNING);
+						}
+					}
+				}
+			}
+		}
+
+		$this->disconnect();
+	}
+
+
+	/**
+	 * This function is called when a user is deleted from within the ISPConfig interface.
+	 * Since MongoDB uses per-DB user management, we have to find every database where the user is
+	 * activated and delete him there.
+	 *
+	 * @param string $event_name the name of the event (insert, update, delete)
+	 * @param array $data the event data (old and new)
+	 * @return only if something is wrong
+	 */
+	function db_user_delete($event_name, $data) {
+		global $app, $conf;
+
+		if ($this->connect() === false) {
+			$app->log("Unable to connect to MongoDB: Connecting using connect() failed.", LOGLEVEL_ERROR);
+			return;
+		}
+
+		if ($this->dropUser($data['old']['database_user']) === true) {
+			$app->log("Dropped MongoDB user: ".$data['old']['database_user'], LOGLEVEL_DEBUG);
+		} else {
+			$app->log("Error while dropping MongoDB user: ".$data['old']['database_user'], LOGLEVEL_WARNING);
+		}
+
+		$this->disconnect();
+	}
+
+}

--
Gitblit v1.9.1