database.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. <?php
  2. /*
  3. FusionPBX
  4. Version: MPL 1.1
  5. The contents of this file are subject to the Mozilla Public License Version
  6. 1.1 (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.mozilla.org/MPL/
  9. Software distributed under the License is distributed on an "AS IS" basis,
  10. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. for the specific language governing rights and limitations under the
  12. License.
  13. The Original Code is FusionPBX
  14. The Initial Developer of the Original Code is
  15. Mark J Crane <[email protected]>
  16. Portions created by the Initial Developer are Copyright (C) 2008-2023
  17. the Initial Developer. All Rights Reserved.
  18. Contributor(s):
  19. Mark J Crane <[email protected]>
  20. */
  21. /**
  22. * plugin_database
  23. *
  24. * @method plugin_database validates the authentication using information from the database
  25. */
  26. class plugin_database {
  27. /**
  28. * Define variables and their scope
  29. */
  30. public $domain_name;
  31. public $domain_uuid;
  32. public $user_uuid;
  33. public $contact_uuid;
  34. public $username;
  35. public $password;
  36. public $key;
  37. public $debug;
  38. public $user_email;
  39. /**
  40. * database checks the local database to authenticate the user or key
  41. * @return array [authorized] => true or false
  42. */
  43. function database() {
  44. //pre-process some settings
  45. $settings['theme']['favicon'] = !empty($_SESSION['theme']['favicon']['text']) ? $_SESSION['theme']['favicon']['text'] : PROJECT_PATH.'/themes/default/favicon.ico';
  46. $settings['login']['destination'] = !empty($_SESSION['login']['destination']['text']) ? $_SESSION['login']['destination']['text'] : '';
  47. $settings['users']['unique'] = !empty($_SESSION['users']['unique']['text']) ? $_SESSION['users']['unique']['text'] : '';
  48. $settings['theme']['logo'] = !empty($_SESSION['theme']['logo']['text']) ? $_SESSION['theme']['logo']['text'] : PROJECT_PATH.'/themes/default/images/logo_login.png';
  49. $settings['theme']['login_logo_width'] = !empty($_SESSION['theme']['login_logo_width']['text']) ? $_SESSION['theme']['login_logo_width']['text'] : 'auto; max-width: 300px';
  50. $settings['theme']['login_logo_height'] = !empty($_SESSION['theme']['login_logo_height']['text']) ? $_SESSION['theme']['login_logo_height']['text'] : 'auto; max-height: 300px';
  51. $settings['theme']['message_delay'] = isset($_SESSION['theme']['message_delay']) ? 1000 * (float) $_SESSION['theme']['message_delay'] : 3000;
  52. $settings['theme']['background_video'] = isset($_SESSION['theme']['background_video'][0]) ? $_SESSION['theme']['background_video'][0] : null;
  53. //already authorized
  54. if (isset($_SESSION['authentication']['plugin']['database']) && $_SESSION['authentication']['plugin']['database']["authorized"]) {
  55. return;
  56. }
  57. else {
  58. if (isset($_SESSION['authentication']['plugin']['database']) && !$_SESSION['authentication']['plugin']['database']["authorized"]) {
  59. //authorized false
  60. }
  61. }
  62. //show the authentication code view
  63. if (empty($_REQUEST["username"]) && empty($_REQUEST["key"])) {
  64. //get the domain
  65. $domain_array = explode(":", $_SERVER["HTTP_HOST"]);
  66. $domain_name = $domain_array[0];
  67. //temp directory
  68. $_SESSION['server']['temp']['dir'] = '/tmp';
  69. //create token
  70. //$object = new token;
  71. //$token = $object->create('login');
  72. //add multi-lingual support
  73. $language = new text;
  74. $text = $language->get(null, '/core/authentication');
  75. //initialize a template object
  76. $view = new template();
  77. $view->engine = 'smarty';
  78. $view->template_dir = $_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/core/authentication/resources/views/';
  79. $view->cache_dir = $_SESSION['server']['temp']['dir'];
  80. $view->init();
  81. //add translations
  82. $view->assign("login_title", $text['button-login']);
  83. $view->assign("label_username", $text['label-username']);
  84. $view->assign("label_password", $text['label-password']);
  85. $view->assign("button_login", $text['button-login']);
  86. //assign default values to the template
  87. $view->assign("project_path", PROJECT_PATH);
  88. $view->assign("login_destination_url", $settings['login']['destination']);
  89. $view->assign("favicon", $settings['theme']['favicon']);
  90. $view->assign("login_logo_width", $settings['theme']['login_logo_width']);
  91. $view->assign("login_logo_height", $settings['theme']['login_logo_height']);
  92. $view->assign("login_logo_source", $settings['theme']['logo']);
  93. $view->assign("message_delay", $settings['theme']['message_delay']);
  94. $view->assign("background_video", $settings['theme']['background_video']);
  95. //if (!empty($_SESSION['authentication']['plugin']['database']['authorized']) && $_SESSION['authentication']['plugin']['database']['authorized'] == 1 && !empty($_SESSION['username'])) {
  96. if (!empty($_SESSION['username'])) {
  97. $view->assign("login_password_description", $text['label-password_description']);
  98. $view->assign("username", $_SESSION['username']);
  99. $view->assign("button_cancel", $text['button-cancel']);
  100. }
  101. //messages
  102. $view->assign('messages', message::html(true, ' '));
  103. //add the token name and hash to the view
  104. //$view->assign("token_name", $token['name']);
  105. //$view->assign("token_hash", $token['hash']);
  106. //show the views
  107. $content = $view->render('login.htm');
  108. echo $content;
  109. exit;
  110. }
  111. //validate the token
  112. //$token = new token;
  113. //if (!$token->validate($_SERVER['PHP_SELF'])) {
  114. // message::add($text['message-invalid_token'],'negative');
  115. // header('Location: domains.php');
  116. // exit;
  117. //}
  118. //add the authentication details
  119. if (isset($_REQUEST["username"])) {
  120. $this->username = $_REQUEST["username"];
  121. $_SESSION['username'] = $this->username;
  122. }
  123. if (isset($_REQUEST["password"])) {
  124. $this->password = $_REQUEST["password"];
  125. }
  126. if (isset($_SESSION['username'])) {
  127. $this->username = $_SESSION['username'];
  128. }
  129. if (isset($_REQUEST["key"])) {
  130. $this->key = $_REQUEST["key"];
  131. }
  132. //get the domain name
  133. $auth = new authentication;
  134. $auth->get_domain();
  135. $this->domain_uuid = $_SESSION['domain_uuid'] ?? null;
  136. $this->domain_name = $_SESSION['domain_name'] ?? null;
  137. $this->username = $_SESSION['username'] ?? null;
  138. //debug information
  139. //echo "domain_uuid: ".$this->domain_uuid."<br />\n";
  140. //echo "domain_name: ".$this->domain_name."<br />\n";
  141. //echo "username: ".$this->username."<br />\n";
  142. //set the default status
  143. $user_authorized = false;
  144. //check the username and password if they don't match then redirect to the login
  145. $sql = "select u.user_uuid, u.contact_uuid, u.username, u.password, ";
  146. $sql .= "u.user_email, u.salt, u.api_key, u.domain_uuid, d.domain_name ";
  147. $sql .= "from v_users as u, v_domains as d ";
  148. $sql .= "where u.domain_uuid = d.domain_uuid ";
  149. $sql .= "and (user_type = 'default' or user_type is null) ";
  150. if (isset($this->key) && strlen($this->key) > 30) {
  151. $sql .= "and u.api_key = :api_key ";
  152. $parameters['api_key'] = $this->key;
  153. }
  154. else {
  155. $sql .= "and (\n";
  156. $sql .= " lower(u.username) = lower(:username)\n";
  157. $sql .= " or lower(u.user_email) = lower(:username)\n";
  158. $sql .= ")\n";
  159. $parameters['username'] = $this->username;
  160. }
  161. if ($settings['users']['unique'] === "global") {
  162. //unique username - global (example: email address)
  163. }
  164. else {
  165. //unique username - per domain
  166. $sql .= "and u.domain_uuid = :domain_uuid ";
  167. $parameters['domain_uuid'] = $this->domain_uuid;
  168. }
  169. $sql .= "and (user_enabled = 'true' or user_enabled is null) ";
  170. $database = new database;
  171. $row = $database->select($sql, $parameters, 'row');
  172. if (!empty($row) && is_array($row) && @sizeof($row) != 0) {
  173. //validate the password
  174. $valid_password = false;
  175. if (isset($this->key) && strlen($this->key) > 30 && $this->key === $row["api_key"]) {
  176. $valid_password = true;
  177. }
  178. else if (substr($row["password"], 0, 1) === '$') {
  179. if (isset($this->password) && !empty($this->password)) {
  180. if (password_verify($this->password, $row["password"])) {
  181. $valid_password = true;
  182. }
  183. }
  184. }
  185. else {
  186. //deprecated - compare the password provided by the user with the one in the database
  187. if (md5($row["salt"].$this->password) === $row["password"]) {
  188. $row["password"] = crypt($this->password, '$1$'.$password_salt.'$');
  189. $valid_password = true;
  190. }
  191. }
  192. //set the domain and user settings
  193. if ($valid_password) {
  194. //set the domain_uuid
  195. $this->domain_uuid = $row["domain_uuid"];
  196. $this->domain_name = $row["domain_name"];
  197. //set the domain session variables
  198. $_SESSION["domain_uuid"] = $this->domain_uuid;
  199. $_SESSION["domain_name"] = $this->domain_name;
  200. //set the domain setting
  201. if ($settings['users']['unique'] === "global" && $row["domain_uuid"] !== $this->domain_uuid) {
  202. $domain = new domains();
  203. $domain->set();
  204. }
  205. //set the variables
  206. $this->user_uuid = $row['user_uuid'];
  207. $this->username = $row['username'];
  208. $this->user_email = $row['user_email'];
  209. $this->contact_uuid = $row['contact_uuid'];
  210. //debug info
  211. //echo "user_uuid ".$this->user_uuid."<br />\n";
  212. //echo "username ".$this->username."<br />\n";
  213. //echo "contact_uuid ".$this->contact_uuid."<br />\n";
  214. //set a few session variables
  215. $_SESSION["user_uuid"] = $row['user_uuid'];
  216. $_SESSION["username"] = $row['username'];
  217. $_SESSION["user_email"] = $row['user_email'];
  218. $_SESSION["contact_uuid"] = $row["contact_uuid"];
  219. }
  220. //check to to see if the the password hash needs to be updated
  221. if ($valid_password) {
  222. //set the password hash cost
  223. $options = array('cost' => 10);
  224. //check if a newer hashing algorithm is available or the cost has changed
  225. if (password_needs_rehash($row["password"], PASSWORD_DEFAULT, $options)) {
  226. //build user insert array
  227. $array['users'][0]['user_uuid'] = $this->user_uuid;
  228. $array['users'][0]['domain_uuid'] = $this->domain_uuid;
  229. $array['users'][0]['user_email'] = $this->user_email;
  230. $array['users'][0]['password'] = password_hash($this->password, PASSWORD_DEFAULT, $options);
  231. $array['users'][0]['salt'] = null;
  232. //build user group insert array
  233. $array['user_groups'][0]['user_group_uuid'] = uuid();
  234. $array['user_groups'][0]['domain_uuid'] = $this->domain_uuid;
  235. $array['user_groups'][0]['group_name'] = 'user';
  236. $array['user_groups'][0]['user_uuid'] = $this->user_uuid;
  237. //grant temporary permissions
  238. $p = new permissions;
  239. $p->add('user_edit', 'temp');
  240. //execute insert
  241. $database = new database;
  242. $database->app_name = 'authentication';
  243. $database->app_uuid = 'a8a12918-69a4-4ece-a1ae-3932be0e41f1';
  244. $database->save($array);
  245. unset($array);
  246. //revoke temporary permissions
  247. $p->delete('user_edit', 'temp');
  248. }
  249. }
  250. else {
  251. //clear authentication session
  252. if (empty($_SESSION['authentication']['methods']) || !is_array($_SESSION['authentication']['methods']) || sizeof($_SESSION['authentication']['methods']) == 0) {
  253. unset($_SESSION['authentication']);
  254. }
  255. // clear username
  256. if (!empty($_REQUEST["password"])) {
  257. unset($_SESSION['username'], $_REQUEST['username'], $_POST['username']);
  258. unset($_SESSION['authentication']);
  259. }
  260. }
  261. //result array
  262. if ($valid_password) {
  263. $result["plugin"] = "database";
  264. $result["domain_name"] = $this->domain_name;
  265. $result["username"] = $this->username;
  266. $result["user_uuid"] = $this->user_uuid;
  267. $result["domain_uuid"] = $_SESSION['domain_uuid'];
  268. $result["contact_uuid"] = $this->contact_uuid;
  269. $result["user_email"] = $this->user_email;
  270. $result["sql"] = $sql;
  271. $result["authorized"] = $valid_password;
  272. }
  273. //return the results
  274. return $result ?? false;
  275. }
  276. else {
  277. unset($_SESSION['username'], $_REQUEST['username'], $_POST['username']);
  278. unset($_SESSION['authentication']);
  279. }
  280. return;
  281. }
  282. }
  283. ?>