]> git.sur5r.net Git - bacula/bacula/blob - gui/baculum/protected/Class/BaculumAPI.php
baculum: Assign Baculum copyright to Kern Sibbald
[bacula/bacula] / gui / baculum / protected / Class / BaculumAPI.php
1 <?php
2 /*
3  * Bacula(R) - The Network Backup Solution
4  * Baculum   - Bacula web interface
5  *
6  * Copyright (C) 2013-2016 Kern Sibbald
7  *
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.
11  *
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.
16  *
17  * This notice must be preserved when any source code is
18  * conveyed and/or propagated.
19  *
20  * Bacula(R) is a registered trademark of Kern Sibbald.
21  */
22  
23 Prado::using('System.Exceptions.TException');
24 Prado::using('Application.Class.Errors');
25
26 /**
27  * Abstract module from which inherits each of API module.
28  * The module contains methods that are common for all API pages.
29  *
30  * @author Marcin Haba <marcin.haba@bacula.pl>
31  */
32 abstract class BaculumAPI extends TPage {
33
34         /**
35          * Storing output from API commands in numeric array.
36          */
37         protected $output;
38
39         /**
40          * Storing error from API commands as integer value.
41          */
42         protected $error;
43
44         /**
45          * Storing currently used Director name for bconsole commands.
46          */
47         protected $director;
48
49         /**
50          * Web interface User name that sent request to API.
51          * Null value means administrator, any other value means normal user
52          * (non-admin user).
53          */
54         protected $user;
55
56         /**
57          * Action methods.
58          */
59
60         // get elements
61         const GET_METHOD = 'GET';
62
63         // create new elemenet
64         const POST_METHOD = 'POST';
65
66         // update elements
67         const PUT_METHOD = 'PUT';
68
69         // delete element
70         const DELETE_METHOD = 'DELETE';
71
72         /**
73          * Get request, login user and do request action.
74          *
75          * @access public
76          * @param mixed $params onInit action params
77          * @return none
78          */
79         public function onInit($params) {
80                 parent::onInit($params);
81                 /*
82                  * Workaround to bug in PHP 5.6 by FastCGI that caused general protection error.
83                  * TODO: Check on newer PHP if it is already fixed.
84                  */
85                 $db = new ActiveRecord();
86                 $db->getDbConnection();
87
88                 // set Director to bconsole execution
89                 $this->director = isset($this->Request['director']) ? $this->Request['director'] : null;
90
91                 /**
92                  * User and password are obligatory for each request. Otherwise authorization
93                  * error takes place.
94                  * Password is provided in hashed form.
95                  */
96                 $user = isset($_SERVER['HTTP_X_BACULUM_USER']) ? $_SERVER['HTTP_X_BACULUM_USER']: null;
97                 $pwd_hash = isset($_SERVER['HTTP_X_BACULUM_PWD']) ? $_SERVER['HTTP_X_BACULUM_PWD']: null;
98                 if (!is_null($user) && !is_null($pwd_hash)) {
99                         // try to log in user
100                         $logged = $this->getModule('users')->loginUser($user, $pwd_hash);
101                         if ($logged === true) {
102                                 /*
103                                  * User and password are valid.
104                                  * Log in action finished successfuly.
105                                  * Now check if logged in user is admin or normal user.
106                                  * Admin value is null. Normal user value is string with the user name.
107                                  */
108                                 $this->user = ($this->User->getIsAdmin() === false) ? $user : null;
109                         } else {
110                                 // Invalid credentials. Authorization error.
111                                 $this->output = AuthorizationError::MSG_ERROR_AUTHORIZATION_TO_WEBGUI_PROBLEM;
112                                 $this->error = AuthorizationError::ERROR_AUTHORIZATION_TO_WEBGUI_PROBLEM;
113                                 return;
114                         }
115                 } else {
116                         // Not provided user or password. Authorization error.
117                         $this->output = AuthorizationError::MSG_ERROR_AUTHORIZATION_TO_WEBGUI_PROBLEM;
118                         $this->error = AuthorizationError::ERROR_AUTHORIZATION_TO_WEBGUI_PROBLEM;
119                         return;
120                 }
121
122                 switch($_SERVER['REQUEST_METHOD']) {
123                         case self::PUT_METHOD: {
124                                 try {
125                                         $this->put();
126                                 } catch(TDbException $e) {
127                                         $this->getModule('logging')->log(
128                                                 __FUNCTION__,
129                                                 $e,
130                                                 Logging::CATEGORY_APPLICATION,
131                                                 __FILE__,
132                                                 __LINE__
133                                         );
134                                         $this->output = DatabaseError::MSG_ERROR_DB_CONNECTION_PROBLEM;
135                                         $this->error = DatabaseError::ERROR_DB_CONNECTION_PROBLEM;
136                                 }
137                                 break;
138                         }
139                         case self::GET_METHOD: {
140                                 try {
141                                         $this->get();
142                                 } catch(TDbException $e) {
143                                         $this->getModule('logging')->log(
144                                                 __FUNCTION__,
145                                                 $e,
146                                                 Logging::CATEGORY_APPLICATION,
147                                                 __FILE__,
148                                                 __LINE__
149                                         );
150                                         $this->output = DatabaseError::MSG_ERROR_DB_CONNECTION_PROBLEM;
151                                         $this->error = DatabaseError::ERROR_DB_CONNECTION_PROBLEM;
152                                 }
153                                 break;
154                         }
155                         case self::POST_METHOD: {
156                                 try {
157                                         $this->post();
158                                 } catch(TDbException $e) {
159                                         $this->getModule('logging')->log(
160                                                 __FUNCTION__,
161                                                 $e,
162                                                 Logging::CATEGORY_APPLICATION,
163                                                 __FILE__,
164                                                 __LINE__
165                                         );
166                                         $this->output = DatabaseError::MSG_ERROR_DB_CONNECTION_PROBLEM;
167                                         $this->error = DatabaseError::ERROR_DB_CONNECTION_PROBLEM;
168                                 }
169                                 break;
170                         }
171                         case self::DELETE_METHOD: {
172                                 try {
173                                         $this->delete();
174                                 } catch(TDbException $e) {
175                                         $this->getModule('logging')->log(
176                                                 __FUNCTION__,
177                                                 $e,
178                                                 Logging::CATEGORY_APPLICATION,
179                                                 __FILE__,
180                                                 __LINE__
181                                         );
182                                         $this->output = DatabaseError::MSG_ERROR_DB_CONNECTION_PROBLEM;
183                                         $this->error = DatabaseError::ERROR_DB_CONNECTION_PROBLEM;
184                                 }
185                                 break;
186                         }
187                 }
188         }
189
190         /**
191          * Get request result data and pack it in JSON format.
192          * JSON values are: {
193          * "output": (list) output values
194          * "error" : (integer) result exit code (0 - OK, non-zero - error)
195          *
196          * @access private
197          * @return string JSON value with output and error values
198          */
199         private function getOutput() {
200                 $output = array('output' => $this->output, 'error' => $this->error);
201                 $json = json_encode($output);
202                 return $json;
203         }
204
205         /**
206          * Return action result which was realized in onInit() method.
207          * On standard output is printed JSON value with request results.
208          *
209          * @access public
210          * @param mixed $params onInit action params
211          * @return none
212          */
213         public function onLoad($params) {
214                 parent::onLoad($params);
215                 echo $this->getOutput();
216         }
217
218         /**
219          * Each of API module should have get() method defined.
220          * Designed to getting data from API.
221          *
222          * @access protected
223          * @return none
224          */
225         abstract protected function get();
226
227         /**
228          * Changing/updating values via API.
229          *
230          * @access private
231          * @return none
232          */
233         private function put() {
234                 $id = isset($this->Request['id']) ? $this->Request['id'] : null;
235
236                 /**
237                  * Check if it is possible to read PUT method data.
238                  * Note that some clients sends data in PUT request as PHP input stream which
239                  * is not possible to read by $_REQUEST data. From this reason, when is
240                  * not possible to ready by superglobal $_REQUEST variable, then is try to
241                  * read PUT data by PHP input stream.
242                  */
243                 if (is_array($this->Request['update']) && count($this->Request['update']) > 0) {
244                         // $_REQUEST available to read
245                         $params = (object)$this->Request['update'];
246                         $this->set($id, $params);
247                 } else {
248                         // no possibility to read data from $_REQUEST. Try to load from input stream.
249                         $inputstr = file_get_contents("php://input");
250
251                         /**
252                          * Read using chunks for case large updates (over 1000 values).
253                          * Otherwise max_input_vars limitation in php.ini can be reached (usually
254                          * set to 1000 variables)
255                          * @see http://php.net/manual/en/info.configuration.php#ini.max-input-vars
256                          */
257                         $chunks = explode('&', $inputstr);
258
259                         $response_data = array();
260                         for($i = 0; $i<count($chunks); $i++) {
261                                 // if chunks would not be used, then here occurs reach max_input_vars limit
262                                 parse_str($chunks[$i], $response_el);
263                                 if (is_array($response_el) && array_key_exists('update', $response_el) && is_array($response_el['update'])) {
264                                         $key = key($response_el['update']);
265                                         $response_data['update'][$key] = $response_el['update'][$key];
266                                 }
267                         }
268                         if (is_array($response_data) && array_key_exists('update', $response_data)) {
269                                 $params = (object)$response_data['update'];
270                                 $this->set($id, $params);
271                         } else {
272                                 /**
273                                  * This case should never occur because it means that there is
274                                  * given nothing to update.
275                                  */
276                                 $this->set($id, array());
277                         }
278                 }
279         }
280
281         /**
282          * Creating new elements.
283          *
284          * @access private
285          * @return none
286          */
287         private function post() {
288                 if (is_array($this->Request['create']) && count($this->Request['create']) > 0) {
289                         $params = (object)$this->Request['create'];
290                         $this->create($params);
291                 }
292         }
293
294         /**
295          * Deleting element by element ID.
296          *
297          * @access private
298          * @return none
299          */
300         private function delete() {
301                 if (isset($this->Request['id'])) {
302                         $id = intval($this->Request['id']);
303                         $this->remove($id);
304                 }
305         }
306
307         /**
308          * Shortcut method for getting application modules instances by
309          * module name.
310          *
311          * @access public
312          * @param string $name application module name
313          * @return object module class instance
314          */
315         public function getModule($name) {
316                 return $this->Application->getModule($name);
317         }
318 }
319 ?>