You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

user.php 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. <?php
  2. /**
  3. * ownCloud
  4. *
  5. * @author Frank Karlitschek
  6. * @copyright 2012 Frank Karlitschek frank@owncloud.org
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  10. * License as published by the Free Software Foundation; either
  11. * version 3 of the License, or any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public
  19. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. /**
  23. * This class provides wrapper methods for user management. Multiple backends are
  24. * supported. User management operations are delegated to the configured backend for
  25. * execution.
  26. *
  27. * Hooks provided:
  28. * pre_createUser(&run, uid, password)
  29. * post_createUser(uid, password)
  30. * pre_deleteUser(&run, uid)
  31. * post_deleteUser(uid)
  32. * pre_setPassword(&run, uid, password)
  33. * post_setPassword(uid, password)
  34. * pre_login(&run, uid)
  35. * post_login(uid)
  36. * logout()
  37. */
  38. class OC_User {
  39. // The backend used for user management
  40. private static $_usedBackends = array();
  41. private static $_setupedBackends = array();
  42. // Backends available (except database)
  43. private static $_backends = array();
  44. /**
  45. * @brief registers backend
  46. * @param $name name of the backend
  47. * @returns true/false
  48. *
  49. * Makes a list of backends that can be used by other modules
  50. */
  51. public static function registerBackend( $backend ) {
  52. self::$_backends[] = $backend;
  53. return true;
  54. }
  55. /**
  56. * @brief gets available backends
  57. * @returns array of backends
  58. *
  59. * Returns the names of all backends.
  60. */
  61. public static function getBackends() {
  62. return self::$_backends;
  63. }
  64. /**
  65. * @brief gets used backends
  66. * @returns array of backends
  67. *
  68. * Returns the names of all used backends.
  69. */
  70. public static function getUsedBackends() {
  71. return array_keys(self::$_usedBackends);
  72. }
  73. /**
  74. * @brief Adds the backend to the list of used backends
  75. * @param $backend default: database The backend to use for user managment
  76. * @returns true/false
  77. *
  78. * Set the User Authentication Module
  79. */
  80. public static function useBackend( $backend = 'database' ) {
  81. if($backend instanceof OC_User_Interface) {
  82. self::$_usedBackends[get_class($backend)]=$backend;
  83. }else{
  84. // You'll never know what happens
  85. if( null === $backend OR !is_string( $backend )) {
  86. $backend = 'database';
  87. }
  88. // Load backend
  89. switch( $backend ) {
  90. case 'database':
  91. case 'mysql':
  92. case 'sqlite':
  93. self::$_usedBackends[$backend] = new OC_User_Database();
  94. break;
  95. default:
  96. $className = 'OC_USER_' . strToUpper($backend);
  97. self::$_usedBackends[$backend] = new $className();
  98. break;
  99. }
  100. }
  101. true;
  102. }
  103. /**
  104. * remove all used backends
  105. */
  106. public static function clearBackends() {
  107. self::$_usedBackends=array();
  108. }
  109. /**
  110. * setup the configured backends in config.php
  111. */
  112. public static function setupBackends() {
  113. $backends=OC_Config::getValue('user_backends',array());
  114. foreach($backends as $i=>$config) {
  115. $class=$config['class'];
  116. $arguments=$config['arguments'];
  117. if(class_exists($class) and array_search($i,self::$_setupedBackends)===false) {
  118. // make a reflection object
  119. $reflectionObj = new ReflectionClass($class);
  120. // use Reflection to create a new instance, using the $args
  121. $backend = $reflectionObj->newInstanceArgs($arguments);
  122. self::useBackend($backend);
  123. $_setupedBackends[]=$i;
  124. }else{
  125. OC_Log::write('core','User backend '.$class.' not found.',OC_Log::ERROR);
  126. }
  127. }
  128. }
  129. /**
  130. * @brief Create a new user
  131. * @param $uid The username of the user to create
  132. * @param $password The password of the new user
  133. * @returns true/false
  134. *
  135. * Creates a new user. Basic checking of username is done in OC_User
  136. * itself, not in its subclasses.
  137. *
  138. * Allowed characters in the username are: "a-z", "A-Z", "0-9" and "_.@-"
  139. */
  140. public static function createUser( $uid, $password ) {
  141. // Check the name for bad characters
  142. // Allowed are: "a-z", "A-Z", "0-9" and "_.@-"
  143. if( preg_match( '/[^a-zA-Z0-9 _\.@\-]/', $uid )) {
  144. throw new Exception('Only the following characters are allowed in a username: "a-z", "A-Z", "0-9", and "_.@-"');
  145. }
  146. // No empty username
  147. if(trim($uid) == '') {
  148. throw new Exception('A valid username must be provided');
  149. }
  150. // No empty password
  151. if(trim($password) == '') {
  152. throw new Exception('A valid password must be provided');
  153. }
  154. // Check if user already exists
  155. if( self::userExists($uid) ) {
  156. throw new Exception('The username is already being used');
  157. }
  158. $run = true;
  159. OC_Hook::emit( "OC_User", "pre_createUser", array( "run" => &$run, "uid" => $uid, "password" => $password ));
  160. if( $run ) {
  161. //create the user in the first backend that supports creating users
  162. foreach(self::$_usedBackends as $backend) {
  163. if(!$backend->implementsActions(OC_USER_BACKEND_CREATE_USER))
  164. continue;
  165. $backend->createUser($uid,$password);
  166. OC_Hook::emit( "OC_User", "post_createUser", array( "uid" => $uid, "password" => $password ));
  167. return true;
  168. }
  169. }
  170. return false;
  171. }
  172. /**
  173. * @brief delete a user
  174. * @param $uid The username of the user to delete
  175. * @returns true/false
  176. *
  177. * Deletes a user
  178. */
  179. public static function deleteUser( $uid ) {
  180. $run = true;
  181. OC_Hook::emit( "OC_User", "pre_deleteUser", array( "run" => &$run, "uid" => $uid ));
  182. if( $run ) {
  183. //delete the user from all backends
  184. foreach(self::$_usedBackends as $backend) {
  185. $backend->deleteUser($uid);
  186. }
  187. // We have to delete the user from all groups
  188. foreach( OC_Group::getUserGroups( $uid ) as $i ) {
  189. OC_Group::removeFromGroup( $uid, $i );
  190. }
  191. // Delete the user's keys in preferences
  192. OC_Preferences::deleteUser($uid);
  193. // Delete user files in /data/
  194. OC_Helper::rmdirr(OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ) . '/'.$uid.'/');
  195. // Emit and exit
  196. OC_Hook::emit( "OC_User", "post_deleteUser", array( "uid" => $uid ));
  197. return true;
  198. }
  199. else{
  200. return false;
  201. }
  202. }
  203. /**
  204. * @brief Try to login a user
  205. * @param $uid The username of the user to log in
  206. * @param $password The password of the user
  207. * @returns true/false
  208. *
  209. * Log in a user and regenerate a new session - if the password is ok
  210. */
  211. public static function login( $uid, $password ) {
  212. $run = true;
  213. OC_Hook::emit( "OC_User", "pre_login", array( "run" => &$run, "uid" => $uid ));
  214. if( $run ) {
  215. $uid = self::checkPassword( $uid, $password );
  216. $enabled = self::isEnabled($uid);
  217. if($uid && $enabled) {
  218. session_regenerate_id(true);
  219. self::setUserId($uid);
  220. OC_Hook::emit( "OC_User", "post_login", array( "uid" => $uid, 'password'=>$password ));
  221. return true;
  222. }
  223. }
  224. return false;
  225. }
  226. /**
  227. * @brief Sets user id for session and triggers emit
  228. * @returns true
  229. *
  230. */
  231. public static function setUserId($uid) {
  232. $_SESSION['user_id'] = $uid;
  233. return true;
  234. }
  235. /**
  236. * @brief Logs the current user out and kills all the session data
  237. * @returns true
  238. *
  239. * Logout, destroys session
  240. */
  241. public static function logout() {
  242. OC_Hook::emit( "OC_User", "logout", array());
  243. session_unset();
  244. session_destroy();
  245. OC_User::unsetMagicInCookie();
  246. return true;
  247. }
  248. /**
  249. * @brief Check if the user is logged in
  250. * @returns true/false
  251. *
  252. * Checks if the user is logged in
  253. */
  254. public static function isLoggedIn() {
  255. if( isset($_SESSION['user_id']) AND $_SESSION['user_id']) {
  256. OC_App::loadApps(array('authentication'));
  257. self::setupBackends();
  258. if (self::userExists($_SESSION['user_id']) ) {
  259. return true;
  260. }
  261. }
  262. return false;
  263. }
  264. /**
  265. * @brief get the user id of the user currently logged in.
  266. * @return string uid or false
  267. */
  268. public static function getUser() {
  269. if( isset($_SESSION['user_id']) AND $_SESSION['user_id'] ) {
  270. return $_SESSION['user_id'];
  271. }
  272. else{
  273. return false;
  274. }
  275. }
  276. /**
  277. * @brief Autogenerate a password
  278. * @returns string
  279. *
  280. * generates a password
  281. */
  282. public static function generatePassword() {
  283. return uniqId();
  284. }
  285. /**
  286. * @brief Set password
  287. * @param $uid The username
  288. * @param $password The new password
  289. * @returns true/false
  290. *
  291. * Change the password of a user
  292. */
  293. public static function setPassword( $uid, $password ) {
  294. $run = true;
  295. OC_Hook::emit( "OC_User", "pre_setPassword", array( "run" => &$run, "uid" => $uid, "password" => $password ));
  296. if( $run ) {
  297. $success = false;
  298. foreach(self::$_usedBackends as $backend) {
  299. if($backend->implementsActions(OC_USER_BACKEND_SET_PASSWORD)) {
  300. if($backend->userExists($uid)) {
  301. $success |= $backend->setPassword($uid,$password);
  302. }
  303. }
  304. }
  305. // invalidate all login cookies
  306. OC_Preferences::deleteApp($uid, 'login_token');
  307. OC_Hook::emit( "OC_User", "post_setPassword", array( "uid" => $uid, "password" => $password ));
  308. return $success;
  309. }
  310. else{
  311. return false;
  312. }
  313. }
  314. /**
  315. * @brief Check if the password is correct
  316. * @param $uid The username
  317. * @param $password The password
  318. * @returns string
  319. *
  320. * Check if the password is correct without logging in the user
  321. * returns the user id or false
  322. */
  323. public static function checkPassword( $uid, $password ) {
  324. foreach(self::$_usedBackends as $backend) {
  325. if($backend->implementsActions(OC_USER_BACKEND_CHECK_PASSWORD)) {
  326. $result=$backend->checkPassword( $uid, $password );
  327. if($result) {
  328. return $result;
  329. }
  330. }
  331. }
  332. }
  333. /**
  334. * @brief Check if the password is correct
  335. * @param $uid The username
  336. * @param $password The password
  337. * @returns string
  338. *
  339. * Check if the password is correct without logging in the user
  340. * returns the user id or false
  341. */
  342. public static function getHome($uid) {
  343. foreach(self::$_usedBackends as $backend) {
  344. if($backend->implementsActions(OC_USER_BACKEND_GET_HOME)) {
  345. $result=$backend->getHome($uid);
  346. if($result) {
  347. return $result;
  348. }
  349. }
  350. }
  351. return OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ) . '/' . $uid;
  352. }
  353. /**
  354. * @brief Get a list of all users
  355. * @returns array with all uids
  356. *
  357. * Get a list of all users.
  358. */
  359. public static function getUsers($search = '', $limit = null, $offset = null) {
  360. $users = array();
  361. foreach (self::$_usedBackends as $backend) {
  362. $backendUsers = $backend->getUsers($search, $limit, $offset);
  363. if (is_array($backendUsers)) {
  364. $users = array_merge($users, $backendUsers);
  365. }
  366. }
  367. asort($users);
  368. return $users;
  369. }
  370. /**
  371. * @brief check if a user exists
  372. * @param string $uid the username
  373. * @return boolean
  374. */
  375. public static function userExists($uid) {
  376. foreach(self::$_usedBackends as $backend) {
  377. $result=$backend->userExists($uid);
  378. if($result===true) {
  379. return true;
  380. }
  381. }
  382. return false;
  383. }
  384. /**
  385. * disables a user
  386. * @param string $userid the user to disable
  387. */
  388. public static function disableUser($userid) {
  389. $sql = "INSERT INTO `*PREFIX*preferences` (`userid`, `appid`, `configkey`, `configvalue`) VALUES(?, ?, ?, ?)";
  390. $stmt = OC_DB::prepare($sql);
  391. if ( ! OC_DB::isError($stmt) ) {
  392. $result = $stmt->execute(array($userid, 'core', 'enabled', 'false'));
  393. if ( OC_DB::isError($result) ) {
  394. OC_Log::write('OC_User', 'could not enable user: '. OC_DB::getErrorMessage($result), OC_Log::ERROR);
  395. }
  396. } else {
  397. OC_Log::write('OC_User', 'could not disable user: '. OC_DB::getErrorMessage($stmt), OC_Log::ERROR);
  398. }
  399. }
  400. /**
  401. * enable a user
  402. * @param string $userid
  403. */
  404. public static function enableUser($userid) {
  405. $sql = "DELETE FROM `*PREFIX*preferences` WHERE `userid` = ? AND `appid` = ? AND `configkey` = ? AND `configvalue` = ?";
  406. $stmt = OC_DB::prepare($sql);
  407. if ( ! OC_DB::isError($stmt) ) {
  408. $result = $stmt->execute(array($userid, 'core', 'enabled', 'false'));
  409. if ( OC_DB::isError($result) ) {
  410. OC_Log::write('OC_User', 'could not enable user: '. OC_DB::getErrorMessage($result), OC_Log::ERROR);
  411. }
  412. } else {
  413. OC_Log::write('OC_User', 'could not enable user: '. OC_DB::getErrorMessage($stmt), OC_Log::ERROR);
  414. }
  415. }
  416. /**
  417. * checks if a user is enabled
  418. * @param string $userid
  419. * @return bool
  420. */
  421. public static function isEnabled($userid) {
  422. $sql = "SELECT `userid` FROM `*PREFIX*preferences` WHERE `userid` = ? AND `appid` = ? AND `configkey` = ? AND `configvalue` = ?";
  423. $stmt = OC_DB::prepare($sql);
  424. if ( ! OC_DB::isError($stmt) ) {
  425. $result = $stmt->execute(array($userid, 'core', 'enabled', 'false'));
  426. if ( ! OC_DB::isError($result) ) {
  427. return $result->numRows() ? false : true;
  428. } else {
  429. OC_Log::write('OC_User', 'could not check if enabled: '. OC_DB::getErrorMessage($result), OC_Log::ERROR);
  430. }
  431. } else {
  432. OC_Log::write('OC_User', 'could not check if enabled: '. OC_DB::getErrorMessage($stmt), OC_Log::ERROR);
  433. }
  434. return false;
  435. }
  436. /**
  437. * @brief Set cookie value to use in next page load
  438. * @param string $username username to be set
  439. */
  440. public static function setMagicInCookie($username, $token) {
  441. $secure_cookie = OC_Config::getValue("forcessl", false);
  442. $expires = time() + OC_Config::getValue('remember_login_cookie_lifetime', 60*60*24*15);
  443. setcookie("oc_username", $username, $expires, '', '', $secure_cookie);
  444. setcookie("oc_token", $token, $expires, '', '', $secure_cookie, true);
  445. setcookie("oc_remember_login", true, $expires, '', '', $secure_cookie);
  446. }
  447. /**
  448. * @brief Remove cookie for "remember username"
  449. */
  450. public static function unsetMagicInCookie() {
  451. unset($_COOKIE["oc_username"]);
  452. unset($_COOKIE["oc_token"]);
  453. unset($_COOKIE["oc_remember_login"]);
  454. setcookie("oc_username", null, -1);
  455. setcookie("oc_token", null, -1);
  456. setcookie("oc_remember_login", null, -1);
  457. }
  458. }