manager.php 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. <?php
  2. /**
  3. * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
  4. * This file is licensed under the Affero General Public License version 3 or
  5. * later.
  6. * See the COPYING-README file.
  7. */
  8. namespace OC\User;
  9. use OC\Hooks\PublicEmitter;
  10. use OCP\IUserManager;
  11. use OCP\IConfig;
  12. /**
  13. * Class Manager
  14. *
  15. * Hooks available in scope \OC\User:
  16. * - preSetPassword(\OC\User\User $user, string $password, string $recoverPassword)
  17. * - postSetPassword(\OC\User\User $user, string $password, string $recoverPassword)
  18. * - preDelete(\OC\User\User $user)
  19. * - postDelete(\OC\User\User $user)
  20. * - preCreateUser(string $uid, string $password)
  21. * - postCreateUser(\OC\User\User $user, string $password)
  22. *
  23. * @package OC\User
  24. */
  25. class Manager extends PublicEmitter implements IUserManager {
  26. /**
  27. * @var \OCP\UserInterface [] $backends
  28. */
  29. private $backends = array();
  30. /**
  31. * @var \OC\User\User[] $cachedUsers
  32. */
  33. private $cachedUsers = array();
  34. /**
  35. * @var \OCP\IConfig $config
  36. */
  37. private $config;
  38. /**
  39. * @param \OCP\IConfig $config
  40. */
  41. public function __construct(IConfig $config = null) {
  42. $this->config = $config;
  43. $cachedUsers = &$this->cachedUsers;
  44. $this->listen('\OC\User', 'postDelete', function ($user) use (&$cachedUsers) {
  45. /** @var \OC\User\User $user */
  46. unset($cachedUsers[$user->getUID()]);
  47. });
  48. $this->listen('\OC\User', 'postLogin', function ($user) {
  49. /** @var \OC\User\User $user */
  50. $user->updateLastLoginTimestamp();
  51. });
  52. $this->listen('\OC\User', 'postRememberedLogin', function ($user) {
  53. /** @var \OC\User\User $user */
  54. $user->updateLastLoginTimestamp();
  55. });
  56. }
  57. /**
  58. * Get the active backends
  59. * @return \OCP\UserInterface[]
  60. */
  61. public function getBackends() {
  62. return $this->backends;
  63. }
  64. /**
  65. * register a user backend
  66. *
  67. * @param \OCP\UserInterface $backend
  68. */
  69. public function registerBackend($backend) {
  70. $this->backends[] = $backend;
  71. }
  72. /**
  73. * remove a user backend
  74. *
  75. * @param \OCP\UserInterface $backend
  76. */
  77. public function removeBackend($backend) {
  78. $this->cachedUsers = array();
  79. if (($i = array_search($backend, $this->backends)) !== false) {
  80. unset($this->backends[$i]);
  81. }
  82. }
  83. /**
  84. * remove all user backends
  85. */
  86. public function clearBackends() {
  87. $this->cachedUsers = array();
  88. $this->backends = array();
  89. }
  90. /**
  91. * get a user by user id
  92. *
  93. * @param string $uid
  94. * @return \OC\User\User|null Either the user or null if the specified user does not exist
  95. */
  96. public function get($uid) {
  97. if (isset($this->cachedUsers[$uid])) { //check the cache first to prevent having to loop over the backends
  98. return $this->cachedUsers[$uid];
  99. }
  100. foreach ($this->backends as $backend) {
  101. if ($backend->userExists($uid)) {
  102. return $this->getUserObject($uid, $backend);
  103. }
  104. }
  105. return null;
  106. }
  107. /**
  108. * get or construct the user object
  109. *
  110. * @param string $uid
  111. * @param \OCP\UserInterface $backend
  112. * @return \OC\User\User
  113. */
  114. protected function getUserObject($uid, $backend) {
  115. if (isset($this->cachedUsers[$uid])) {
  116. return $this->cachedUsers[$uid];
  117. }
  118. $this->cachedUsers[$uid] = new User($uid, $backend, $this, $this->config);
  119. return $this->cachedUsers[$uid];
  120. }
  121. /**
  122. * check if a user exists
  123. *
  124. * @param string $uid
  125. * @return bool
  126. */
  127. public function userExists($uid) {
  128. $user = $this->get($uid);
  129. return ($user !== null);
  130. }
  131. /**
  132. * Check if the password is valid for the user
  133. *
  134. * @param string $loginname
  135. * @param string $password
  136. * @return mixed the User object on success, false otherwise
  137. */
  138. public function checkPassword($loginname, $password) {
  139. $loginname = str_replace("\0", '', $loginname);
  140. $password = str_replace("\0", '', $password);
  141. foreach ($this->backends as $backend) {
  142. if ($backend->implementsActions(\OC_User_Backend::CHECK_PASSWORD)) {
  143. $uid = $backend->checkPassword($loginname, $password);
  144. if ($uid !== false) {
  145. return $this->getUserObject($uid, $backend);
  146. }
  147. }
  148. }
  149. \OC::$server->getLogger()->warning('Login failed: \''. $loginname .'\' (Remote IP: \''. \OC::$server->getRequest()->getRemoteAddress(). ')', ['app' => 'core']);
  150. return false;
  151. }
  152. /**
  153. * search by user id
  154. *
  155. * @param string $pattern
  156. * @param int $limit
  157. * @param int $offset
  158. * @return \OC\User\User[]
  159. */
  160. public function search($pattern, $limit = null, $offset = null) {
  161. $users = array();
  162. foreach ($this->backends as $backend) {
  163. $backendUsers = $backend->getUsers($pattern, $limit, $offset);
  164. if (is_array($backendUsers)) {
  165. foreach ($backendUsers as $uid) {
  166. $users[$uid] = $this->getUserObject($uid, $backend);
  167. }
  168. }
  169. }
  170. uasort($users, function ($a, $b) {
  171. /**
  172. * @var \OC\User\User $a
  173. * @var \OC\User\User $b
  174. */
  175. return strcmp($a->getUID(), $b->getUID());
  176. });
  177. return $users;
  178. }
  179. /**
  180. * search by displayName
  181. *
  182. * @param string $pattern
  183. * @param int $limit
  184. * @param int $offset
  185. * @return \OC\User\User[]
  186. */
  187. public function searchDisplayName($pattern, $limit = null, $offset = null) {
  188. $users = array();
  189. foreach ($this->backends as $backend) {
  190. $backendUsers = $backend->getDisplayNames($pattern, $limit, $offset);
  191. if (is_array($backendUsers)) {
  192. foreach ($backendUsers as $uid => $displayName) {
  193. $users[] = $this->getUserObject($uid, $backend);
  194. }
  195. }
  196. }
  197. usort($users, function ($a, $b) {
  198. /**
  199. * @var \OC\User\User $a
  200. * @var \OC\User\User $b
  201. */
  202. return strcmp($a->getDisplayName(), $b->getDisplayName());
  203. });
  204. return $users;
  205. }
  206. /**
  207. * @param string $uid
  208. * @param string $password
  209. * @throws \Exception
  210. * @return bool|\OC\User\User the created user or false
  211. */
  212. public function createUser($uid, $password) {
  213. $l = \OC::$server->getL10N('lib');
  214. // Check the name for bad characters
  215. // Allowed are: "a-z", "A-Z", "0-9" and "_.@-"
  216. if (preg_match('/[^a-zA-Z0-9 _\.@\-]/', $uid)) {
  217. throw new \Exception($l->t('Only the following characters are allowed in a username:'
  218. . ' "a-z", "A-Z", "0-9", and "_.@-"'));
  219. }
  220. // No empty username
  221. if (trim($uid) == '') {
  222. throw new \Exception($l->t('A valid username must be provided'));
  223. }
  224. // No empty password
  225. if (trim($password) == '') {
  226. throw new \Exception($l->t('A valid password must be provided'));
  227. }
  228. // Check if user already exists
  229. if ($this->userExists($uid)) {
  230. throw new \Exception($l->t('The username is already being used'));
  231. }
  232. $this->emit('\OC\User', 'preCreateUser', array($uid, $password));
  233. foreach ($this->backends as $backend) {
  234. if ($backend->implementsActions(\OC_User_Backend::CREATE_USER)) {
  235. $backend->createUser($uid, $password);
  236. $user = $this->getUserObject($uid, $backend);
  237. $this->emit('\OC\User', 'postCreateUser', array($user, $password));
  238. return $user;
  239. }
  240. }
  241. return false;
  242. }
  243. /**
  244. * returns how many users per backend exist (if supported by backend)
  245. *
  246. * @return array an array of backend class as key and count number as value
  247. */
  248. public function countUsers() {
  249. $userCountStatistics = array();
  250. foreach ($this->backends as $backend) {
  251. if ($backend->implementsActions(\OC_User_Backend::COUNT_USERS)) {
  252. $backendusers = $backend->countUsers();
  253. if($backendusers !== false) {
  254. if($backend instanceof \OCP\IUserBackend) {
  255. $name = $backend->getBackendName();
  256. } else {
  257. $name = get_class($backend);
  258. }
  259. if(isset($userCountStatistics[$name])) {
  260. $userCountStatistics[$name] += $backendusers;
  261. } else {
  262. $userCountStatistics[$name] = $backendusers;
  263. }
  264. }
  265. }
  266. }
  267. return $userCountStatistics;
  268. }
  269. }