OC_User.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-only
  6. */
  7. use OC\User\LoginException;
  8. use OCP\EventDispatcher\IEventDispatcher;
  9. use OCP\IGroupManager;
  10. use OCP\ISession;
  11. use OCP\IUser;
  12. use OCP\IUserManager;
  13. use OCP\Server;
  14. use OCP\User\Events\BeforeUserLoggedInEvent;
  15. use OCP\User\Events\UserLoggedInEvent;
  16. use Psr\Log\LoggerInterface;
  17. /**
  18. * This class provides wrapper methods for user management. Multiple backends are
  19. * supported. User management operations are delegated to the configured backend for
  20. * execution.
  21. *
  22. * Note that &run is deprecated and won't work anymore.
  23. *
  24. * Hooks provided:
  25. * pre_createUser(&run, uid, password)
  26. * post_createUser(uid, password)
  27. * pre_deleteUser(&run, uid)
  28. * post_deleteUser(uid)
  29. * pre_setPassword(&run, uid, password, recoveryPassword)
  30. * post_setPassword(uid, password, recoveryPassword)
  31. * pre_login(&run, uid, password)
  32. * post_login(uid)
  33. * logout()
  34. */
  35. class OC_User {
  36. private static $_usedBackends = [];
  37. private static $_setupedBackends = [];
  38. // bool, stores if a user want to access a resource anonymously, e.g if they open a public link
  39. private static $incognitoMode = false;
  40. /**
  41. * Adds the backend to the list of used backends
  42. *
  43. * @param string|\OCP\UserInterface $backend default: database The backend to use for user management
  44. * @return bool
  45. *
  46. * Set the User Authentication Module
  47. * @suppress PhanDeprecatedFunction
  48. */
  49. public static function useBackend($backend = 'database') {
  50. if ($backend instanceof \OCP\UserInterface) {
  51. self::$_usedBackends[get_class($backend)] = $backend;
  52. \OC::$server->getUserManager()->registerBackend($backend);
  53. } else {
  54. // You'll never know what happens
  55. if ($backend === null or !is_string($backend)) {
  56. $backend = 'database';
  57. }
  58. // Load backend
  59. switch ($backend) {
  60. case 'database':
  61. case 'mysql':
  62. case 'sqlite':
  63. Server::get(LoggerInterface::class)->debug('Adding user backend ' . $backend . '.', ['app' => 'core']);
  64. self::$_usedBackends[$backend] = new \OC\User\Database();
  65. \OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]);
  66. break;
  67. case 'dummy':
  68. self::$_usedBackends[$backend] = new \Test\Util\User\Dummy();
  69. \OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]);
  70. break;
  71. default:
  72. Server::get(LoggerInterface::class)->debug('Adding default user backend ' . $backend . '.', ['app' => 'core']);
  73. $className = 'OC_USER_' . strtoupper($backend);
  74. self::$_usedBackends[$backend] = new $className();
  75. \OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]);
  76. break;
  77. }
  78. }
  79. return true;
  80. }
  81. /**
  82. * remove all used backends
  83. */
  84. public static function clearBackends() {
  85. self::$_usedBackends = [];
  86. \OC::$server->getUserManager()->clearBackends();
  87. }
  88. /**
  89. * setup the configured backends in config.php
  90. * @suppress PhanDeprecatedFunction
  91. */
  92. public static function setupBackends() {
  93. OC_App::loadApps(['prelogin']);
  94. $backends = \OC::$server->getSystemConfig()->getValue('user_backends', []);
  95. if (isset($backends['default']) && !$backends['default']) {
  96. // clear default backends
  97. self::clearBackends();
  98. }
  99. foreach ($backends as $i => $config) {
  100. if (!is_array($config)) {
  101. continue;
  102. }
  103. $class = $config['class'];
  104. $arguments = $config['arguments'];
  105. if (class_exists($class)) {
  106. if (!in_array($i, self::$_setupedBackends)) {
  107. // make a reflection object
  108. $reflectionObj = new ReflectionClass($class);
  109. // use Reflection to create a new instance, using the $args
  110. $backend = $reflectionObj->newInstanceArgs($arguments);
  111. self::useBackend($backend);
  112. self::$_setupedBackends[] = $i;
  113. } else {
  114. Server::get(LoggerInterface::class)->debug('User backend ' . $class . ' already initialized.', ['app' => 'core']);
  115. }
  116. } else {
  117. Server::get(LoggerInterface::class)->error('User backend ' . $class . ' not found.', ['app' => 'core']);
  118. }
  119. }
  120. }
  121. /**
  122. * Try to login a user, assuming authentication
  123. * has already happened (e.g. via Single Sign On).
  124. *
  125. * Log in a user and regenerate a new session.
  126. *
  127. * @param \OCP\Authentication\IApacheBackend $backend
  128. * @return bool
  129. */
  130. public static function loginWithApache(\OCP\Authentication\IApacheBackend $backend) {
  131. $uid = $backend->getCurrentUserId();
  132. $run = true;
  133. OC_Hook::emit("OC_User", "pre_login", ["run" => &$run, "uid" => $uid, 'backend' => $backend]);
  134. if ($uid) {
  135. if (self::getUser() !== $uid) {
  136. self::setUserId($uid);
  137. $userSession = \OC::$server->getUserSession();
  138. /** @var IEventDispatcher $dispatcher */
  139. $dispatcher = \OC::$server->get(IEventDispatcher::class);
  140. if ($userSession->getUser() && !$userSession->getUser()->isEnabled()) {
  141. $message = \OC::$server->getL10N('lib')->t('Account disabled');
  142. throw new LoginException($message);
  143. }
  144. $userSession->setLoginName($uid);
  145. $request = OC::$server->getRequest();
  146. $password = null;
  147. if ($backend instanceof \OCP\Authentication\IProvideUserSecretBackend) {
  148. $password = $backend->getCurrentUserSecret();
  149. }
  150. /** @var IEventDispatcher $dispatcher */
  151. $dispatcher->dispatchTyped(new BeforeUserLoggedInEvent($uid, $password, $backend));
  152. $userSession->createSessionToken($request, $uid, $uid, $password);
  153. $userSession->createRememberMeToken($userSession->getUser());
  154. // setup the filesystem
  155. OC_Util::setupFS($uid);
  156. // first call the post_login hooks, the login-process needs to be
  157. // completed before we can safely create the users folder.
  158. // For example encryption needs to initialize the users keys first
  159. // before we can create the user folder with the skeleton files
  160. OC_Hook::emit(
  161. 'OC_User',
  162. 'post_login',
  163. [
  164. 'uid' => $uid,
  165. 'password' => $password,
  166. 'isTokenLogin' => false,
  167. ]
  168. );
  169. $dispatcher->dispatchTyped(new UserLoggedInEvent(
  170. \OC::$server->get(IUserManager::class)->get($uid),
  171. $uid,
  172. null,
  173. false)
  174. );
  175. //trigger creation of user home and /files folder
  176. \OC::$server->getUserFolder($uid);
  177. }
  178. return true;
  179. }
  180. return false;
  181. }
  182. /**
  183. * Verify with Apache whether user is authenticated.
  184. *
  185. * @return boolean|null
  186. * true: authenticated
  187. * false: not authenticated
  188. * null: not handled / no backend available
  189. */
  190. public static function handleApacheAuth() {
  191. $backend = self::findFirstActiveUsedBackend();
  192. if ($backend) {
  193. OC_App::loadApps();
  194. //setup extra user backends
  195. self::setupBackends();
  196. \OC::$server->getUserSession()->unsetMagicInCookie();
  197. return self::loginWithApache($backend);
  198. }
  199. return null;
  200. }
  201. /**
  202. * Sets user id for session and triggers emit
  203. *
  204. * @param string $uid
  205. */
  206. public static function setUserId($uid) {
  207. $userSession = \OC::$server->getUserSession();
  208. $userManager = \OC::$server->getUserManager();
  209. if ($user = $userManager->get($uid)) {
  210. $userSession->setUser($user);
  211. } else {
  212. \OC::$server->getSession()->set('user_id', $uid);
  213. }
  214. }
  215. /**
  216. * Check if the user is logged in, considers also the HTTP basic credentials
  217. *
  218. * @deprecated use \OC::$server->getUserSession()->isLoggedIn()
  219. * @return bool
  220. */
  221. public static function isLoggedIn() {
  222. return \OC::$server->getUserSession()->isLoggedIn();
  223. }
  224. /**
  225. * set incognito mode, e.g. if a user wants to open a public link
  226. *
  227. * @param bool $status
  228. */
  229. public static function setIncognitoMode($status) {
  230. self::$incognitoMode = $status;
  231. }
  232. /**
  233. * get incognito mode status
  234. *
  235. * @return bool
  236. */
  237. public static function isIncognitoMode() {
  238. return self::$incognitoMode;
  239. }
  240. /**
  241. * Returns the current logout URL valid for the currently logged-in user
  242. *
  243. * @param \OCP\IURLGenerator $urlGenerator
  244. * @return string
  245. */
  246. public static function getLogoutUrl(\OCP\IURLGenerator $urlGenerator) {
  247. $backend = self::findFirstActiveUsedBackend();
  248. if ($backend) {
  249. return $backend->getLogoutUrl();
  250. }
  251. $user = \OC::$server->getUserSession()->getUser();
  252. if ($user instanceof IUser) {
  253. $backend = $user->getBackend();
  254. if ($backend instanceof \OCP\User\Backend\ICustomLogout) {
  255. return $backend->getLogoutUrl();
  256. }
  257. }
  258. $logoutUrl = $urlGenerator->linkToRoute('core.login.logout');
  259. $logoutUrl .= '?requesttoken=' . urlencode(\OCP\Util::callRegister());
  260. return $logoutUrl;
  261. }
  262. /**
  263. * Check if the user is an admin user
  264. *
  265. * @param string $uid uid of the admin
  266. * @return bool
  267. */
  268. public static function isAdminUser($uid) {
  269. $user = Server::get(IUserManager::class)->get($uid);
  270. $isAdmin = $user && Server::get(IGroupManager::class)->isAdmin($user->getUID());
  271. return $isAdmin && self::$incognitoMode === false;
  272. }
  273. /**
  274. * get the user id of the user currently logged in.
  275. *
  276. * @return string|false uid or false
  277. */
  278. public static function getUser() {
  279. $uid = Server::get(ISession::class)?->get('user_id');
  280. if (!is_null($uid) && self::$incognitoMode === false) {
  281. return $uid;
  282. } else {
  283. return false;
  284. }
  285. }
  286. /**
  287. * Set password
  288. *
  289. * @param string $uid The username
  290. * @param string $password The new password
  291. * @param string $recoveryPassword for the encryption app to reset encryption keys
  292. * @return bool
  293. *
  294. * Change the password of a user
  295. */
  296. public static function setPassword($uid, $password, $recoveryPassword = null) {
  297. $user = \OC::$server->getUserManager()->get($uid);
  298. if ($user) {
  299. return $user->setPassword($password, $recoveryPassword);
  300. } else {
  301. return false;
  302. }
  303. }
  304. /**
  305. * @param string $uid The username
  306. * @return string
  307. *
  308. * returns the path to the users home directory
  309. * @deprecated Use \OC::$server->getUserManager->getHome()
  310. */
  311. public static function getHome($uid) {
  312. $user = \OC::$server->getUserManager()->get($uid);
  313. if ($user) {
  314. return $user->getHome();
  315. } else {
  316. return \OC::$server->getSystemConfig()->getValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $uid;
  317. }
  318. }
  319. /**
  320. * Get a list of all users display name
  321. *
  322. * @param string $search
  323. * @param int $limit
  324. * @param int $offset
  325. * @return array associative array with all display names (value) and corresponding uids (key)
  326. *
  327. * Get a list of all display names and user ids.
  328. * @deprecated Use \OC::$server->getUserManager->searchDisplayName($search, $limit, $offset) instead.
  329. */
  330. public static function getDisplayNames($search = '', $limit = null, $offset = null) {
  331. $displayNames = [];
  332. $users = \OC::$server->getUserManager()->searchDisplayName($search, $limit, $offset);
  333. foreach ($users as $user) {
  334. $displayNames[$user->getUID()] = $user->getDisplayName();
  335. }
  336. return $displayNames;
  337. }
  338. /**
  339. * Returns the first active backend from self::$_usedBackends.
  340. *
  341. * @return OCP\Authentication\IApacheBackend|null if no backend active, otherwise OCP\Authentication\IApacheBackend
  342. */
  343. private static function findFirstActiveUsedBackend() {
  344. foreach (self::$_usedBackends as $backend) {
  345. if ($backend instanceof OCP\Authentication\IApacheBackend) {
  346. if ($backend->isSessionActive()) {
  347. return $backend;
  348. }
  349. }
  350. }
  351. return null;
  352. }
  353. }