manager.php 8.3 KB

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