您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. <?php
  2. /**
  3. *
  4. * MySQL authentication module. Uses MySQL capability to store or
  5. * retrieve user credentials. Called from API when authentication
  6. * functions are requested.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * version 3 as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * @author Filippo Callegari (callegari.filippo@gmail.com)
  18. * @version $Id:1.0 MySQL.php 2015-03-10 23:49:11 Tio Igor
  19. * @package phpVirtualBox
  20. *
  21. */
  22. /**
  23. * struct of db:
  24. * CREATE TABLE users(
  25. * username VARCHAR(20) PRIMARY KEY,
  26. * password VARCHAR(40),
  27. * admin ENUM('0','1') DEFAULT '0'
  28. * )ENGINE=InnoDB;
  29. *
  30. * user:admin, pass:admin
  31. * INSERT INTO users(username,password,admin)
  32. * VALUES("admin","$1$65CMtT1M$GSDBTEZ6o5Web.4cDL6rz1",'1')
  33. *
  34. */
  35. class phpvbAuthMySQL implements phpvbAuth
  36. {
  37. var $capabilities = array(
  38. 'canChangePassword' => true,
  39. 'canModifyUsers' => true,
  40. 'canLogout' => true
  41. );
  42. /**
  43. *
  44. * Connect to MySQL DB.
  45. * return PDOconnection.
  46. */
  47. function newPDO()
  48. {
  49. $host="127.0.0.1";
  50. $port=3306;
  51. $user="MySQLuser";
  52. $pass="MySQLpassword";
  53. $db="vboxDB";
  54. try{
  55. return new PDO("mysql:host=$host;port=$port;dbname=$db;charset=utf8",$user,$pass);
  56. }catch (PDOException $e){throw new Exception("Can't connect to MySQL db!",vboxconnector::PHPVB_ERRNO_CONNECT);}
  57. }
  58. /**
  59. *
  60. * Select row from username
  61. * @param $username the user we search
  62. * return row
  63. */
  64. function PDO_selectUser($username)
  65. {
  66. try{
  67. $statement=$this->newPDO()->prepare("SELECT username, password, admin FROM users WHERE username=:username");
  68. $statement->bindValue(":username",$username, PDO::PARAM_STR);
  69. $statement->execute();
  70. }catch(PDOException $e){throw new Exception("Can't execute requested query!",vboxconnector::PHPVB_ERRNO_FATAL);}
  71. return $statement->fetch(PDO::FETCH_ASSOC);
  72. }
  73. /**
  74. *
  75. * Generate a random salt.
  76. * @param $lenght the lenght of the salt, default is 8.
  77. *
  78. * On Linux (in particular Ubuntu), the password is generate with this command:
  79. * "echo "${username}:${password}" | chpasswd -S -c $crypt_method | cut -d: -f2".
  80. * in this particoular implementation I use MD5.
  81. *
  82. * Max length is 20 char!
  83. */
  84. function generateRandomSalt($length = 8)
  85. {
  86. return substr(sha1(rand().time()), rand(0,20-$length), $length);
  87. }
  88. /**
  89. *
  90. * Revalidate login info and set authCheckHeartbeat session variable.
  91. * @param vboxconnector $vbox vboxconnector object instance, THIS VARIABLE WILL NOT USED.
  92. */
  93. function heartbeat($vbox)
  94. {
  95. global $_SESSION;
  96. $q=$this->PDO_selectUser(@$_SESSION['user']);
  97. $p=isset($q['password'])?$q['password']:0;
  98. if($p && $p!=@$_SESSION[uHash])
  99. {
  100. $_SESSION['valid']=false;
  101. session_destroy();
  102. }
  103. else
  104. {
  105. $_SESSION['admin']=intval(q['admin']);
  106. $_SESSION['authCheckHeartbeat']=time();
  107. }
  108. if(!isset($_SESSION['valid']) || !$_SESSION['valid'])
  109. throw new Exception(trans('Not logged in.','UIUsers'), vboxconnector::PHPVB_ERRNO_FATAL);
  110. }
  111. /**
  112. *
  113. * Log in function. Populates $_SESSION
  114. * @param string $username user name
  115. * @param string $password password
  116. */
  117. function login($username, $password)
  118. {
  119. global $_SESSION;
  120. $q=$this->PDO_selectUser($username);
  121. $p=isset($q['password'])?$q['password']:0;
  122. if($p && password_verify($password,$p))
  123. {
  124. $_SESSION['valid'] = true;
  125. $_SESSION['user'] = $username;
  126. $_SESSION['admin'] = intval($q['admin']);
  127. $_SESSION['authCheckHeartbeat'] = time();
  128. $_SESSION['uHash'] = $p;
  129. }
  130. }
  131. /**
  132. *
  133. * Log out user present in $_SESSION
  134. * @param array $response response passed byref by API and populated within function
  135. */
  136. function logout(&$response)
  137. {
  138. global $_SESSION;
  139. if(function_exists('session_destroy')) session_destroy();
  140. else unset($_SESSION['valid']);
  141. $response['data']['result'] = 1;
  142. }
  143. /**
  144. *
  145. * Change password function.
  146. * @param string $old old password
  147. * @param string $new new password
  148. * @return boolean true on success
  149. */
  150. function changePassword($old, $new)
  151. {
  152. global $_SESSION;
  153. $p=$this->PDO_selectUser($_SESSION['user']);
  154. $p=isset($p['password'])?$p['password']:0; //along the time is changed?
  155. if($p && password_verify($old, $p))
  156. {
  157. $np=crypt($new, '$1$'.$this->generateRandomSalt().'$'); //look the MD5 format!!
  158. //look here for more info: http://php.net/manual/en/faq.passwords.php
  159. try{
  160. $sth=$this->newPDO()->prepare("UPDATE users SET password=:password WHERE username=:username");
  161. $sth->bindValue(":password",$np,PDO::PARAM_STR);
  162. $sth->bindValue(":username",$_SESSION['user'],PDO::PARAM_STR);
  163. $sth->execute();
  164. }catch(PDOException $e){throw new Exception("Can't execute requested query!",vboxconnector::PHPVB_ERRNO_FATAL);}
  165. return true;
  166. }
  167. return false;
  168. }
  169. /**
  170. *
  171. * Return a list of users
  172. * @return array list of users
  173. */
  174. function listUsers()
  175. {
  176. $response = array();
  177. try{
  178. $sth=$this->newPDO()->prepare("SELECT * FROM users");
  179. $sth->execute();
  180. }catch(PDOException $e){throw new Exception("Can't display users list!",vboxconnector::PHPVB_ERRNO_FATAL);}
  181. while(($row=$sth->fetch(PDO::FETCH_ASSOC))!==FALSE)
  182. {
  183. $response[$row['username']]=array('username'=> $row['username'], 'admin'=> intval($row['admin']));
  184. }
  185. return $response;
  186. }
  187. /**
  188. *
  189. * Update user information such as password and admin status
  190. * @param array $vboxRequest request passed from API representing the ajax request. Contains user, password and administration level.
  191. * @param boolean $skipExistCheck Do not check that the user exists first. Essentially, if this is set and the user does not exist, it is added.
  192. */
  193. function updateUser($vboxRequest, $skipExistCheck)
  194. {
  195. global $_SESSION;
  196. if(!$_SESSION['admin']) return;
  197. $q=$this->PDO_selectUser($vboxRequest['u']);
  198. if(!$skipExistCheck && $q) return;
  199. $np=($vboxRequest['p'])?crypt($vboxRequest['p'], '$1$'.$this->generateRandomSalt().'$'):0;
  200. $query="INSERT INTO `users`(`username`, `password`,`admin`)
  201. VALUES (:username, :password, :admin)
  202. ON DUPLICATE KEY UPDATE `password`=:password, `admin`=:admin";
  203. $sth=$this->newPDO()->prepare($query);
  204. try{
  205. $sth->bindValue(":username",$vboxRequest['u'],PDO::PARAM_STR);
  206. $sth->bindValue(":password",($vboxRequest['p']?$np:$q['password']),PDO::PARAM_STR);
  207. $sth->bindValue(":admin",($vboxRequest['a']?"1":"0"),PDO::PARAM_STR);
  208. $sth->execute();
  209. }catch(PDOException $e){throw new Exception("Can't execute requested query!",vboxconnector::PHPVB_ERRNO_FATAL);}
  210. }
  211. /**
  212. *
  213. * Remove the user $user
  214. * @param string $user Username to remove
  215. */
  216. function deleteUser($user)
  217. {
  218. $sth=$this->newPDO()->prepare("DELETE FROM users WHERE username=:username");
  219. try{
  220. $sth->bindValue(":username",$user,PDO::PARAM_STR);
  221. $sth->execute();
  222. }catch(PDOException $e){throw new Exception("Can't execute requested query!",vboxconnector::PHPVB_ERRNO_FATAL);}
  223. }
  224. }