user.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  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. OC_Log::write('core', 'Adding user backend instance of '.get_class($backend).'.', OC_Log::DEBUG);
  83. self::$_usedBackends[get_class($backend)]=$backend;
  84. } else {
  85. // You'll never know what happens
  86. if( null === $backend OR !is_string( $backend )) {
  87. $backend = 'database';
  88. }
  89. // Load backend
  90. switch( $backend ) {
  91. case 'database':
  92. case 'mysql':
  93. case 'sqlite':
  94. OC_Log::write('core', 'Adding user backend '.$backend.'.', OC_Log::DEBUG);
  95. self::$_usedBackends[$backend] = new OC_User_Database();
  96. break;
  97. default:
  98. OC_Log::write('core', 'Adding default user backend '.$backend.'.', OC_Log::DEBUG);
  99. $className = 'OC_USER_' . strToUpper($backend);
  100. self::$_usedBackends[$backend] = new $className();
  101. break;
  102. }
  103. }
  104. return true;
  105. }
  106. /**
  107. * remove all used backends
  108. */
  109. public static function clearBackends() {
  110. self::$_usedBackends=array();
  111. }
  112. /**
  113. * setup the configured backends in config.php
  114. */
  115. public static function setupBackends() {
  116. $backends=OC_Config::getValue('user_backends', array());
  117. foreach($backends as $i=>$config) {
  118. $class=$config['class'];
  119. $arguments=$config['arguments'];
  120. if(class_exists($class)) {
  121. if(array_search($i, self::$_setupedBackends)===false) {
  122. // make a reflection object
  123. $reflectionObj = new ReflectionClass($class);
  124. // use Reflection to create a new instance, using the $args
  125. $backend = $reflectionObj->newInstanceArgs($arguments);
  126. self::useBackend($backend);
  127. $_setupedBackends[]=$i;
  128. } else {
  129. OC_Log::write('core', 'User backend '.$class.' already initialized.', OC_Log::DEBUG);
  130. }
  131. } else {
  132. OC_Log::write('core', 'User backend '.$class.' not found.', OC_Log::ERROR);
  133. }
  134. }
  135. }
  136. /**
  137. * @brief Create a new user
  138. * @param $uid The username of the user to create
  139. * @param $password The password of the new user
  140. * @returns true/false
  141. *
  142. * Creates a new user. Basic checking of username is done in OC_User
  143. * itself, not in its subclasses.
  144. *
  145. * Allowed characters in the username are: "a-z", "A-Z", "0-9" and "_.@-"
  146. */
  147. public static function createUser( $uid, $password ) {
  148. // Check the name for bad characters
  149. // Allowed are: "a-z", "A-Z", "0-9" and "_.@-"
  150. if( preg_match( '/[^a-zA-Z0-9 _\.@\-]/', $uid )) {
  151. throw new Exception('Only the following characters are allowed in a username: "a-z", "A-Z", "0-9", and "_.@-"');
  152. }
  153. // No empty username
  154. if(trim($uid) == '') {
  155. throw new Exception('A valid username must be provided');
  156. }
  157. // No empty password
  158. if(trim($password) == '') {
  159. throw new Exception('A valid password must be provided');
  160. }
  161. // Check if user already exists
  162. if( self::userExists($uid) ) {
  163. throw new Exception('The username is already being used');
  164. }
  165. $run = true;
  166. OC_Hook::emit( "OC_User", "pre_createUser", array( "run" => &$run, "uid" => $uid, "password" => $password ));
  167. if( $run ) {
  168. //create the user in the first backend that supports creating users
  169. foreach(self::$_usedBackends as $backend) {
  170. if(!$backend->implementsActions(OC_USER_BACKEND_CREATE_USER))
  171. continue;
  172. $backend->createUser($uid, $password);
  173. OC_Hook::emit( "OC_User", "post_createUser", array( "uid" => $uid, "password" => $password ));
  174. return self::userExists($uid);
  175. }
  176. }
  177. return false;
  178. }
  179. /**
  180. * @brief delete a user
  181. * @param $uid The username of the user to delete
  182. * @returns true/false
  183. *
  184. * Deletes a user
  185. */
  186. public static function deleteUser( $uid ) {
  187. $run = true;
  188. OC_Hook::emit( "OC_User", "pre_deleteUser", array( "run" => &$run, "uid" => $uid ));
  189. if( $run ) {
  190. //delete the user from all backends
  191. foreach(self::$_usedBackends as $backend) {
  192. $backend->deleteUser($uid);
  193. }
  194. if (self::userExists($uid)) {
  195. return false;
  196. }
  197. // We have to delete the user from all groups
  198. foreach( OC_Group::getUserGroups( $uid ) as $i ) {
  199. OC_Group::removeFromGroup( $uid, $i );
  200. }
  201. // Delete the user's keys in preferences
  202. OC_Preferences::deleteUser($uid);
  203. // Delete user files in /data/
  204. OC_Helper::rmdirr(OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ) . '/'.$uid.'/');
  205. // Emit and exit
  206. OC_Hook::emit( "OC_User", "post_deleteUser", array( "uid" => $uid ));
  207. return true;
  208. }
  209. else{
  210. return false;
  211. }
  212. }
  213. /**
  214. * @brief Try to login a user
  215. * @param $uid The username of the user to log in
  216. * @param $password The password of the user
  217. * @returns true/false
  218. *
  219. * Log in a user and regenerate a new session - if the password is ok
  220. */
  221. public static function login( $uid, $password ) {
  222. $run = true;
  223. OC_Hook::emit( "OC_User", "pre_login", array( "run" => &$run, "uid" => $uid ));
  224. if( $run ) {
  225. $uid = self::checkPassword( $uid, $password );
  226. $enabled = self::isEnabled($uid);
  227. if($uid && $enabled) {
  228. session_regenerate_id(true);
  229. self::setUserId($uid);
  230. self::setDisplayName($uid);
  231. OC_Hook::emit( "OC_User", "post_login", array( "uid" => $uid, 'password'=>$password ));
  232. return true;
  233. }
  234. }
  235. return false;
  236. }
  237. /**
  238. * @brief Sets user id for session and triggers emit
  239. */
  240. public static function setUserId($uid) {
  241. $_SESSION['user_id'] = $uid;
  242. }
  243. /**
  244. * @brief Sets user display name for session
  245. */
  246. public static function setDisplayName($uid, $displayName = null) {
  247. $result = false;
  248. if ($displayName ) {
  249. foreach(self::$_usedBackends as $backend) {
  250. if($backend->implementsActions(OC_USER_BACKEND_SET_DISPLAYNAME)) {
  251. if($backend->userExists($uid)) {
  252. $result |= $backend->setDisplayName($uid, $displayName);
  253. }
  254. }
  255. }
  256. } else {
  257. $displayName = self::determineDisplayName($uid);
  258. $result = true;
  259. }
  260. if (OC_User::getUser() === $uid) {
  261. $_SESSION['display_name'] = $displayName;
  262. }
  263. return $result;
  264. }
  265. /**
  266. * @brief get display name
  267. * @param $uid The username
  268. * @returns string display name or uid if no display name is defined
  269. *
  270. */
  271. private static function determineDisplayName( $uid ) {
  272. foreach(self::$_usedBackends as $backend) {
  273. if($backend->implementsActions(OC_USER_BACKEND_GET_DISPLAYNAME)) {
  274. $result=$backend->getDisplayName( $uid );
  275. if($result) {
  276. return $result;
  277. }
  278. }
  279. }
  280. return $uid;
  281. }
  282. /**
  283. * @brief Logs the current user out and kills all the session data
  284. *
  285. * Logout, destroys session
  286. */
  287. public static function logout() {
  288. OC_Hook::emit( "OC_User", "logout", array());
  289. session_unset();
  290. session_destroy();
  291. OC_User::unsetMagicInCookie();
  292. }
  293. /**
  294. * @brief Check if the user is logged in
  295. * @returns true/false
  296. *
  297. * Checks if the user is logged in
  298. */
  299. public static function isLoggedIn() {
  300. if( isset($_SESSION['user_id']) AND $_SESSION['user_id']) {
  301. OC_App::loadApps(array('authentication'));
  302. self::setupBackends();
  303. if (self::userExists($_SESSION['user_id']) ) {
  304. return true;
  305. }
  306. }
  307. return false;
  308. }
  309. /**
  310. * @brief Check if the user is an admin user
  311. * @param $uid uid of the admin
  312. * @returns bool
  313. */
  314. public static function isAdminUser($uid) {
  315. if(OC_Group::inGroup($uid, 'admin' )) {
  316. return true;
  317. }
  318. return false;
  319. }
  320. /**
  321. * @brief get the user id of the user currently logged in.
  322. * @return string uid or false
  323. */
  324. public static function getUser() {
  325. if( isset($_SESSION['user_id']) AND $_SESSION['user_id'] ) {
  326. return $_SESSION['user_id'];
  327. }
  328. else{
  329. return false;
  330. }
  331. }
  332. /**
  333. * @brief get the display name of the user currently logged in.
  334. * @return string uid or false
  335. */
  336. public static function getDisplayName($user=null) {
  337. if ( $user ) {
  338. return self::determineDisplayName($user);
  339. } else if( isset($_SESSION['display_name']) AND $_SESSION['display_name'] ) {
  340. return $_SESSION['display_name'];
  341. }
  342. else{
  343. return false;
  344. }
  345. }
  346. /**
  347. * @brief Autogenerate a password
  348. * @returns string
  349. *
  350. * generates a password
  351. */
  352. public static function generatePassword() {
  353. return uniqId();
  354. }
  355. /**
  356. * @brief Set password
  357. * @param $uid The username
  358. * @param $password The new password
  359. * @returns true/false
  360. *
  361. * Change the password of a user
  362. */
  363. public static function setPassword( $uid, $password ) {
  364. $run = true;
  365. OC_Hook::emit( "OC_User", "pre_setPassword", array( "run" => &$run, "uid" => $uid, "password" => $password ));
  366. if( $run ) {
  367. $success = false;
  368. foreach(self::$_usedBackends as $backend) {
  369. if($backend->implementsActions(OC_USER_BACKEND_SET_PASSWORD)) {
  370. if($backend->userExists($uid)) {
  371. $success |= $backend->setPassword($uid, $password);
  372. }
  373. }
  374. }
  375. // invalidate all login cookies
  376. OC_Preferences::deleteApp($uid, 'login_token');
  377. OC_Hook::emit( "OC_User", "post_setPassword", array( "uid" => $uid, "password" => $password ));
  378. return $success;
  379. }
  380. else{
  381. return false;
  382. }
  383. }
  384. /**
  385. * @brief Check whether user can change his password
  386. * @param $uid The username
  387. * @returns true/false
  388. *
  389. * Check whether a specified user can change his password
  390. */
  391. public static function canUserChangePassword($uid) {
  392. foreach(self::$_usedBackends as $backend) {
  393. if($backend->implementsActions(OC_USER_BACKEND_SET_PASSWORD)) {
  394. if($backend->userExists($uid)) {
  395. return true;
  396. }
  397. }
  398. }
  399. return false;
  400. }
  401. /**
  402. * @brief Check whether user can change his display name
  403. * @param $uid The username
  404. * @returns true/false
  405. *
  406. * Check whether a specified user can change his display name
  407. */
  408. public static function canUserChangeDisplayName($uid) {
  409. foreach(self::$_usedBackends as $backend) {
  410. if($backend->implementsActions(OC_USER_BACKEND_SET_DISPLAYNAME)) {
  411. if($backend->userExists($uid)) {
  412. return true;
  413. }
  414. }
  415. }
  416. return false;
  417. }
  418. /**
  419. * @brief Check if the password is correct
  420. * @param $uid The username
  421. * @param $password The password
  422. * @returns string
  423. *
  424. * Check if the password is correct without logging in the user
  425. * returns the user id or false
  426. */
  427. public static function checkPassword( $uid, $password ) {
  428. foreach(self::$_usedBackends as $backend) {
  429. if($backend->implementsActions(OC_USER_BACKEND_CHECK_PASSWORD)) {
  430. $result=$backend->checkPassword( $uid, $password );
  431. if($result) {
  432. return $result;
  433. }
  434. }
  435. }
  436. }
  437. /**
  438. * @brief Check if the password is correct
  439. * @param string $uid The username
  440. * @param string $password The password
  441. * @returns string
  442. *
  443. * returns the path to the users home directory
  444. */
  445. public static function getHome($uid) {
  446. foreach(self::$_usedBackends as $backend) {
  447. if($backend->implementsActions(OC_USER_BACKEND_GET_HOME)) {
  448. $result=$backend->getHome($uid);
  449. if($result) {
  450. return $result;
  451. }
  452. }
  453. }
  454. return OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ) . '/' . $uid;
  455. }
  456. /**
  457. * @brief Get a list of all users
  458. * @returns array with all uids
  459. *
  460. * Get a list of all users.
  461. */
  462. public static function getUsers($search = '', $limit = null, $offset = null) {
  463. $users = array();
  464. foreach (self::$_usedBackends as $backend) {
  465. $backendUsers = $backend->getUsers($search, $limit, $offset);
  466. if (is_array($backendUsers)) {
  467. $users = array_merge($users, $backendUsers);
  468. }
  469. }
  470. asort($users);
  471. return $users;
  472. }
  473. /**
  474. * @brief Get a list of all users display name
  475. * @returns associative array with all display names (value) and corresponding uids (key)
  476. *
  477. * Get a list of all display names and user ids.
  478. */
  479. public static function getDisplayNames($search = '', $limit = null, $offset = null) {
  480. $displayNames = array();
  481. foreach (self::$_usedBackends as $backend) {
  482. $backendDisplayNames = $backend->getDisplayNames($search, $limit, $offset);
  483. if (is_array($backendDisplayNames)) {
  484. $displayNames = array_merge($displayNames, $backendDisplayNames);
  485. }
  486. }
  487. ksort($displayNames);
  488. return $displayNames;
  489. }
  490. /**
  491. * @brief check if a user exists
  492. * @param string $uid the username
  493. * @param string $excludingBackend (default none)
  494. * @return boolean
  495. */
  496. public static function userExists($uid, $excludingBackend=null) {
  497. foreach(self::$_usedBackends as $backend) {
  498. if (!is_null($excludingBackend) && !strcmp(get_class($backend),$excludingBackend)) {
  499. OC_Log::write('OC_User', $excludingBackend . 'excluded from user existance check.', OC_Log::DEBUG);
  500. continue;
  501. }
  502. $result=$backend->userExists($uid);
  503. if($result===true) {
  504. return true;
  505. }
  506. }
  507. return false;
  508. }
  509. /**
  510. * disables a user
  511. * @param string $userid the user to disable
  512. */
  513. public static function disableUser($userid) {
  514. $sql = "INSERT INTO `*PREFIX*preferences` (`userid`, `appid`, `configkey`, `configvalue`) VALUES(?, ?, ?, ?)";
  515. $stmt = OC_DB::prepare($sql);
  516. if ( ! OC_DB::isError($stmt) ) {
  517. $result = $stmt->execute(array($userid, 'core', 'enabled', 'false'));
  518. if ( OC_DB::isError($result) ) {
  519. OC_Log::write('OC_User', 'could not enable user: '. OC_DB::getErrorMessage($result), OC_Log::ERROR);
  520. }
  521. } else {
  522. OC_Log::write('OC_User', 'could not disable user: '. OC_DB::getErrorMessage($stmt), OC_Log::ERROR);
  523. }
  524. }
  525. /**
  526. * enable a user
  527. * @param string $userid
  528. */
  529. public static function enableUser($userid) {
  530. $sql = "DELETE FROM `*PREFIX*preferences` WHERE `userid` = ? AND `appid` = ? AND `configkey` = ? AND `configvalue` = ?";
  531. $stmt = OC_DB::prepare($sql);
  532. if ( ! OC_DB::isError($stmt) ) {
  533. $result = $stmt->execute(array($userid, 'core', 'enabled', 'false'));
  534. if ( OC_DB::isError($result) ) {
  535. OC_Log::write('OC_User', 'could not enable user: '. OC_DB::getErrorMessage($result), OC_Log::ERROR);
  536. }
  537. } else {
  538. OC_Log::write('OC_User', 'could not enable user: '. OC_DB::getErrorMessage($stmt), OC_Log::ERROR);
  539. }
  540. }
  541. /**
  542. * checks if a user is enabled
  543. * @param string $userid
  544. * @return bool
  545. */
  546. public static function isEnabled($userid) {
  547. $sql = "SELECT `userid` FROM `*PREFIX*preferences` WHERE `userid` = ? AND `appid` = ? AND `configkey` = ? AND `configvalue` = ?";
  548. $stmt = OC_DB::prepare($sql);
  549. if ( ! OC_DB::isError($stmt) ) {
  550. $result = $stmt->execute(array($userid, 'core', 'enabled', 'false'));
  551. if ( ! OC_DB::isError($result) ) {
  552. return $result->numRows() ? false : true;
  553. } else {
  554. OC_Log::write('OC_User', 'could not check if enabled: '. OC_DB::getErrorMessage($result), OC_Log::ERROR);
  555. }
  556. } else {
  557. OC_Log::write('OC_User', 'could not check if enabled: '. OC_DB::getErrorMessage($stmt), OC_Log::ERROR);
  558. }
  559. return false;
  560. }
  561. /**
  562. * @brief Set cookie value to use in next page load
  563. * @param string $username username to be set
  564. */
  565. public static function setMagicInCookie($username, $token) {
  566. $secure_cookie = OC_Config::getValue("forcessl", false);
  567. $expires = time() + OC_Config::getValue('remember_login_cookie_lifetime', 60*60*24*15);
  568. setcookie("oc_username", $username, $expires, '', '', $secure_cookie);
  569. setcookie("oc_token", $token, $expires, '', '', $secure_cookie, true);
  570. setcookie("oc_remember_login", true, $expires, '', '', $secure_cookie);
  571. }
  572. /**
  573. * @brief Remove cookie for "remember username"
  574. */
  575. public static function unsetMagicInCookie() {
  576. unset($_COOKIE["oc_username"]);
  577. unset($_COOKIE["oc_token"]);
  578. unset($_COOKIE["oc_remember_login"]);
  579. setcookie("oc_username", null, -1);
  580. setcookie("oc_token", null, -1);
  581. setcookie("oc_remember_login", null, -1);
  582. }
  583. }