3 * Bacula(R) - The Network Backup Solution
4 * Baculum - Bacula web interface
6 * Copyright (C) 2013-2016 Kern Sibbald
8 * The main author of Baculum is Marcin Haba.
9 * The original author of Bacula is Kern Sibbald, with contributions
10 * from many others, a complete list can be found in the file AUTHORS.
12 * You may use this file and others of this release according to the
13 * license defined in the LICENSE file, which includes the Affero General
14 * Public License, v3.0 ("AGPLv3") and some additional permissions and
15 * terms pursuant to its AGPLv3 Section 7.
17 * This notice must be preserved when any source code is
18 * conveyed and/or propagated.
20 * Bacula(R) is a registered trademark of Kern Sibbald.
23 Prado::using('Application.Class.Miscellaneous');
26 * Manage application configuration.
27 * Module is responsible for get/set application config data like:
28 * read/write application config and usersfiles, get application language
31 * @author Marcin Haba <marcin.haba@bacula.pl>
33 class ConfigurationManager extends TModule
37 * Application config file path
39 const CONFIG_FILE = 'Application.Data.settings';
42 * Users login and password file for HTTP Basic auth.
44 const USERS_FILE = 'Application.Data.baculum';
47 * User name allowed characters pattern
49 const USER_PATTERN = '[a-zA-Z0-9]+';
52 * PostgreSQL default params
54 const PGSQL = 'pgsql';
55 const PGSQL_NAME = 'PostgreSQL';
56 const PGSQL_PORT = 5432;
59 * MySQL default params
61 const MYSQL = 'mysql';
62 const MYSQL_NAME = 'MySQL';
63 const MYSQL_PORT = 3306;
66 * SQLite default params
68 const SQLITE = 'sqlite';
69 const SQLITE_NAME = 'SQLite';
70 const SQLITE_PORT = null;
73 * Default application language
75 const DEFAULT_LANGUAGE = 'en';
78 * Get database name by database type (short name).
81 * @param string $type database type ('pgsql', 'mysql' ...)
82 * @return mixed database name or null if database name not found
84 public function getDbNameByType($type) {
85 $type = (string) $type;
87 case self::PGSQL: $db_name = self::PGSQL_NAME; break;
88 case self::MYSQL: $db_name = self::MYSQL_NAME; break;
89 case self::SQLITE: $db_name = self::SQLITE_NAME; break;
90 default: $db_name = null; break;
96 * Check if given database type is PostgreSQL type.
99 * @param string $type database type ('pgsql', 'mysql' ...)
100 * @return boolean true if database type is PostgreSQL, otherwise false
102 public function isPostgreSQLType($type) {
103 return ($type === self::PGSQL);
107 * Check if given database type is MySQL type.
110 * @param string $type database type ('pgsql', 'mysql' ...)
111 * @return boolean true if database type is MySQL, otherwise false
113 public function isMySQLType($type) {
114 return ($type === self::MYSQL);
118 * Check if given database type is SQLite type.
121 * @param string $type database type ('sqlite', 'mysql' ...)
122 * @return boolean true if database type is SQLite, otherwise false
124 public function isSQLiteType($type) {
125 return ($type === self::SQLITE);
129 * Get currently set application language short name.
130 * If no language set then default language is taken.
133 * @return string lanuage short name
135 public function getLanguage() {
136 $language = self::DEFAULT_LANGUAGE;
137 if ($this->isApplicationConfig() === true) {
138 $config = self::getApplicationConfig();
139 if (array_key_exists('lang', $config['baculum'])) {
140 $language = $config['baculum']['lang'];
147 * Save application configuration.
150 * @param array $config structure of config file params
151 * @return boolean true if config save is successfully, false if config save is failure
153 public function setApplicationConfig(array $config) {
154 $cfg_file = Prado::getPathOfNamespace(self::CONFIG_FILE, '.conf');
155 return ($this->Application->getModule('misc')->writeINIFile($cfg_file, $config) != false);
159 * Get application configuration.
162 * @return array application configuration
164 public static function getApplicationConfig() {
165 $cfg_file = Prado::getPathOfNamespace(self::CONFIG_FILE, '.conf');
166 return Miscellaneous::parseINIFile($cfg_file);
170 * Check if application configuration file exists.
173 * @return boolean true if file exists, otherwise false
175 public function isApplicationConfig() {
176 return file_exists(Prado::getPathOfNamespace(self::CONFIG_FILE, '.conf'));
180 * Get user name allowed characters pattern
183 * @return string user name pattern
185 public function getUserPattern() {
186 return self::USER_PATTERN;
190 * Get encrypted password to use in HTTP Basic auth.
193 * @param string $password plain text password
194 * @return string encrypted password
196 public function getCryptedPassword($password) {
197 $enc_pwd = crypt($password, base64_encode($password));
202 * Save user to users configuration file.
205 * @param string $user username
206 * @param string $password user's password
207 * @param boolean $first_usage determine if it is first saved user during first Baculum run
208 * @param mixed $old_user previous username before change
209 * @return boolean true if user saved successfully, otherwise false
211 public function setUsersConfig($user, $password, $first_usage = false, $old_user = null) {
212 if ($first_usage === true) {
213 $this->clearUsersConfig();
216 $all_users = $this->getAllUsers();
217 $password = $this->getCryptedPassword($password);
219 $userExists = array_key_exists($user, $all_users);
222 if ($userExists === true) {
223 // update user password;
224 $all_users[$user] = $password;
227 if (!is_null($old_user) && $old_user !== $user) {
228 // delete old username with password from configuration file
229 if (array_key_exists($old_user, $all_users)) {
230 unset($all_users[$old_user]);
234 // add new user if does not exist
235 if ($userExists === false) {
236 $all_users[$user] = $password;
239 $result = $this->saveUserConfig($all_users);
244 * Read all users from HTTP Basic users file.
245 * Returned value is associative array with usernames as keys
246 * and encrypted passwords as values.
249 * @return array users/passwords list
251 public function getAllUsers() {
252 $all_users = array();
253 if ($this->isUsersConfig() === true) {
254 $users_file = Prado::getPathOfNamespace(self::USERS_FILE, '.users');
255 $users = file($users_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
257 for($i = 0; $i < count($users); $i++) {
258 if (preg_match("/^(?P<user>\S+)\:(?P<hash>\S+)$/", $users[$i], $match) === 1) {
259 $all_users[$match['user']] = $match['hash'];
267 * Save HTTP Basic users file.
268 * Given parameter is associative array with usernames as keys
269 * and encrypted passwords as values.
272 * @param array $all_users users/passwords list
273 * @return boolean true if users file saved successfully, otherwise false
275 public function saveUserConfig($all_users) {
277 foreach ($all_users as $user => $pwd) {
278 $users[] = "$user:$pwd";
280 $users_file = Prado::getPathOfNamespace(self::USERS_FILE, '.users');
281 $usersToFile = implode("\n", $users);
282 $old_umask = umask(0);
284 $result = file_put_contents($users_file, $usersToFile) !== false;
290 * Remove single user from HTTP Basic users file.
291 * Note, this method saves config file if username was existed
295 * @param string $username user name to remove
296 * @return boolean true if users file saved successfully, otherwise false
298 public function removeUser($username) {
300 $all_users = $this->getAllUsers();
301 if (array_key_exists($username, $all_users)) {
302 unset($all_users[$username]);
303 $result = $this->saveUserConfig($all_users);
309 * Check if users configuration file exists.
312 * @return boolean true if file exists, otherwise false
314 public function isUsersConfig() {
315 return file_exists(Prado::getPathOfNamespace(self::USERS_FILE, '.users'));
319 * Clear all content of users file.
322 * @return boolean true if file cleared successfully, otherwise false
324 public function clearUsersConfig() {
325 $users_file = Prado::getPathOfNamespace(self::USERS_FILE, '.users');
326 $result = file_put_contents($users_file, '') !== false;
331 * Log in as specific user.
333 * Note, usually after this method call there required is using exit() just
334 * after method execution. Otherwise the HTTP redirection may be canceled on some
338 * @param string $http_protocol 'http' or 'https' value
339 * @param string $host hostname without port, for example: my.own.host or localhost
340 * @param integer $port port number on which listens web server
341 * @param string $user user name to log in
342 * @param string $string plain text user's password
345 public function switchToUser($http_protocol, $host, $port, $user, $password) {
346 $url_prefix = $this->Application->getModule('friendly-url')->getUrlPrefix();
347 $location = sprintf("%s://%s:%s@%s:%d%s", $http_protocol, $user, $password, $host, $port, $url_prefix);
348 $refresh_url = sprintf("%s://%s:%d%s", $http_protocol, $host, $port, $url_prefix);
351 * Refresh page is required due to lack of auth data in $_SERVER superglobal array
352 * after re-login by URI.
354 $_SESSION['refresh_page'] = $refresh_url;
357 header("Location: $location");
361 * Get (pseudo)random string.
363 * Useful for log out user from HTTP Basic auth by providing random password.
366 * @return string random 62 characters string from range [a-zA-Z0-9]
368 public function getRandomString() {
369 $characters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
370 $rand_string = str_shuffle($characters);