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 18KB

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