*
* Bacula(R) is a registered trademark of Kern Sibbald.
*/
+
+/*
+ * Constant is used to localize always valid document root directory
+ * Using for placing Baculum files in document root subdirectory
+ */
define('APPLICATION_DIRECTORY', __DIR__);
require_once('./protected/Init.php');
require_once('./framework/prado.php');
+// Start application
$application=new TApplication;
$application->run();
?>
Prado::using('Application.Class.Errors');
+/**
+ * Internal API client module.
+ *
+ * @author Marcin Haba
+ */
class API extends TModule {
+ /**
+ * API version (used in HTTP header)
+ */
const API_VERSION = '0.1';
+ /**
+ * Store configuration data from settings file
+ * @access protected
+ */
protected $appCfg;
+ /**
+ * These errors are allowed in API response and they do not cause
+ * disturb application working (no direction to error page)
+ * @access private
+ */
private $allowedErrors = array(
GenericError::ERROR_NO_ERRORS,
BconsoleError::ERROR_INVALID_COMMAND,
PoolError::ERROR_NO_VOLUMES_IN_POOL_TO_UPDATE
);
- private function getConnection() {
+ /**
+ * Get connection request handler.
+ * For data requests is used cURL interface.
+ * @access public
+ * @return resource connection handler on success, false on errors
+ */
+ public function getConnection() {
$ch = curl_init();
+ $userpwd = sprintf('%s:%s', $this->appCfg['baculum']['login'], $this->appCfg['baculum']['password']);
+ curl_setopt($ch, CURLOPT_USERPWD, $userpwd);
+ curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_COOKIE, 'PHPSESSID=' . md5(session_id()));
- curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
- curl_setopt($ch, CURLOPT_USERPWD, $this->appCfg['baculum']['login'] . ':' . $this->appCfg['baculum']['password']);
return $ch;
}
+ /**
+ * Get API specific headers used in HTTP requests.
+ * @access private
+ * @return API specific headers
+ */
private function getAPIHeaders() {
$headers = array(
'X-Baculum-API: ' . self::API_VERSION,
return $headers;
}
+ /**
+ * Initializes API module (framework module constructor)
+ * @access public
+ * @param TXmlElement $config API module configuration
+ */
public function init($config) {
$this->initSessionCache();
$this->appCfg = $this->Application->getModule('configuration')->getApplicationConfig();
}
+ /**
+ * Get URL to use by internal API client's request.
+ * @access private
+ * @return string URL to internal API server
+ */
private function getURL() {
$protocol = !empty($_SERVER['HTTPS']) ? 'https' : 'http';
$host = $_SERVER['SERVER_NAME'];
$port = $_SERVER['SERVER_PORT'];
+
+ // support for document root subdirectory
$urlPrefix = $this->Application->getModule('friendly-url')->getUrlPrefix();
+
$url = sprintf('%s://%s:%d%s/', $protocol, $host, $port, $urlPrefix);
return $url;
}
- private function setParamsToUrl(&$url) {
- $url .= (preg_match('/\?/', $url) === 1 ? '&' : '?' ) . 'director=' . ((array_key_exists('director', $_SESSION)) ? $_SESSION['director'] : '');
- $this->Application->getModule('logging')->log(__FUNCTION__, PHP_EOL . PHP_EOL . 'EXECUTE URL ==> ' . $url . ' <==' . PHP_EOL . PHP_EOL, Logging::CATEGORY_APPLICATION, __FILE__, __LINE__);
+ /**
+ * Set URL parameters and prepare URL to request send.
+ * @access private
+ * @param string &$url reference to URL string variable
+ */
+ private function setUrlParams(&$url) {
+ $url .= (preg_match('/\?/', $url) === 1 ? '&' : '?');
+ $url .= 'director=';
+ if (array_key_exists('director', $_SESSION)) {
+ $url .= $_SESSION['director'];
+ }
+
+ $this->Application->getModule('logging')->log(
+ __FUNCTION__,
+ PHP_EOL . PHP_EOL . 'EXECUTE URL ==> ' . $url . ' <==' . PHP_EOL . PHP_EOL,
+ Logging::CATEGORY_APPLICATION,
+ __FILE__,
+ __LINE__
+ );
}
/**
- * API REQUESTS METHODS (get, set, create, delete)
+ * Internal API GET request.
+ * @access public
+ * @param array $params GET params to send in request
+ * @param bool $use_cache if true then try to use session cache, if false then always use fresh data
+ * @return object stdClass with request result as two properties: 'output' and 'error'
*/
-
public function get(array $params, $use_cache = false) {
$cached = null;
$ret = null;
$ret = $cached;
} else {
$url = $this->getURL() . implode('/', $params);
- $this->setParamsToUrl($url);
+ $this->setUrlParams($url);
$ch = $this->getConnection();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $this->getAPIHeaders());
return $ret;
}
+ /**
+ * Internal API SET request.
+ * @access public
+ * @param array $params GET params to send in request
+ * @param array $options POST params to send in request
+ * @return object stdClass with request result as two properties: 'output' and 'error'
+ */
public function set(array $params, array $options) {
$url = $this->getURL() . implode('/', $params);
- $this->setParamsToUrl($url);
+ $this->setUrlParams($url);
$data = http_build_query(array('update' => $options));
$ch = $this->getConnection();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
- curl_setopt($ch, CURLOPT_HTTPHEADER, array_merge($this->getAPIHeaders(), array('X-HTTP-Method-Override: PUT', 'Content-Length: ' . strlen($data), 'Expect:')));
+ curl_setopt($ch, CURLOPT_HTTPHEADER, array_merge(
+ $this->getAPIHeaders(),
+ array('X-HTTP-Method-Override: PUT', 'Content-Length: ' . strlen($data), 'Expect:')
+ ));
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$result = curl_exec($ch);
return $this->preParseOutput($result);
}
+ /**
+ * Internal API CREATE request.
+ * @access public
+ * @param array $params GET params to send in request
+ * @param array $options POST params to send in request
+ * @return object stdClass with request result as two properties: 'output' and 'error'
+ */
public function create(array $params, array $options) {
$url = $this->getURL() . implode('/', $params);
- $this->setParamsToUrl($url);
+ $this->setUrlParams($url);
$data = http_build_query(array('create' => $options));
$ch = $this->getConnection();
curl_setopt($ch, CURLOPT_URL, $url);
return $this->preParseOutput($result);
}
+ /**
+ * Internal API REMOVE request.
+ * @access public
+ * @param array $params GET params to send in request
+ * @return object stdClass with request result as two properties: 'output' and 'error'
+ */
public function remove(array $params) {
$url = $this->getURL() . implode('/', $params);
- $this->setParamsToUrl($url);
+ $this->setUrlParams($url);
$ch = $this->getConnection();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
return $this->preParseOutput($result);
}
+ /**
+ * Initially parse and prepare every Internal API response.
+ * If a error occurs then redirect to appropriate error page.
+ * @access private
+ * @param string $result response output as JSON string (not object yet)
+ * @return object stdClass parsed response with two top level properties 'output' and 'error'
+ */
private function preParseOutput($result) {
- $this->Application->getModule('logging')->log(__FUNCTION__, $result, Logging::CATEGORY_APPLICATION, __FILE__, __LINE__);
+ // first write log with that what comes
+ $this->Application->getModule('logging')->log(
+ __FUNCTION__,
+ $result,
+ Logging::CATEGORY_APPLICATION,
+ __FILE__,
+ __LINE__
+ );
+
+ // decode JSON to object
$resource = json_decode($result);
+
$error = null;
+
if(is_object($resource) && property_exists($resource, 'error')) {
if(!in_array($resource->error, $this->allowedErrors)) {
$error = $resource->error;
$error = AuthorizationError::ERROR_AUTHORIZATION_TO_WEBGUI_PROBLEM;
}
- $this->Application->getModule('logging')->log(__FUNCTION__, $resource, Logging::CATEGORY_APPLICATION, __FILE__, __LINE__);
+ $this->Application->getModule('logging')->log(
+ __FUNCTION__,
+ $resource,
+ Logging::CATEGORY_APPLICATION,
+ __FILE__,
+ __LINE__
+ );
+
+ // if other than allowed errors exist then show error page (redirect)
if(!is_null($error)) {
// Note! Redirection to error page takes place here.
- $this->Response->redirect($this->Service->constructUrl('BaculumError',array('error' => $error), false));
+ $this->Response->redirect(
+ $this->Service->constructUrl(
+ 'BaculumError',
+ array('error' => $error),
+ false
+ )
+ );
}
return $resource;
Prado::using('Application.Class.Miscellaneous');
+/**
+ * Manage application configuration.
+ * Module is responsible for get/set application config data like:
+ * read/write application config and usersfiles, get application language
+ * and others.
+ *
+ * @author Marcin Haba
+ */
class ConfigurationManager extends TModule
{
/**
- * Location o application configuration file.
+ * Application config file path
*/
const CONFIG_FILE = 'Application.Data.settings';
const USERS_FILE = 'Application.Data.baculum';
/**
- * PostgreSQL default params.
+ * PostgreSQL default params
*/
const PGSQL = 'pgsql';
const PGSQL_NAME = 'PostgreSQL';
const PGSQL_PORT = 5432;
/**
- * MySQL default params.
+ * MySQL default params
*/
const MYSQL = 'mysql';
const MYSQL_NAME = 'MySQL';
const MYSQL_PORT = 3306;
/**
- * SQLite default params.
+ * SQLite default params
*/
const SQLITE = 'sqlite';
const SQLITE_NAME = 'SQLite';
const SQLITE_PORT = null;
/**
- * Default language for application.
+ * Default application language
*/
const DEFAULT_LANGUAGE = 'en';
+ /**
+ * Get database name by database type (short name).
+ * @access public
+ * @param string $type database type ('pgsql', 'mysql' ...)
+ * @return mixed database name or null if database name not found
+ */
public function getDbNameByType($type) {
+ $type = (string) $type;
switch($type) {
case self::PGSQL: $dbName = self::PGSQL_NAME; break;
case self::MYSQL: $dbName = self::MYSQL_NAME; break;
return $dbName;
}
- public function getPostgreSQLType() {
- return self::PGSQL;
- }
-
- public function getMySQLType() {
- return self::MYSQL;
- }
-
- public function getSQLiteType() {
- return self::SQLITE;
- }
-
+ /**
+ * Check if given database type is PostgreSQL type.
+ * @access public
+ * @param string $type database type ('pgsql', 'mysql' ...)
+ * @return boolean true if database type is PostgreSQL, otherwise false
+ */
public function isPostgreSQLType($type) {
return ($type === self::PGSQL);
}
+ /**
+ * Check if given database type is MySQL type.
+ * @access public
+ * @param string $type database type ('pgsql', 'mysql' ...)
+ * @return boolean true if database type is MySQL, otherwise false
+ */
public function isMySQLType($type) {
return ($type === self::MYSQL);
}
+ /**
+ * Check if given database type is SQLite type.
+ * @access public
+ * @param string $type database type ('sqlite', 'mysql' ...)
+ * @return boolean true if database type is SQLite, otherwise false
+ */
public function isSQLiteType($type) {
return ($type === self::SQLITE);
}
+ /**
+ * Get currently set application language short name.
+ * If no language set then default language is taken.
+ * @access public
+ * @return string lanuage short name
+ */
public function getLanguage() {
$language = self::DEFAULT_LANGUAGE;
if ($this->isApplicationConfig() === true) {
- $config = $this->getApplicationConfig();
+ $config = self::getApplicationConfig();
if (array_key_exists('lang', $config['baculum'])) {
$language = $config['baculum']['lang'];
}
return $language;
}
- public function setLanguage($language) {
-
- }
-
/**
- * Saving application configuration.
- *
+ * Save application configuration.
* @access public
* @param array $config structure of config file params
* @return boolean true if config save is successfully, false if config save is failure
}
/**
- * Getting application configuration.
- *
+ * Get application configuration.
* @access public
* @return array application configuration
*/
}
/**
- * Checking if application configuration file exists.
- *
+ * Check if application configuration file exists.
* @access public
* @return boolean true if file exists, otherwise false
*/
return file_exists(Prado::getPathOfNamespace(self::CONFIG_FILE, '.conf'));
}
+ /**
+ * Get encrypted password to use in HTTP Basic auth.
+ *
+ * @access public
+ * @param string $password plain text password
+ * @return string encrypted password
+ */
public function getCryptedPassword($password) {
$enc_pwd = crypt($password, base64_encode($password));
return $enc_pwd;
}
/**
- * Saving user to users configuration file.
- *
- * NOTE!
- * So far by webGUI is possible to set one user.
- * For more users and restricted consoles, there is need to modify
- * users and passwords file.
- *
- * TODO: Support for more than one user setting on webGUI.
+ * Save user to users configuration file.
*
* @access public
* @param string $user username
* @return boolean true if user saved successfully, otherwise false
*/
public function setUsersConfig($user, $password, $firstUsage = false, $oldUser = null) {
- $allUsers = $this->getAllUsers();
- $password = $this->getCryptedPassword($password);
-
if($firstUsage === true) {
$this->clearUsersConfig();
}
+ $allUsers = $this->getAllUsers();
+ $password = $this->getCryptedPassword($password);
+
$userExists = array_key_exists($user, $allUsers);
return $result;
}
+ /**
+ * Read all users from HTTP Basic users file.
+ * Returned value is associative array with usernames as keys
+ * and encrypted passwords as values.
+ *
+ * @access public
+ * @return array users/passwords list
+ */
public function getAllUsers() {
$allUsers = array();
if ($this->isUsersConfig() === true) {
return $allUsers;
}
+ /**
+ * Save HTTP Basic users file.
+ * Given parameter is associative array with usernames as keys
+ * and encrypted passwords as values.
+ *
+ * @access public
+ * @param array $allUsers users/passwords list
+ * @return boolean true if users file saved successfully, otherwise false
+ */
public function saveUserConfig($allUsers) {
$users = array();
foreach ($allUsers as $user => $pwd) {
return $result;
}
+ /**
+ * Remove single user from HTTP Basic users file.
+ * Note, this method saves config file if username was existed
+ * before removing.
+ *
+ * @access public
+ * @param string $username user name to remove
+ * @return boolean true if users file saved successfully, otherwise false
+ */
public function removeUser($username) {
$result = false;
$allUsers = $this->getAllUsers();
}
/**
- * Checking if users configuration file exists.
- *
+ * Check if users configuration file exists.
* @access public
* @return boolean true if file exists, otherwise false
*/
/**
* Clear all content of users file.
- *
- * @access private
+ * @access public
* @return boolean true if file cleared successfully, otherwise false
*/
- private function clearUsersConfig() {
+ public function clearUsersConfig() {
$usersFile = Prado::getPathOfNamespace(self::USERS_FILE, '.users');
$result = file_put_contents($usersFile, '') !== false;
return $result;
}
+ /**
+ * Log in as specific user.
+ *
+ * Note, usually after this method call there required is using exit() just
+ * after method execution. Otherwise the HTTP redirection may be canceled on some
+ * web servers.
+ *
+ * @access public
+ * @param string $http_protocol 'http' or 'https' value
+ * @param string $host hostname without port, for example: my.own.host or localhost
+ * @param integer $port port number on which listens web server
+ * @param string $user user name to log in
+ * @param string $string plain text user's password
+ * @return none
+ */
public function switchToUser($http_protocol, $host, $port, $user, $password) {
$urlPrefix = $this->Application->getModule('friendly-url')->getUrlPrefix();
$location = sprintf("%s://%s:%s@%s:%d%s", $http_protocol, $user, $password, $host, $port, $urlPrefix);
header("Location: $location");
}
+ /**
+ * Get (pseudo)random string.
+ *
+ * Useful for log out user from HTTP Basic auth by providing random password.
+ *
+ * @access public
+ * @return string random 62 characters string from range [a-zA-Z0-9]
+ */
public function getRandomString() {
$characters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
$rand_string = str_shuffle($characters);
date_default_timezone_set($timezone);
}
-// Support for web servers which do not provide direct info about HTTP Basic auth to PHP superglobal $_SERVER array.
-if(!isset($_SERVER['PHP_AUTH_USER']) && !isset($_SERVER['PHP_AUTH_PW']) && isset($_SERVER['HTTP_AUTHORIZATION'])) {
- list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
+/*
+ * Support for web servers (for example Lighttpd) which do not provide direct
+ * info about HTTP Basic auth to PHP superglobal $_SERVER array.
+ */
+if (!isset($_SERVER['PHP_AUTH_USER']) && !isset($_SERVER['PHP_AUTH_PW']) && isset($_SERVER['HTTP_AUTHORIZATION'])) {
+ /*
+ * Substring 'Basic ' from HTTP authorization header
+ * Example 'Basic YWRtaW46YWRtaW4=' becomes 'YWRtaW46YWRtaW4='
+ */
+ $encoded_credentials = substr($_SERVER['HTTP_AUTHORIZATION'], 6);
+ $decoded_credentials = base64_decode($encoded_credentials);
+
+ // initialize required auth superglobal $_SERVER array
+ list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', $decoded_credentials);
}
+// Check requirements and if are some needed then show requirements page
require_once('./protected/Pages/Requirements.php');
new Requirements(dirname(__DIR__));
<?xml version="1.0" encoding="utf-8"?>
<application id="baculum" mode="Normal">
<paths>
- <using namespace="Application.Class.*" />
<using namespace="System.Data.ActiveRecord.*" />
<using namespace="System.I18N.*" />
+ <using namespace="Application.Class.*" />
<using namespace="Application.Portlets.BButton" />
<using namespace="Application.Portlets.BActiveButton" />
</paths>