Passed
Push — master ( d011df...0d46fa )
by Joas
15:48 queued 11s
created
apps/user_ldap/lib/User_LDAP.php 1 patch
Indentation   +583 added lines, -583 removed lines patch added patch discarded remove patch
@@ -52,587 +52,587 @@
 block discarded – undo
52 52
 use OCP\Util;
53 53
 
54 54
 class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserInterface, IUserLDAP {
55
-	/** @var \OCP\IConfig */
56
-	protected $ocConfig;
57
-
58
-	/** @var INotificationManager */
59
-	protected $notificationManager;
60
-
61
-	/** @var UserPluginManager */
62
-	protected $userPluginManager;
63
-
64
-	/**
65
-	 * @param Access $access
66
-	 * @param \OCP\IConfig $ocConfig
67
-	 * @param \OCP\Notification\IManager $notificationManager
68
-	 * @param IUserSession $userSession
69
-	 */
70
-	public function __construct(Access $access, IConfig $ocConfig, INotificationManager $notificationManager, IUserSession $userSession, UserPluginManager $userPluginManager) {
71
-		parent::__construct($access);
72
-		$this->ocConfig = $ocConfig;
73
-		$this->notificationManager = $notificationManager;
74
-		$this->userPluginManager = $userPluginManager;
75
-	}
76
-
77
-	/**
78
-	 * checks whether the user is allowed to change his avatar in Nextcloud
79
-	 *
80
-	 * @param string $uid the Nextcloud user name
81
-	 * @return boolean either the user can or cannot
82
-	 * @throws \Exception
83
-	 */
84
-	public function canChangeAvatar($uid) {
85
-		if ($this->userPluginManager->implementsActions(Backend::PROVIDE_AVATAR)) {
86
-			return $this->userPluginManager->canChangeAvatar($uid);
87
-		}
88
-
89
-		if (!$this->implementsActions(Backend::PROVIDE_AVATAR)) {
90
-			return true;
91
-		}
92
-
93
-		$user = $this->access->userManager->get($uid);
94
-		if (!$user instanceof User) {
95
-			return false;
96
-		}
97
-		$imageData = $user->getAvatarImage();
98
-		if ($imageData === false) {
99
-			return true;
100
-		}
101
-		return !$user->updateAvatar(true);
102
-	}
103
-
104
-	/**
105
-	 * Return the username for the given login name, if available
106
-	 *
107
-	 * @param string $loginName
108
-	 * @return string|false
109
-	 * @throws \Exception
110
-	 */
111
-	public function loginName2UserName($loginName) {
112
-		$cacheKey = 'loginName2UserName-' . $loginName;
113
-		$username = $this->access->connection->getFromCache($cacheKey);
114
-
115
-		if ($username !== null) {
116
-			return $username;
117
-		}
118
-
119
-		try {
120
-			$ldapRecord = $this->getLDAPUserByLoginName($loginName);
121
-			$user = $this->access->userManager->get($ldapRecord['dn'][0]);
122
-			if ($user === null || $user instanceof OfflineUser) {
123
-				// this path is not really possible, however get() is documented
124
-				// to return User, OfflineUser or null so we are very defensive here.
125
-				$this->access->connection->writeToCache($cacheKey, false);
126
-				return false;
127
-			}
128
-			$username = $user->getUsername();
129
-			$this->access->connection->writeToCache($cacheKey, $username);
130
-			return $username;
131
-		} catch (NotOnLDAP $e) {
132
-			$this->access->connection->writeToCache($cacheKey, false);
133
-			return false;
134
-		}
135
-	}
136
-
137
-	/**
138
-	 * returns the username for the given LDAP DN, if available
139
-	 *
140
-	 * @param string $dn
141
-	 * @return string|false with the username
142
-	 */
143
-	public function dn2UserName($dn) {
144
-		return $this->access->dn2username($dn);
145
-	}
146
-
147
-	/**
148
-	 * returns an LDAP record based on a given login name
149
-	 *
150
-	 * @param string $loginName
151
-	 * @return array
152
-	 * @throws NotOnLDAP
153
-	 */
154
-	public function getLDAPUserByLoginName($loginName) {
155
-		//find out dn of the user name
156
-		$attrs = $this->access->userManager->getAttributes();
157
-		$users = $this->access->fetchUsersByLoginName($loginName, $attrs);
158
-		if (count($users) < 1) {
159
-			throw new NotOnLDAP('No user available for the given login name on ' .
160
-				$this->access->connection->ldapHost . ':' . $this->access->connection->ldapPort);
161
-		}
162
-		return $users[0];
163
-	}
164
-
165
-	/**
166
-	 * Check if the password is correct without logging in the user
167
-	 *
168
-	 * @param string $uid The username
169
-	 * @param string $password The password
170
-	 * @return false|string
171
-	 */
172
-	public function checkPassword($uid, $password) {
173
-		try {
174
-			$ldapRecord = $this->getLDAPUserByLoginName($uid);
175
-		} catch (NotOnLDAP $e) {
176
-			\OC::$server->getLogger()->logException($e, ['app' => 'user_ldap', 'level' => ILogger::DEBUG]);
177
-			return false;
178
-		}
179
-		$dn = $ldapRecord['dn'][0];
180
-		$user = $this->access->userManager->get($dn);
181
-
182
-		if (!$user instanceof User) {
183
-			Util::writeLog('user_ldap',
184
-				'LDAP Login: Could not get user object for DN ' . $dn .
185
-				'. Maybe the LDAP entry has no set display name attribute?',
186
-				ILogger::WARN);
187
-			return false;
188
-		}
189
-		if ($user->getUsername() !== false) {
190
-			//are the credentials OK?
191
-			if (!$this->access->areCredentialsValid($dn, $password)) {
192
-				return false;
193
-			}
194
-
195
-			$this->access->cacheUserExists($user->getUsername());
196
-			$user->processAttributes($ldapRecord);
197
-			$user->markLogin();
198
-
199
-			return $user->getUsername();
200
-		}
201
-
202
-		return false;
203
-	}
204
-
205
-	/**
206
-	 * Set password
207
-	 * @param string $uid The username
208
-	 * @param string $password The new password
209
-	 * @return bool
210
-	 */
211
-	public function setPassword($uid, $password) {
212
-		if ($this->userPluginManager->implementsActions(Backend::SET_PASSWORD)) {
213
-			return $this->userPluginManager->setPassword($uid, $password);
214
-		}
215
-
216
-		$user = $this->access->userManager->get($uid);
217
-
218
-		if (!$user instanceof User) {
219
-			throw new \Exception('LDAP setPassword: Could not get user object for uid ' . $uid .
220
-				'. Maybe the LDAP entry has no set display name attribute?');
221
-		}
222
-		if ($user->getUsername() !== false && $this->access->setPassword($user->getDN(), $password)) {
223
-			$ldapDefaultPPolicyDN = $this->access->connection->ldapDefaultPPolicyDN;
224
-			$turnOnPasswordChange = $this->access->connection->turnOnPasswordChange;
225
-			if (!empty($ldapDefaultPPolicyDN) && ((int)$turnOnPasswordChange === 1)) {
226
-				//remove last password expiry warning if any
227
-				$notification = $this->notificationManager->createNotification();
228
-				$notification->setApp('user_ldap')
229
-					->setUser($uid)
230
-					->setObject('pwd_exp_warn', $uid)
231
-				;
232
-				$this->notificationManager->markProcessed($notification);
233
-			}
234
-			return true;
235
-		}
236
-
237
-		return false;
238
-	}
239
-
240
-	/**
241
-	 * Get a list of all users
242
-	 *
243
-	 * @param string $search
244
-	 * @param integer $limit
245
-	 * @param integer $offset
246
-	 * @return string[] an array of all uids
247
-	 */
248
-	public function getUsers($search = '', $limit = 10, $offset = 0) {
249
-		$search = $this->access->escapeFilterPart($search, true);
250
-		$cachekey = 'getUsers-'.$search.'-'.$limit.'-'.$offset;
251
-
252
-		//check if users are cached, if so return
253
-		$ldap_users = $this->access->connection->getFromCache($cachekey);
254
-		if (!is_null($ldap_users)) {
255
-			return $ldap_users;
256
-		}
257
-
258
-		// if we'd pass -1 to LDAP search, we'd end up in a Protocol
259
-		// error. With a limit of 0, we get 0 results. So we pass null.
260
-		if ($limit <= 0) {
261
-			$limit = null;
262
-		}
263
-		$filter = $this->access->combineFilterWithAnd([
264
-			$this->access->connection->ldapUserFilter,
265
-			$this->access->connection->ldapUserDisplayName . '=*',
266
-			$this->access->getFilterPartForUserSearch($search)
267
-		]);
268
-
269
-		Util::writeLog('user_ldap',
270
-			'getUsers: Options: search '.$search.' limit '.$limit.' offset '.$offset.' Filter: '.$filter,
271
-			ILogger::DEBUG);
272
-		//do the search and translate results to Nextcloud names
273
-		$ldap_users = $this->access->fetchListOfUsers(
274
-			$filter,
275
-			$this->access->userManager->getAttributes(true),
276
-			$limit, $offset);
277
-		$ldap_users = $this->access->nextcloudUserNames($ldap_users);
278
-		Util::writeLog('user_ldap', 'getUsers: '.count($ldap_users). ' Users found', ILogger::DEBUG);
279
-
280
-		$this->access->connection->writeToCache($cachekey, $ldap_users);
281
-		return $ldap_users;
282
-	}
283
-
284
-	/**
285
-	 * checks whether a user is still available on LDAP
286
-	 *
287
-	 * @param string|\OCA\User_LDAP\User\User $user either the Nextcloud user
288
-	 * name or an instance of that user
289
-	 * @return bool
290
-	 * @throws \Exception
291
-	 * @throws \OC\ServerNotAvailableException
292
-	 */
293
-	public function userExistsOnLDAP($user) {
294
-		if (is_string($user)) {
295
-			$user = $this->access->userManager->get($user);
296
-		}
297
-		if (is_null($user)) {
298
-			return false;
299
-		}
300
-		$uid = $user instanceof User ? $user->getUsername() : $user->getOCName();
301
-		$cacheKey = 'userExistsOnLDAP' . $uid;
302
-		$userExists = $this->access->connection->getFromCache($cacheKey);
303
-		if (!is_null($userExists)) {
304
-			return (bool)$userExists;
305
-		}
306
-
307
-		$dn = $user->getDN();
308
-		//check if user really still exists by reading its entry
309
-		if (!is_array($this->access->readAttribute($dn, '', $this->access->connection->ldapUserFilter))) {
310
-			try {
311
-				$uuid = $this->access->getUserMapper()->getUUIDByDN($dn);
312
-				if (!$uuid) {
313
-					$this->access->connection->writeToCache($cacheKey, false);
314
-					return false;
315
-				}
316
-				$newDn = $this->access->getUserDnByUuid($uuid);
317
-				//check if renamed user is still valid by reapplying the ldap filter
318
-				if ($newDn === $dn || !is_array($this->access->readAttribute($newDn, '', $this->access->connection->ldapUserFilter))) {
319
-					$this->access->connection->writeToCache($cacheKey, false);
320
-					return false;
321
-				}
322
-				$this->access->getUserMapper()->setDNbyUUID($newDn, $uuid);
323
-				$this->access->connection->writeToCache($cacheKey, true);
324
-				return true;
325
-			} catch (ServerNotAvailableException $e) {
326
-				throw $e;
327
-			} catch (\Exception $e) {
328
-				$this->access->connection->writeToCache($cacheKey, false);
329
-				return false;
330
-			}
331
-		}
332
-
333
-		if ($user instanceof OfflineUser) {
334
-			$user->unmark();
335
-		}
336
-
337
-		$this->access->connection->writeToCache($cacheKey, true);
338
-		return true;
339
-	}
340
-
341
-	/**
342
-	 * check if a user exists
343
-	 * @param string $uid the username
344
-	 * @return boolean
345
-	 * @throws \Exception when connection could not be established
346
-	 */
347
-	public function userExists($uid) {
348
-		$userExists = $this->access->connection->getFromCache('userExists'.$uid);
349
-		if (!is_null($userExists)) {
350
-			return (bool)$userExists;
351
-		}
352
-		//getting dn, if false the user does not exist. If dn, he may be mapped only, requires more checking.
353
-		$user = $this->access->userManager->get($uid);
354
-
355
-		if (is_null($user)) {
356
-			Util::writeLog('user_ldap', 'No DN found for '.$uid.' on '.
357
-				$this->access->connection->ldapHost, ILogger::DEBUG);
358
-			$this->access->connection->writeToCache('userExists'.$uid, false);
359
-			return false;
360
-		}
361
-
362
-		$this->access->connection->writeToCache('userExists'.$uid, true);
363
-		return true;
364
-	}
365
-
366
-	/**
367
-	 * returns whether a user was deleted in LDAP
368
-	 *
369
-	 * @param string $uid The username of the user to delete
370
-	 * @return bool
371
-	 */
372
-	public function deleteUser($uid) {
373
-		if ($this->userPluginManager->canDeleteUser()) {
374
-			$status = $this->userPluginManager->deleteUser($uid);
375
-			if ($status === false) {
376
-				return false;
377
-			}
378
-		}
379
-
380
-		$marked = $this->ocConfig->getUserValue($uid, 'user_ldap', 'isDeleted', 0);
381
-		if ((int)$marked === 0) {
382
-			\OC::$server->getLogger()->notice(
383
-				'User '.$uid . ' is not marked as deleted, not cleaning up.',
384
-				['app' => 'user_ldap']);
385
-			return false;
386
-		}
387
-		\OC::$server->getLogger()->info('Cleaning up after user ' . $uid,
388
-			['app' => 'user_ldap']);
389
-
390
-		$this->access->getUserMapper()->unmap($uid); // we don't emit unassign signals here, since it is implicit to delete signals fired from core
391
-		$this->access->userManager->invalidate($uid);
392
-		$this->access->connection->clearCache();
393
-		return true;
394
-	}
395
-
396
-	/**
397
-	 * get the user's home directory
398
-	 *
399
-	 * @param string $uid the username
400
-	 * @return bool|string
401
-	 * @throws NoUserException
402
-	 * @throws \Exception
403
-	 */
404
-	public function getHome($uid) {
405
-		// user Exists check required as it is not done in user proxy!
406
-		if (!$this->userExists($uid)) {
407
-			return false;
408
-		}
409
-
410
-		if ($this->userPluginManager->implementsActions(Backend::GET_HOME)) {
411
-			return $this->userPluginManager->getHome($uid);
412
-		}
413
-
414
-		$cacheKey = 'getHome'.$uid;
415
-		$path = $this->access->connection->getFromCache($cacheKey);
416
-		if (!is_null($path)) {
417
-			return $path;
418
-		}
419
-
420
-		// early return path if it is a deleted user
421
-		$user = $this->access->userManager->get($uid);
422
-		if ($user instanceof User || $user instanceof OfflineUser) {
423
-			$path = $user->getHomePath() ?: false;
424
-		} else {
425
-			throw new NoUserException($uid . ' is not a valid user anymore');
426
-		}
427
-
428
-		$this->access->cacheUserHome($uid, $path);
429
-		return $path;
430
-	}
431
-
432
-	/**
433
-	 * get display name of the user
434
-	 * @param string $uid user ID of the user
435
-	 * @return string|false display name
436
-	 */
437
-	public function getDisplayName($uid) {
438
-		if ($this->userPluginManager->implementsActions(Backend::GET_DISPLAYNAME)) {
439
-			return $this->userPluginManager->getDisplayName($uid);
440
-		}
441
-
442
-		if (!$this->userExists($uid)) {
443
-			return false;
444
-		}
445
-
446
-		$cacheKey = 'getDisplayName'.$uid;
447
-		if (!is_null($displayName = $this->access->connection->getFromCache($cacheKey))) {
448
-			return $displayName;
449
-		}
450
-
451
-		//Check whether the display name is configured to have a 2nd feature
452
-		$additionalAttribute = $this->access->connection->ldapUserDisplayName2;
453
-		$displayName2 = '';
454
-		if ($additionalAttribute !== '') {
455
-			$displayName2 = $this->access->readAttribute(
456
-				$this->access->username2dn($uid),
457
-				$additionalAttribute);
458
-		}
459
-
460
-		$displayName = $this->access->readAttribute(
461
-			$this->access->username2dn($uid),
462
-			$this->access->connection->ldapUserDisplayName);
463
-
464
-		if ($displayName && (count($displayName) > 0)) {
465
-			$displayName = $displayName[0];
466
-
467
-			if (is_array($displayName2)) {
468
-				$displayName2 = count($displayName2) > 0 ? $displayName2[0] : '';
469
-			}
470
-
471
-			$user = $this->access->userManager->get($uid);
472
-			if ($user instanceof User) {
473
-				$displayName = $user->composeAndStoreDisplayName($displayName, $displayName2);
474
-				$this->access->connection->writeToCache($cacheKey, $displayName);
475
-			}
476
-			if ($user instanceof OfflineUser) {
477
-				/** @var OfflineUser $user*/
478
-				$displayName = $user->getDisplayName();
479
-			}
480
-			return $displayName;
481
-		}
482
-
483
-		return null;
484
-	}
485
-
486
-	/**
487
-	 * set display name of the user
488
-	 * @param string $uid user ID of the user
489
-	 * @param string $displayName new display name of the user
490
-	 * @return string|false display name
491
-	 */
492
-	public function setDisplayName($uid, $displayName) {
493
-		if ($this->userPluginManager->implementsActions(Backend::SET_DISPLAYNAME)) {
494
-			$this->userPluginManager->setDisplayName($uid, $displayName);
495
-			$this->access->cacheUserDisplayName($uid, $displayName);
496
-			return $displayName;
497
-		}
498
-		return false;
499
-	}
500
-
501
-	/**
502
-	 * Get a list of all display names
503
-	 *
504
-	 * @param string $search
505
-	 * @param int|null $limit
506
-	 * @param int|null $offset
507
-	 * @return array an array of all displayNames (value) and the corresponding uids (key)
508
-	 */
509
-	public function getDisplayNames($search = '', $limit = null, $offset = null) {
510
-		$cacheKey = 'getDisplayNames-'.$search.'-'.$limit.'-'.$offset;
511
-		if (!is_null($displayNames = $this->access->connection->getFromCache($cacheKey))) {
512
-			return $displayNames;
513
-		}
514
-
515
-		$displayNames = [];
516
-		$users = $this->getUsers($search, $limit, $offset);
517
-		foreach ($users as $user) {
518
-			$displayNames[$user] = $this->getDisplayName($user);
519
-		}
520
-		$this->access->connection->writeToCache($cacheKey, $displayNames);
521
-		return $displayNames;
522
-	}
523
-
524
-	/**
525
-	 * Check if backend implements actions
526
-	 * @param int $actions bitwise-or'ed actions
527
-	 * @return boolean
528
-	 *
529
-	 * Returns the supported actions as int to be
530
-	 * compared with \OC\User\Backend::CREATE_USER etc.
531
-	 */
532
-	public function implementsActions($actions) {
533
-		return (bool)((Backend::CHECK_PASSWORD
534
-			| Backend::GET_HOME
535
-			| Backend::GET_DISPLAYNAME
536
-			| (($this->access->connection->ldapUserAvatarRule !== 'none') ? Backend::PROVIDE_AVATAR : 0)
537
-			| Backend::COUNT_USERS
538
-			| (((int)$this->access->connection->turnOnPasswordChange === 1)? Backend::SET_PASSWORD :0)
539
-			| $this->userPluginManager->getImplementedActions())
540
-			& $actions);
541
-	}
542
-
543
-	/**
544
-	 * @return bool
545
-	 */
546
-	public function hasUserListings() {
547
-		return true;
548
-	}
549
-
550
-	/**
551
-	 * counts the users in LDAP
552
-	 *
553
-	 * @return int|bool
554
-	 */
555
-	public function countUsers() {
556
-		if ($this->userPluginManager->implementsActions(Backend::COUNT_USERS)) {
557
-			return $this->userPluginManager->countUsers();
558
-		}
559
-
560
-		$filter = $this->access->getFilterForUserCount();
561
-		$cacheKey = 'countUsers-'.$filter;
562
-		if (!is_null($entries = $this->access->connection->getFromCache($cacheKey))) {
563
-			return $entries;
564
-		}
565
-		$entries = $this->access->countUsers($filter);
566
-		$this->access->connection->writeToCache($cacheKey, $entries);
567
-		return $entries;
568
-	}
569
-
570
-	/**
571
-	 * Backend name to be shown in user management
572
-	 * @return string the name of the backend to be shown
573
-	 */
574
-	public function getBackendName() {
575
-		return 'LDAP';
576
-	}
577
-
578
-	/**
579
-	 * Return access for LDAP interaction.
580
-	 * @param string $uid
581
-	 * @return Access instance of Access for LDAP interaction
582
-	 */
583
-	public function getLDAPAccess($uid) {
584
-		return $this->access;
585
-	}
586
-
587
-	/**
588
-	 * Return LDAP connection resource from a cloned connection.
589
-	 * The cloned connection needs to be closed manually.
590
-	 * of the current access.
591
-	 * @param string $uid
592
-	 * @return resource of the LDAP connection
593
-	 */
594
-	public function getNewLDAPConnection($uid) {
595
-		$connection = clone $this->access->getConnection();
596
-		return $connection->getConnectionResource();
597
-	}
598
-
599
-	/**
600
-	 * create new user
601
-	 * @param string $username username of the new user
602
-	 * @param string $password password of the new user
603
-	 * @throws \UnexpectedValueException
604
-	 * @return bool
605
-	 */
606
-	public function createUser($username, $password) {
607
-		if ($this->userPluginManager->implementsActions(Backend::CREATE_USER)) {
608
-			if ($dn = $this->userPluginManager->createUser($username, $password)) {
609
-				if (is_string($dn)) {
610
-					// the NC user creation work flow requires a know user id up front
611
-					$uuid = $this->access->getUUID($dn, true);
612
-					if (is_string($uuid)) {
613
-						$this->access->mapAndAnnounceIfApplicable(
614
-							$this->access->getUserMapper(),
615
-							$dn,
616
-							$username,
617
-							$uuid,
618
-							true
619
-						);
620
-						$this->access->cacheUserExists($username);
621
-					} else {
622
-						\OC::$server->getLogger()->warning(
623
-							'Failed to map created LDAP user with userid {userid}, because UUID could not be determined',
624
-							[
625
-								'app' => 'user_ldap',
626
-								'userid' => $username,
627
-							]
628
-						);
629
-					}
630
-				} else {
631
-					throw new \UnexpectedValueException("LDAP Plugin: Method createUser changed to return the user DN instead of boolean.");
632
-				}
633
-			}
634
-			return (bool) $dn;
635
-		}
636
-		return false;
637
-	}
55
+    /** @var \OCP\IConfig */
56
+    protected $ocConfig;
57
+
58
+    /** @var INotificationManager */
59
+    protected $notificationManager;
60
+
61
+    /** @var UserPluginManager */
62
+    protected $userPluginManager;
63
+
64
+    /**
65
+     * @param Access $access
66
+     * @param \OCP\IConfig $ocConfig
67
+     * @param \OCP\Notification\IManager $notificationManager
68
+     * @param IUserSession $userSession
69
+     */
70
+    public function __construct(Access $access, IConfig $ocConfig, INotificationManager $notificationManager, IUserSession $userSession, UserPluginManager $userPluginManager) {
71
+        parent::__construct($access);
72
+        $this->ocConfig = $ocConfig;
73
+        $this->notificationManager = $notificationManager;
74
+        $this->userPluginManager = $userPluginManager;
75
+    }
76
+
77
+    /**
78
+     * checks whether the user is allowed to change his avatar in Nextcloud
79
+     *
80
+     * @param string $uid the Nextcloud user name
81
+     * @return boolean either the user can or cannot
82
+     * @throws \Exception
83
+     */
84
+    public function canChangeAvatar($uid) {
85
+        if ($this->userPluginManager->implementsActions(Backend::PROVIDE_AVATAR)) {
86
+            return $this->userPluginManager->canChangeAvatar($uid);
87
+        }
88
+
89
+        if (!$this->implementsActions(Backend::PROVIDE_AVATAR)) {
90
+            return true;
91
+        }
92
+
93
+        $user = $this->access->userManager->get($uid);
94
+        if (!$user instanceof User) {
95
+            return false;
96
+        }
97
+        $imageData = $user->getAvatarImage();
98
+        if ($imageData === false) {
99
+            return true;
100
+        }
101
+        return !$user->updateAvatar(true);
102
+    }
103
+
104
+    /**
105
+     * Return the username for the given login name, if available
106
+     *
107
+     * @param string $loginName
108
+     * @return string|false
109
+     * @throws \Exception
110
+     */
111
+    public function loginName2UserName($loginName) {
112
+        $cacheKey = 'loginName2UserName-' . $loginName;
113
+        $username = $this->access->connection->getFromCache($cacheKey);
114
+
115
+        if ($username !== null) {
116
+            return $username;
117
+        }
118
+
119
+        try {
120
+            $ldapRecord = $this->getLDAPUserByLoginName($loginName);
121
+            $user = $this->access->userManager->get($ldapRecord['dn'][0]);
122
+            if ($user === null || $user instanceof OfflineUser) {
123
+                // this path is not really possible, however get() is documented
124
+                // to return User, OfflineUser or null so we are very defensive here.
125
+                $this->access->connection->writeToCache($cacheKey, false);
126
+                return false;
127
+            }
128
+            $username = $user->getUsername();
129
+            $this->access->connection->writeToCache($cacheKey, $username);
130
+            return $username;
131
+        } catch (NotOnLDAP $e) {
132
+            $this->access->connection->writeToCache($cacheKey, false);
133
+            return false;
134
+        }
135
+    }
136
+
137
+    /**
138
+     * returns the username for the given LDAP DN, if available
139
+     *
140
+     * @param string $dn
141
+     * @return string|false with the username
142
+     */
143
+    public function dn2UserName($dn) {
144
+        return $this->access->dn2username($dn);
145
+    }
146
+
147
+    /**
148
+     * returns an LDAP record based on a given login name
149
+     *
150
+     * @param string $loginName
151
+     * @return array
152
+     * @throws NotOnLDAP
153
+     */
154
+    public function getLDAPUserByLoginName($loginName) {
155
+        //find out dn of the user name
156
+        $attrs = $this->access->userManager->getAttributes();
157
+        $users = $this->access->fetchUsersByLoginName($loginName, $attrs);
158
+        if (count($users) < 1) {
159
+            throw new NotOnLDAP('No user available for the given login name on ' .
160
+                $this->access->connection->ldapHost . ':' . $this->access->connection->ldapPort);
161
+        }
162
+        return $users[0];
163
+    }
164
+
165
+    /**
166
+     * Check if the password is correct without logging in the user
167
+     *
168
+     * @param string $uid The username
169
+     * @param string $password The password
170
+     * @return false|string
171
+     */
172
+    public function checkPassword($uid, $password) {
173
+        try {
174
+            $ldapRecord = $this->getLDAPUserByLoginName($uid);
175
+        } catch (NotOnLDAP $e) {
176
+            \OC::$server->getLogger()->logException($e, ['app' => 'user_ldap', 'level' => ILogger::DEBUG]);
177
+            return false;
178
+        }
179
+        $dn = $ldapRecord['dn'][0];
180
+        $user = $this->access->userManager->get($dn);
181
+
182
+        if (!$user instanceof User) {
183
+            Util::writeLog('user_ldap',
184
+                'LDAP Login: Could not get user object for DN ' . $dn .
185
+                '. Maybe the LDAP entry has no set display name attribute?',
186
+                ILogger::WARN);
187
+            return false;
188
+        }
189
+        if ($user->getUsername() !== false) {
190
+            //are the credentials OK?
191
+            if (!$this->access->areCredentialsValid($dn, $password)) {
192
+                return false;
193
+            }
194
+
195
+            $this->access->cacheUserExists($user->getUsername());
196
+            $user->processAttributes($ldapRecord);
197
+            $user->markLogin();
198
+
199
+            return $user->getUsername();
200
+        }
201
+
202
+        return false;
203
+    }
204
+
205
+    /**
206
+     * Set password
207
+     * @param string $uid The username
208
+     * @param string $password The new password
209
+     * @return bool
210
+     */
211
+    public function setPassword($uid, $password) {
212
+        if ($this->userPluginManager->implementsActions(Backend::SET_PASSWORD)) {
213
+            return $this->userPluginManager->setPassword($uid, $password);
214
+        }
215
+
216
+        $user = $this->access->userManager->get($uid);
217
+
218
+        if (!$user instanceof User) {
219
+            throw new \Exception('LDAP setPassword: Could not get user object for uid ' . $uid .
220
+                '. Maybe the LDAP entry has no set display name attribute?');
221
+        }
222
+        if ($user->getUsername() !== false && $this->access->setPassword($user->getDN(), $password)) {
223
+            $ldapDefaultPPolicyDN = $this->access->connection->ldapDefaultPPolicyDN;
224
+            $turnOnPasswordChange = $this->access->connection->turnOnPasswordChange;
225
+            if (!empty($ldapDefaultPPolicyDN) && ((int)$turnOnPasswordChange === 1)) {
226
+                //remove last password expiry warning if any
227
+                $notification = $this->notificationManager->createNotification();
228
+                $notification->setApp('user_ldap')
229
+                    ->setUser($uid)
230
+                    ->setObject('pwd_exp_warn', $uid)
231
+                ;
232
+                $this->notificationManager->markProcessed($notification);
233
+            }
234
+            return true;
235
+        }
236
+
237
+        return false;
238
+    }
239
+
240
+    /**
241
+     * Get a list of all users
242
+     *
243
+     * @param string $search
244
+     * @param integer $limit
245
+     * @param integer $offset
246
+     * @return string[] an array of all uids
247
+     */
248
+    public function getUsers($search = '', $limit = 10, $offset = 0) {
249
+        $search = $this->access->escapeFilterPart($search, true);
250
+        $cachekey = 'getUsers-'.$search.'-'.$limit.'-'.$offset;
251
+
252
+        //check if users are cached, if so return
253
+        $ldap_users = $this->access->connection->getFromCache($cachekey);
254
+        if (!is_null($ldap_users)) {
255
+            return $ldap_users;
256
+        }
257
+
258
+        // if we'd pass -1 to LDAP search, we'd end up in a Protocol
259
+        // error. With a limit of 0, we get 0 results. So we pass null.
260
+        if ($limit <= 0) {
261
+            $limit = null;
262
+        }
263
+        $filter = $this->access->combineFilterWithAnd([
264
+            $this->access->connection->ldapUserFilter,
265
+            $this->access->connection->ldapUserDisplayName . '=*',
266
+            $this->access->getFilterPartForUserSearch($search)
267
+        ]);
268
+
269
+        Util::writeLog('user_ldap',
270
+            'getUsers: Options: search '.$search.' limit '.$limit.' offset '.$offset.' Filter: '.$filter,
271
+            ILogger::DEBUG);
272
+        //do the search and translate results to Nextcloud names
273
+        $ldap_users = $this->access->fetchListOfUsers(
274
+            $filter,
275
+            $this->access->userManager->getAttributes(true),
276
+            $limit, $offset);
277
+        $ldap_users = $this->access->nextcloudUserNames($ldap_users);
278
+        Util::writeLog('user_ldap', 'getUsers: '.count($ldap_users). ' Users found', ILogger::DEBUG);
279
+
280
+        $this->access->connection->writeToCache($cachekey, $ldap_users);
281
+        return $ldap_users;
282
+    }
283
+
284
+    /**
285
+     * checks whether a user is still available on LDAP
286
+     *
287
+     * @param string|\OCA\User_LDAP\User\User $user either the Nextcloud user
288
+     * name or an instance of that user
289
+     * @return bool
290
+     * @throws \Exception
291
+     * @throws \OC\ServerNotAvailableException
292
+     */
293
+    public function userExistsOnLDAP($user) {
294
+        if (is_string($user)) {
295
+            $user = $this->access->userManager->get($user);
296
+        }
297
+        if (is_null($user)) {
298
+            return false;
299
+        }
300
+        $uid = $user instanceof User ? $user->getUsername() : $user->getOCName();
301
+        $cacheKey = 'userExistsOnLDAP' . $uid;
302
+        $userExists = $this->access->connection->getFromCache($cacheKey);
303
+        if (!is_null($userExists)) {
304
+            return (bool)$userExists;
305
+        }
306
+
307
+        $dn = $user->getDN();
308
+        //check if user really still exists by reading its entry
309
+        if (!is_array($this->access->readAttribute($dn, '', $this->access->connection->ldapUserFilter))) {
310
+            try {
311
+                $uuid = $this->access->getUserMapper()->getUUIDByDN($dn);
312
+                if (!$uuid) {
313
+                    $this->access->connection->writeToCache($cacheKey, false);
314
+                    return false;
315
+                }
316
+                $newDn = $this->access->getUserDnByUuid($uuid);
317
+                //check if renamed user is still valid by reapplying the ldap filter
318
+                if ($newDn === $dn || !is_array($this->access->readAttribute($newDn, '', $this->access->connection->ldapUserFilter))) {
319
+                    $this->access->connection->writeToCache($cacheKey, false);
320
+                    return false;
321
+                }
322
+                $this->access->getUserMapper()->setDNbyUUID($newDn, $uuid);
323
+                $this->access->connection->writeToCache($cacheKey, true);
324
+                return true;
325
+            } catch (ServerNotAvailableException $e) {
326
+                throw $e;
327
+            } catch (\Exception $e) {
328
+                $this->access->connection->writeToCache($cacheKey, false);
329
+                return false;
330
+            }
331
+        }
332
+
333
+        if ($user instanceof OfflineUser) {
334
+            $user->unmark();
335
+        }
336
+
337
+        $this->access->connection->writeToCache($cacheKey, true);
338
+        return true;
339
+    }
340
+
341
+    /**
342
+     * check if a user exists
343
+     * @param string $uid the username
344
+     * @return boolean
345
+     * @throws \Exception when connection could not be established
346
+     */
347
+    public function userExists($uid) {
348
+        $userExists = $this->access->connection->getFromCache('userExists'.$uid);
349
+        if (!is_null($userExists)) {
350
+            return (bool)$userExists;
351
+        }
352
+        //getting dn, if false the user does not exist. If dn, he may be mapped only, requires more checking.
353
+        $user = $this->access->userManager->get($uid);
354
+
355
+        if (is_null($user)) {
356
+            Util::writeLog('user_ldap', 'No DN found for '.$uid.' on '.
357
+                $this->access->connection->ldapHost, ILogger::DEBUG);
358
+            $this->access->connection->writeToCache('userExists'.$uid, false);
359
+            return false;
360
+        }
361
+
362
+        $this->access->connection->writeToCache('userExists'.$uid, true);
363
+        return true;
364
+    }
365
+
366
+    /**
367
+     * returns whether a user was deleted in LDAP
368
+     *
369
+     * @param string $uid The username of the user to delete
370
+     * @return bool
371
+     */
372
+    public function deleteUser($uid) {
373
+        if ($this->userPluginManager->canDeleteUser()) {
374
+            $status = $this->userPluginManager->deleteUser($uid);
375
+            if ($status === false) {
376
+                return false;
377
+            }
378
+        }
379
+
380
+        $marked = $this->ocConfig->getUserValue($uid, 'user_ldap', 'isDeleted', 0);
381
+        if ((int)$marked === 0) {
382
+            \OC::$server->getLogger()->notice(
383
+                'User '.$uid . ' is not marked as deleted, not cleaning up.',
384
+                ['app' => 'user_ldap']);
385
+            return false;
386
+        }
387
+        \OC::$server->getLogger()->info('Cleaning up after user ' . $uid,
388
+            ['app' => 'user_ldap']);
389
+
390
+        $this->access->getUserMapper()->unmap($uid); // we don't emit unassign signals here, since it is implicit to delete signals fired from core
391
+        $this->access->userManager->invalidate($uid);
392
+        $this->access->connection->clearCache();
393
+        return true;
394
+    }
395
+
396
+    /**
397
+     * get the user's home directory
398
+     *
399
+     * @param string $uid the username
400
+     * @return bool|string
401
+     * @throws NoUserException
402
+     * @throws \Exception
403
+     */
404
+    public function getHome($uid) {
405
+        // user Exists check required as it is not done in user proxy!
406
+        if (!$this->userExists($uid)) {
407
+            return false;
408
+        }
409
+
410
+        if ($this->userPluginManager->implementsActions(Backend::GET_HOME)) {
411
+            return $this->userPluginManager->getHome($uid);
412
+        }
413
+
414
+        $cacheKey = 'getHome'.$uid;
415
+        $path = $this->access->connection->getFromCache($cacheKey);
416
+        if (!is_null($path)) {
417
+            return $path;
418
+        }
419
+
420
+        // early return path if it is a deleted user
421
+        $user = $this->access->userManager->get($uid);
422
+        if ($user instanceof User || $user instanceof OfflineUser) {
423
+            $path = $user->getHomePath() ?: false;
424
+        } else {
425
+            throw new NoUserException($uid . ' is not a valid user anymore');
426
+        }
427
+
428
+        $this->access->cacheUserHome($uid, $path);
429
+        return $path;
430
+    }
431
+
432
+    /**
433
+     * get display name of the user
434
+     * @param string $uid user ID of the user
435
+     * @return string|false display name
436
+     */
437
+    public function getDisplayName($uid) {
438
+        if ($this->userPluginManager->implementsActions(Backend::GET_DISPLAYNAME)) {
439
+            return $this->userPluginManager->getDisplayName($uid);
440
+        }
441
+
442
+        if (!$this->userExists($uid)) {
443
+            return false;
444
+        }
445
+
446
+        $cacheKey = 'getDisplayName'.$uid;
447
+        if (!is_null($displayName = $this->access->connection->getFromCache($cacheKey))) {
448
+            return $displayName;
449
+        }
450
+
451
+        //Check whether the display name is configured to have a 2nd feature
452
+        $additionalAttribute = $this->access->connection->ldapUserDisplayName2;
453
+        $displayName2 = '';
454
+        if ($additionalAttribute !== '') {
455
+            $displayName2 = $this->access->readAttribute(
456
+                $this->access->username2dn($uid),
457
+                $additionalAttribute);
458
+        }
459
+
460
+        $displayName = $this->access->readAttribute(
461
+            $this->access->username2dn($uid),
462
+            $this->access->connection->ldapUserDisplayName);
463
+
464
+        if ($displayName && (count($displayName) > 0)) {
465
+            $displayName = $displayName[0];
466
+
467
+            if (is_array($displayName2)) {
468
+                $displayName2 = count($displayName2) > 0 ? $displayName2[0] : '';
469
+            }
470
+
471
+            $user = $this->access->userManager->get($uid);
472
+            if ($user instanceof User) {
473
+                $displayName = $user->composeAndStoreDisplayName($displayName, $displayName2);
474
+                $this->access->connection->writeToCache($cacheKey, $displayName);
475
+            }
476
+            if ($user instanceof OfflineUser) {
477
+                /** @var OfflineUser $user*/
478
+                $displayName = $user->getDisplayName();
479
+            }
480
+            return $displayName;
481
+        }
482
+
483
+        return null;
484
+    }
485
+
486
+    /**
487
+     * set display name of the user
488
+     * @param string $uid user ID of the user
489
+     * @param string $displayName new display name of the user
490
+     * @return string|false display name
491
+     */
492
+    public function setDisplayName($uid, $displayName) {
493
+        if ($this->userPluginManager->implementsActions(Backend::SET_DISPLAYNAME)) {
494
+            $this->userPluginManager->setDisplayName($uid, $displayName);
495
+            $this->access->cacheUserDisplayName($uid, $displayName);
496
+            return $displayName;
497
+        }
498
+        return false;
499
+    }
500
+
501
+    /**
502
+     * Get a list of all display names
503
+     *
504
+     * @param string $search
505
+     * @param int|null $limit
506
+     * @param int|null $offset
507
+     * @return array an array of all displayNames (value) and the corresponding uids (key)
508
+     */
509
+    public function getDisplayNames($search = '', $limit = null, $offset = null) {
510
+        $cacheKey = 'getDisplayNames-'.$search.'-'.$limit.'-'.$offset;
511
+        if (!is_null($displayNames = $this->access->connection->getFromCache($cacheKey))) {
512
+            return $displayNames;
513
+        }
514
+
515
+        $displayNames = [];
516
+        $users = $this->getUsers($search, $limit, $offset);
517
+        foreach ($users as $user) {
518
+            $displayNames[$user] = $this->getDisplayName($user);
519
+        }
520
+        $this->access->connection->writeToCache($cacheKey, $displayNames);
521
+        return $displayNames;
522
+    }
523
+
524
+    /**
525
+     * Check if backend implements actions
526
+     * @param int $actions bitwise-or'ed actions
527
+     * @return boolean
528
+     *
529
+     * Returns the supported actions as int to be
530
+     * compared with \OC\User\Backend::CREATE_USER etc.
531
+     */
532
+    public function implementsActions($actions) {
533
+        return (bool)((Backend::CHECK_PASSWORD
534
+            | Backend::GET_HOME
535
+            | Backend::GET_DISPLAYNAME
536
+            | (($this->access->connection->ldapUserAvatarRule !== 'none') ? Backend::PROVIDE_AVATAR : 0)
537
+            | Backend::COUNT_USERS
538
+            | (((int)$this->access->connection->turnOnPasswordChange === 1)? Backend::SET_PASSWORD :0)
539
+            | $this->userPluginManager->getImplementedActions())
540
+            & $actions);
541
+    }
542
+
543
+    /**
544
+     * @return bool
545
+     */
546
+    public function hasUserListings() {
547
+        return true;
548
+    }
549
+
550
+    /**
551
+     * counts the users in LDAP
552
+     *
553
+     * @return int|bool
554
+     */
555
+    public function countUsers() {
556
+        if ($this->userPluginManager->implementsActions(Backend::COUNT_USERS)) {
557
+            return $this->userPluginManager->countUsers();
558
+        }
559
+
560
+        $filter = $this->access->getFilterForUserCount();
561
+        $cacheKey = 'countUsers-'.$filter;
562
+        if (!is_null($entries = $this->access->connection->getFromCache($cacheKey))) {
563
+            return $entries;
564
+        }
565
+        $entries = $this->access->countUsers($filter);
566
+        $this->access->connection->writeToCache($cacheKey, $entries);
567
+        return $entries;
568
+    }
569
+
570
+    /**
571
+     * Backend name to be shown in user management
572
+     * @return string the name of the backend to be shown
573
+     */
574
+    public function getBackendName() {
575
+        return 'LDAP';
576
+    }
577
+
578
+    /**
579
+     * Return access for LDAP interaction.
580
+     * @param string $uid
581
+     * @return Access instance of Access for LDAP interaction
582
+     */
583
+    public function getLDAPAccess($uid) {
584
+        return $this->access;
585
+    }
586
+
587
+    /**
588
+     * Return LDAP connection resource from a cloned connection.
589
+     * The cloned connection needs to be closed manually.
590
+     * of the current access.
591
+     * @param string $uid
592
+     * @return resource of the LDAP connection
593
+     */
594
+    public function getNewLDAPConnection($uid) {
595
+        $connection = clone $this->access->getConnection();
596
+        return $connection->getConnectionResource();
597
+    }
598
+
599
+    /**
600
+     * create new user
601
+     * @param string $username username of the new user
602
+     * @param string $password password of the new user
603
+     * @throws \UnexpectedValueException
604
+     * @return bool
605
+     */
606
+    public function createUser($username, $password) {
607
+        if ($this->userPluginManager->implementsActions(Backend::CREATE_USER)) {
608
+            if ($dn = $this->userPluginManager->createUser($username, $password)) {
609
+                if (is_string($dn)) {
610
+                    // the NC user creation work flow requires a know user id up front
611
+                    $uuid = $this->access->getUUID($dn, true);
612
+                    if (is_string($uuid)) {
613
+                        $this->access->mapAndAnnounceIfApplicable(
614
+                            $this->access->getUserMapper(),
615
+                            $dn,
616
+                            $username,
617
+                            $uuid,
618
+                            true
619
+                        );
620
+                        $this->access->cacheUserExists($username);
621
+                    } else {
622
+                        \OC::$server->getLogger()->warning(
623
+                            'Failed to map created LDAP user with userid {userid}, because UUID could not be determined',
624
+                            [
625
+                                'app' => 'user_ldap',
626
+                                'userid' => $username,
627
+                            ]
628
+                        );
629
+                    }
630
+                } else {
631
+                    throw new \UnexpectedValueException("LDAP Plugin: Method createUser changed to return the user DN instead of boolean.");
632
+                }
633
+            }
634
+            return (bool) $dn;
635
+        }
636
+        return false;
637
+    }
638 638
 }
Please login to merge, or discard this patch.
apps/user_ldap/lib/User_Proxy.php 1 patch
Indentation   +323 added lines, -323 removed lines patch added patch discarded remove patch
@@ -38,352 +38,352 @@
 block discarded – undo
38 38
 use OCP\Notification\IManager as INotificationManager;
39 39
 
40 40
 class User_Proxy extends Proxy implements \OCP\IUserBackend, \OCP\UserInterface, IUserLDAP {
41
-	private $backends = [];
42
-	/** @var User_LDAP */
43
-	private $refBackend = null;
41
+    private $backends = [];
42
+    /** @var User_LDAP */
43
+    private $refBackend = null;
44 44
 
45
-	public function __construct(
46
-		Helper $helper,
47
-		ILDAPWrapper $ldap,
48
-		IConfig $ocConfig,
49
-		INotificationManager $notificationManager,
50
-		IUserSession $userSession,
51
-		UserPluginManager $userPluginManager
52
-	) {
53
-		parent::__construct($ldap);
54
-		$serverConfigPrefixes = $helper->getServerConfigurationPrefixes(true);
55
-		foreach ($serverConfigPrefixes as $configPrefix) {
56
-			$this->backends[$configPrefix] =
57
-				new User_LDAP($this->getAccess($configPrefix), $ocConfig, $notificationManager, $userSession, $userPluginManager);
45
+    public function __construct(
46
+        Helper $helper,
47
+        ILDAPWrapper $ldap,
48
+        IConfig $ocConfig,
49
+        INotificationManager $notificationManager,
50
+        IUserSession $userSession,
51
+        UserPluginManager $userPluginManager
52
+    ) {
53
+        parent::__construct($ldap);
54
+        $serverConfigPrefixes = $helper->getServerConfigurationPrefixes(true);
55
+        foreach ($serverConfigPrefixes as $configPrefix) {
56
+            $this->backends[$configPrefix] =
57
+                new User_LDAP($this->getAccess($configPrefix), $ocConfig, $notificationManager, $userSession, $userPluginManager);
58 58
 
59
-			if (is_null($this->refBackend)) {
60
-				$this->refBackend = &$this->backends[$configPrefix];
61
-			}
62
-		}
63
-	}
59
+            if (is_null($this->refBackend)) {
60
+                $this->refBackend = &$this->backends[$configPrefix];
61
+            }
62
+        }
63
+    }
64 64
 
65
-	/**
66
-	 * Tries the backends one after the other until a positive result is returned from the specified method
67
-	 *
68
-	 * @param string $id the uid connected to the request
69
-	 * @param string $method the method of the user backend that shall be called
70
-	 * @param array $parameters an array of parameters to be passed
71
-	 * @return mixed the result of the method or false
72
-	 */
73
-	protected function walkBackends($id, $method, $parameters) {
74
-		$uid = $id;
75
-		$cacheKey = $this->getUserCacheKey($uid);
76
-		foreach ($this->backends as $configPrefix => $backend) {
77
-			$instance = $backend;
78
-			if (!method_exists($instance, $method)
79
-				&& method_exists($this->getAccess($configPrefix), $method)) {
80
-				$instance = $this->getAccess($configPrefix);
81
-			}
82
-			if ($result = call_user_func_array([$instance, $method], $parameters)) {
83
-				if (!$this->isSingleBackend()) {
84
-					$this->writeToCache($cacheKey, $configPrefix);
85
-				}
86
-				return $result;
87
-			}
88
-		}
89
-		return false;
90
-	}
65
+    /**
66
+     * Tries the backends one after the other until a positive result is returned from the specified method
67
+     *
68
+     * @param string $id the uid connected to the request
69
+     * @param string $method the method of the user backend that shall be called
70
+     * @param array $parameters an array of parameters to be passed
71
+     * @return mixed the result of the method or false
72
+     */
73
+    protected function walkBackends($id, $method, $parameters) {
74
+        $uid = $id;
75
+        $cacheKey = $this->getUserCacheKey($uid);
76
+        foreach ($this->backends as $configPrefix => $backend) {
77
+            $instance = $backend;
78
+            if (!method_exists($instance, $method)
79
+                && method_exists($this->getAccess($configPrefix), $method)) {
80
+                $instance = $this->getAccess($configPrefix);
81
+            }
82
+            if ($result = call_user_func_array([$instance, $method], $parameters)) {
83
+                if (!$this->isSingleBackend()) {
84
+                    $this->writeToCache($cacheKey, $configPrefix);
85
+                }
86
+                return $result;
87
+            }
88
+        }
89
+        return false;
90
+    }
91 91
 
92
-	/**
93
-	 * Asks the backend connected to the server that supposely takes care of the uid from the request.
94
-	 *
95
-	 * @param string $id the uid connected to the request
96
-	 * @param string $method the method of the user backend that shall be called
97
-	 * @param array $parameters an array of parameters to be passed
98
-	 * @param mixed $passOnWhen the result matches this variable
99
-	 * @return mixed the result of the method or false
100
-	 */
101
-	protected function callOnLastSeenOn($id, $method, $parameters, $passOnWhen) {
102
-		$uid = $id;
103
-		$cacheKey = $this->getUserCacheKey($uid);
104
-		$prefix = $this->getFromCache($cacheKey);
105
-		//in case the uid has been found in the past, try this stored connection first
106
-		if (!is_null($prefix)) {
107
-			if (isset($this->backends[$prefix])) {
108
-				$instance = $this->backends[$prefix];
109
-				if (!method_exists($instance, $method)
110
-					&& method_exists($this->getAccess($prefix), $method)) {
111
-					$instance = $this->getAccess($prefix);
112
-				}
113
-				$result = call_user_func_array([$instance, $method], $parameters);
114
-				if ($result === $passOnWhen) {
115
-					//not found here, reset cache to null if user vanished
116
-					//because sometimes methods return false with a reason
117
-					$userExists = call_user_func_array(
118
-						[$this->backends[$prefix], 'userExistsOnLDAP'],
119
-						[$uid]
120
-					);
121
-					if (!$userExists) {
122
-						$this->writeToCache($cacheKey, null);
123
-					}
124
-				}
125
-				return $result;
126
-			}
127
-		}
128
-		return false;
129
-	}
92
+    /**
93
+     * Asks the backend connected to the server that supposely takes care of the uid from the request.
94
+     *
95
+     * @param string $id the uid connected to the request
96
+     * @param string $method the method of the user backend that shall be called
97
+     * @param array $parameters an array of parameters to be passed
98
+     * @param mixed $passOnWhen the result matches this variable
99
+     * @return mixed the result of the method or false
100
+     */
101
+    protected function callOnLastSeenOn($id, $method, $parameters, $passOnWhen) {
102
+        $uid = $id;
103
+        $cacheKey = $this->getUserCacheKey($uid);
104
+        $prefix = $this->getFromCache($cacheKey);
105
+        //in case the uid has been found in the past, try this stored connection first
106
+        if (!is_null($prefix)) {
107
+            if (isset($this->backends[$prefix])) {
108
+                $instance = $this->backends[$prefix];
109
+                if (!method_exists($instance, $method)
110
+                    && method_exists($this->getAccess($prefix), $method)) {
111
+                    $instance = $this->getAccess($prefix);
112
+                }
113
+                $result = call_user_func_array([$instance, $method], $parameters);
114
+                if ($result === $passOnWhen) {
115
+                    //not found here, reset cache to null if user vanished
116
+                    //because sometimes methods return false with a reason
117
+                    $userExists = call_user_func_array(
118
+                        [$this->backends[$prefix], 'userExistsOnLDAP'],
119
+                        [$uid]
120
+                    );
121
+                    if (!$userExists) {
122
+                        $this->writeToCache($cacheKey, null);
123
+                    }
124
+                }
125
+                return $result;
126
+            }
127
+        }
128
+        return false;
129
+    }
130 130
 
131
-	protected function activeBackends(): int {
132
-		return count($this->backends);
133
-	}
131
+    protected function activeBackends(): int {
132
+        return count($this->backends);
133
+    }
134 134
 
135
-	/**
136
-	 * Check if backend implements actions
137
-	 *
138
-	 * @param int $actions bitwise-or'ed actions
139
-	 * @return boolean
140
-	 *
141
-	 * Returns the supported actions as int to be
142
-	 * compared with \OC\User\Backend::CREATE_USER etc.
143
-	 */
144
-	public function implementsActions($actions) {
145
-		//it's the same across all our user backends obviously
146
-		return $this->refBackend->implementsActions($actions);
147
-	}
135
+    /**
136
+     * Check if backend implements actions
137
+     *
138
+     * @param int $actions bitwise-or'ed actions
139
+     * @return boolean
140
+     *
141
+     * Returns the supported actions as int to be
142
+     * compared with \OC\User\Backend::CREATE_USER etc.
143
+     */
144
+    public function implementsActions($actions) {
145
+        //it's the same across all our user backends obviously
146
+        return $this->refBackend->implementsActions($actions);
147
+    }
148 148
 
149
-	/**
150
-	 * Backend name to be shown in user management
151
-	 *
152
-	 * @return string the name of the backend to be shown
153
-	 */
154
-	public function getBackendName() {
155
-		return $this->refBackend->getBackendName();
156
-	}
149
+    /**
150
+     * Backend name to be shown in user management
151
+     *
152
+     * @return string the name of the backend to be shown
153
+     */
154
+    public function getBackendName() {
155
+        return $this->refBackend->getBackendName();
156
+    }
157 157
 
158
-	/**
159
-	 * Get a list of all users
160
-	 *
161
-	 * @param string $search
162
-	 * @param null|int $limit
163
-	 * @param null|int $offset
164
-	 * @return string[] an array of all uids
165
-	 */
166
-	public function getUsers($search = '', $limit = 10, $offset = 0) {
167
-		//we do it just as the /OC_User implementation: do not play around with limit and offset but ask all backends
168
-		$users = [];
169
-		foreach ($this->backends as $backend) {
170
-			$backendUsers = $backend->getUsers($search, $limit, $offset);
171
-			if (is_array($backendUsers)) {
172
-				$users = array_merge($users, $backendUsers);
173
-			}
174
-		}
175
-		return $users;
176
-	}
158
+    /**
159
+     * Get a list of all users
160
+     *
161
+     * @param string $search
162
+     * @param null|int $limit
163
+     * @param null|int $offset
164
+     * @return string[] an array of all uids
165
+     */
166
+    public function getUsers($search = '', $limit = 10, $offset = 0) {
167
+        //we do it just as the /OC_User implementation: do not play around with limit and offset but ask all backends
168
+        $users = [];
169
+        foreach ($this->backends as $backend) {
170
+            $backendUsers = $backend->getUsers($search, $limit, $offset);
171
+            if (is_array($backendUsers)) {
172
+                $users = array_merge($users, $backendUsers);
173
+            }
174
+        }
175
+        return $users;
176
+    }
177 177
 
178
-	/**
179
-	 * check if a user exists
180
-	 *
181
-	 * @param string $uid the username
182
-	 * @return boolean
183
-	 */
184
-	public function userExists($uid) {
185
-		$existsOnLDAP = false;
186
-		$existsLocally = $this->handleRequest($uid, 'userExists', [$uid]);
187
-		if ($existsLocally) {
188
-			$existsOnLDAP = $this->userExistsOnLDAP($uid);
189
-		}
190
-		if ($existsLocally && !$existsOnLDAP) {
191
-			try {
192
-				$user = $this->getLDAPAccess($uid)->userManager->get($uid);
193
-				if ($user instanceof User) {
194
-					$user->markUser();
195
-				}
196
-			} catch (\Exception $e) {
197
-				// ignore
198
-			}
199
-		}
200
-		return $existsLocally;
201
-	}
178
+    /**
179
+     * check if a user exists
180
+     *
181
+     * @param string $uid the username
182
+     * @return boolean
183
+     */
184
+    public function userExists($uid) {
185
+        $existsOnLDAP = false;
186
+        $existsLocally = $this->handleRequest($uid, 'userExists', [$uid]);
187
+        if ($existsLocally) {
188
+            $existsOnLDAP = $this->userExistsOnLDAP($uid);
189
+        }
190
+        if ($existsLocally && !$existsOnLDAP) {
191
+            try {
192
+                $user = $this->getLDAPAccess($uid)->userManager->get($uid);
193
+                if ($user instanceof User) {
194
+                    $user->markUser();
195
+                }
196
+            } catch (\Exception $e) {
197
+                // ignore
198
+            }
199
+        }
200
+        return $existsLocally;
201
+    }
202 202
 
203
-	/**
204
-	 * check if a user exists on LDAP
205
-	 *
206
-	 * @param string|\OCA\User_LDAP\User\User $user either the Nextcloud user
207
-	 * name or an instance of that user
208
-	 * @return boolean
209
-	 */
210
-	public function userExistsOnLDAP($user) {
211
-		$id = ($user instanceof User) ? $user->getUsername() : $user;
212
-		return $this->handleRequest($id, 'userExistsOnLDAP', [$user]);
213
-	}
203
+    /**
204
+     * check if a user exists on LDAP
205
+     *
206
+     * @param string|\OCA\User_LDAP\User\User $user either the Nextcloud user
207
+     * name or an instance of that user
208
+     * @return boolean
209
+     */
210
+    public function userExistsOnLDAP($user) {
211
+        $id = ($user instanceof User) ? $user->getUsername() : $user;
212
+        return $this->handleRequest($id, 'userExistsOnLDAP', [$user]);
213
+    }
214 214
 
215
-	/**
216
-	 * Check if the password is correct
217
-	 *
218
-	 * @param string $uid The username
219
-	 * @param string $password The password
220
-	 * @return bool
221
-	 *
222
-	 * Check if the password is correct without logging in the user
223
-	 */
224
-	public function checkPassword($uid, $password) {
225
-		return $this->handleRequest($uid, 'checkPassword', [$uid, $password]);
226
-	}
215
+    /**
216
+     * Check if the password is correct
217
+     *
218
+     * @param string $uid The username
219
+     * @param string $password The password
220
+     * @return bool
221
+     *
222
+     * Check if the password is correct without logging in the user
223
+     */
224
+    public function checkPassword($uid, $password) {
225
+        return $this->handleRequest($uid, 'checkPassword', [$uid, $password]);
226
+    }
227 227
 
228
-	/**
229
-	 * returns the username for the given login name, if available
230
-	 *
231
-	 * @param string $loginName
232
-	 * @return string|false
233
-	 */
234
-	public function loginName2UserName($loginName) {
235
-		$id = 'LOGINNAME,' . $loginName;
236
-		return $this->handleRequest($id, 'loginName2UserName', [$loginName]);
237
-	}
228
+    /**
229
+     * returns the username for the given login name, if available
230
+     *
231
+     * @param string $loginName
232
+     * @return string|false
233
+     */
234
+    public function loginName2UserName($loginName) {
235
+        $id = 'LOGINNAME,' . $loginName;
236
+        return $this->handleRequest($id, 'loginName2UserName', [$loginName]);
237
+    }
238 238
 
239
-	/**
240
-	 * returns the username for the given LDAP DN, if available
241
-	 *
242
-	 * @param string $dn
243
-	 * @return string|false with the username
244
-	 */
245
-	public function dn2UserName($dn) {
246
-		$id = 'DN,' . $dn;
247
-		return $this->handleRequest($id, 'dn2UserName', [$dn]);
248
-	}
239
+    /**
240
+     * returns the username for the given LDAP DN, if available
241
+     *
242
+     * @param string $dn
243
+     * @return string|false with the username
244
+     */
245
+    public function dn2UserName($dn) {
246
+        $id = 'DN,' . $dn;
247
+        return $this->handleRequest($id, 'dn2UserName', [$dn]);
248
+    }
249 249
 
250
-	/**
251
-	 * get the user's home directory
252
-	 *
253
-	 * @param string $uid the username
254
-	 * @return boolean
255
-	 */
256
-	public function getHome($uid) {
257
-		return $this->handleRequest($uid, 'getHome', [$uid]);
258
-	}
250
+    /**
251
+     * get the user's home directory
252
+     *
253
+     * @param string $uid the username
254
+     * @return boolean
255
+     */
256
+    public function getHome($uid) {
257
+        return $this->handleRequest($uid, 'getHome', [$uid]);
258
+    }
259 259
 
260
-	/**
261
-	 * get display name of the user
262
-	 *
263
-	 * @param string $uid user ID of the user
264
-	 * @return string display name
265
-	 */
266
-	public function getDisplayName($uid) {
267
-		return $this->handleRequest($uid, 'getDisplayName', [$uid]);
268
-	}
260
+    /**
261
+     * get display name of the user
262
+     *
263
+     * @param string $uid user ID of the user
264
+     * @return string display name
265
+     */
266
+    public function getDisplayName($uid) {
267
+        return $this->handleRequest($uid, 'getDisplayName', [$uid]);
268
+    }
269 269
 
270
-	/**
271
-	 * set display name of the user
272
-	 *
273
-	 * @param string $uid user ID of the user
274
-	 * @param string $displayName new display name
275
-	 * @return string display name
276
-	 */
277
-	public function setDisplayName($uid, $displayName) {
278
-		return $this->handleRequest($uid, 'setDisplayName', [$uid, $displayName]);
279
-	}
270
+    /**
271
+     * set display name of the user
272
+     *
273
+     * @param string $uid user ID of the user
274
+     * @param string $displayName new display name
275
+     * @return string display name
276
+     */
277
+    public function setDisplayName($uid, $displayName) {
278
+        return $this->handleRequest($uid, 'setDisplayName', [$uid, $displayName]);
279
+    }
280 280
 
281
-	/**
282
-	 * checks whether the user is allowed to change his avatar in Nextcloud
283
-	 *
284
-	 * @param string $uid the Nextcloud user name
285
-	 * @return boolean either the user can or cannot
286
-	 */
287
-	public function canChangeAvatar($uid) {
288
-		return $this->handleRequest($uid, 'canChangeAvatar', [$uid], true);
289
-	}
281
+    /**
282
+     * checks whether the user is allowed to change his avatar in Nextcloud
283
+     *
284
+     * @param string $uid the Nextcloud user name
285
+     * @return boolean either the user can or cannot
286
+     */
287
+    public function canChangeAvatar($uid) {
288
+        return $this->handleRequest($uid, 'canChangeAvatar', [$uid], true);
289
+    }
290 290
 
291
-	/**
292
-	 * Get a list of all display names and user ids.
293
-	 *
294
-	 * @param string $search
295
-	 * @param int|null $limit
296
-	 * @param int|null $offset
297
-	 * @return array an array of all displayNames (value) and the corresponding uids (key)
298
-	 */
299
-	public function getDisplayNames($search = '', $limit = null, $offset = null) {
300
-		//we do it just as the /OC_User implementation: do not play around with limit and offset but ask all backends
301
-		$users = [];
302
-		foreach ($this->backends as $backend) {
303
-			$backendUsers = $backend->getDisplayNames($search, $limit, $offset);
304
-			if (is_array($backendUsers)) {
305
-				$users = $users + $backendUsers;
306
-			}
307
-		}
308
-		return $users;
309
-	}
291
+    /**
292
+     * Get a list of all display names and user ids.
293
+     *
294
+     * @param string $search
295
+     * @param int|null $limit
296
+     * @param int|null $offset
297
+     * @return array an array of all displayNames (value) and the corresponding uids (key)
298
+     */
299
+    public function getDisplayNames($search = '', $limit = null, $offset = null) {
300
+        //we do it just as the /OC_User implementation: do not play around with limit and offset but ask all backends
301
+        $users = [];
302
+        foreach ($this->backends as $backend) {
303
+            $backendUsers = $backend->getDisplayNames($search, $limit, $offset);
304
+            if (is_array($backendUsers)) {
305
+                $users = $users + $backendUsers;
306
+            }
307
+        }
308
+        return $users;
309
+    }
310 310
 
311
-	/**
312
-	 * delete a user
313
-	 *
314
-	 * @param string $uid The username of the user to delete
315
-	 * @return bool
316
-	 *
317
-	 * Deletes a user
318
-	 */
319
-	public function deleteUser($uid) {
320
-		return $this->handleRequest($uid, 'deleteUser', [$uid]);
321
-	}
311
+    /**
312
+     * delete a user
313
+     *
314
+     * @param string $uid The username of the user to delete
315
+     * @return bool
316
+     *
317
+     * Deletes a user
318
+     */
319
+    public function deleteUser($uid) {
320
+        return $this->handleRequest($uid, 'deleteUser', [$uid]);
321
+    }
322 322
 
323
-	/**
324
-	 * Set password
325
-	 *
326
-	 * @param string $uid The username
327
-	 * @param string $password The new password
328
-	 * @return bool
329
-	 *
330
-	 */
331
-	public function setPassword($uid, $password) {
332
-		return $this->handleRequest($uid, 'setPassword', [$uid, $password]);
333
-	}
323
+    /**
324
+     * Set password
325
+     *
326
+     * @param string $uid The username
327
+     * @param string $password The new password
328
+     * @return bool
329
+     *
330
+     */
331
+    public function setPassword($uid, $password) {
332
+        return $this->handleRequest($uid, 'setPassword', [$uid, $password]);
333
+    }
334 334
 
335
-	/**
336
-	 * @return bool
337
-	 */
338
-	public function hasUserListings() {
339
-		return $this->refBackend->hasUserListings();
340
-	}
335
+    /**
336
+     * @return bool
337
+     */
338
+    public function hasUserListings() {
339
+        return $this->refBackend->hasUserListings();
340
+    }
341 341
 
342
-	/**
343
-	 * Count the number of users
344
-	 *
345
-	 * @return int|bool
346
-	 */
347
-	public function countUsers() {
348
-		$users = false;
349
-		foreach ($this->backends as $backend) {
350
-			$backendUsers = $backend->countUsers();
351
-			if ($backendUsers !== false) {
352
-				$users += $backendUsers;
353
-			}
354
-		}
355
-		return $users;
356
-	}
342
+    /**
343
+     * Count the number of users
344
+     *
345
+     * @return int|bool
346
+     */
347
+    public function countUsers() {
348
+        $users = false;
349
+        foreach ($this->backends as $backend) {
350
+            $backendUsers = $backend->countUsers();
351
+            if ($backendUsers !== false) {
352
+                $users += $backendUsers;
353
+            }
354
+        }
355
+        return $users;
356
+    }
357 357
 
358
-	/**
359
-	 * Return access for LDAP interaction.
360
-	 *
361
-	 * @param string $uid
362
-	 * @return Access instance of Access for LDAP interaction
363
-	 */
364
-	public function getLDAPAccess($uid) {
365
-		return $this->handleRequest($uid, 'getLDAPAccess', [$uid]);
366
-	}
358
+    /**
359
+     * Return access for LDAP interaction.
360
+     *
361
+     * @param string $uid
362
+     * @return Access instance of Access for LDAP interaction
363
+     */
364
+    public function getLDAPAccess($uid) {
365
+        return $this->handleRequest($uid, 'getLDAPAccess', [$uid]);
366
+    }
367 367
 
368
-	/**
369
-	 * Return a new LDAP connection for the specified user.
370
-	 * The connection needs to be closed manually.
371
-	 *
372
-	 * @param string $uid
373
-	 * @return resource of the LDAP connection
374
-	 */
375
-	public function getNewLDAPConnection($uid) {
376
-		return $this->handleRequest($uid, 'getNewLDAPConnection', [$uid]);
377
-	}
368
+    /**
369
+     * Return a new LDAP connection for the specified user.
370
+     * The connection needs to be closed manually.
371
+     *
372
+     * @param string $uid
373
+     * @return resource of the LDAP connection
374
+     */
375
+    public function getNewLDAPConnection($uid) {
376
+        return $this->handleRequest($uid, 'getNewLDAPConnection', [$uid]);
377
+    }
378 378
 
379
-	/**
380
-	 * Creates a new user in LDAP
381
-	 *
382
-	 * @param $username
383
-	 * @param $password
384
-	 * @return bool
385
-	 */
386
-	public function createUser($username, $password) {
387
-		return $this->handleRequest($username, 'createUser', [$username, $password]);
388
-	}
379
+    /**
380
+     * Creates a new user in LDAP
381
+     *
382
+     * @param $username
383
+     * @param $password
384
+     * @return bool
385
+     */
386
+    public function createUser($username, $password) {
387
+        return $this->handleRequest($username, 'createUser', [$username, $password]);
388
+    }
389 389
 }
Please login to merge, or discard this patch.
core/Migrations/Version21000Date20210309185127.php 1 patch
Indentation   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -31,22 +31,22 @@
 block discarded – undo
31 31
 use OCP\Migration\SimpleMigrationStep;
32 32
 
33 33
 class Version21000Date20210309185127 extends SimpleMigrationStep {
34
-	/**
35
-	 * @param IOutput $output
36
-	 * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
37
-	 * @param array $options
38
-	 * @return null|ISchemaWrapper
39
-	 */
40
-	public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
41
-		/** @var ISchemaWrapper $schema */
42
-		$schema = $schemaClosure();
34
+    /**
35
+     * @param IOutput $output
36
+     * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
37
+     * @param array $options
38
+     * @return null|ISchemaWrapper
39
+     */
40
+    public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
41
+        /** @var ISchemaWrapper $schema */
42
+        $schema = $schemaClosure();
43 43
 
44
-		$table = $schema->getTable('known_users');
45
-		if (!$table->hasIndex('ku_known_user')) {
46
-			$table->addIndex(['known_user'], 'ku_known_user');
47
-			return $schema;
48
-		}
44
+        $table = $schema->getTable('known_users');
45
+        if (!$table->hasIndex('ku_known_user')) {
46
+            $table->addIndex(['known_user'], 'ku_known_user');
47
+            return $schema;
48
+        }
49 49
 
50
-		return null;
51
-	}
50
+        return null;
51
+    }
52 52
 }
Please login to merge, or discard this patch.
lib/public/User/Backend/ISearchKnownUsersBackend.php 1 patch
Indentation   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -31,13 +31,13 @@
 block discarded – undo
31 31
  */
32 32
 interface ISearchKnownUsersBackend {
33 33
 
34
-	/**
35
-	 * @param string $searcher
36
-	 * @param string $pattern
37
-	 * @param int|null $limit
38
-	 * @param int|null $offset
39
-	 * @return array
40
-	 * @since 21.0.1
41
-	 */
42
-	public function searchKnownUsersByDisplayName(string $searcher, string $pattern, ?int $limit = null, ?int $offset = null): array;
34
+    /**
35
+     * @param string $searcher
36
+     * @param string $pattern
37
+     * @param int|null $limit
38
+     * @param int|null $offset
39
+     * @return array
40
+     * @since 21.0.1
41
+     */
42
+    public function searchKnownUsersByDisplayName(string $searcher, string $pattern, ?int $limit = null, ?int $offset = null): array;
43 43
 }
Please login to merge, or discard this patch.
lib/public/User/Backend/IGetRealUIDBackend.php 1 patch
Indentation   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -31,16 +31,16 @@
 block discarded – undo
31 31
  */
32 32
 interface IGetRealUIDBackend {
33 33
 
34
-	/**
35
-	 * Some backends accept different UIDs than what is the internal UID to be used.
36
-	 * For example the database backend accepts different cased UIDs in all the functions
37
-	 * but the internal UID that is to be used should be correctly cased.
38
-	 *
39
-	 * This little function makes sure that the used UID will be correct hen using the user object
40
-	 *
41
-	 * @since 17.0.0
42
-	 * @param string $uid
43
-	 * @return string
44
-	 */
45
-	public function getRealUID(string $uid): string;
34
+    /**
35
+     * Some backends accept different UIDs than what is the internal UID to be used.
36
+     * For example the database backend accepts different cased UIDs in all the functions
37
+     * but the internal UID that is to be used should be correctly cased.
38
+     *
39
+     * This little function makes sure that the used UID will be correct hen using the user object
40
+     *
41
+     * @since 17.0.0
42
+     * @param string $uid
43
+     * @return string
44
+     */
45
+    public function getRealUID(string $uid): string;
46 46
 }
Please login to merge, or discard this patch.
lib/public/IUserManager.php 1 patch
Indentation   +155 added lines, -155 removed lines patch added patch discarded remove patch
@@ -47,159 +47,159 @@
 block discarded – undo
47 47
  * @since 8.0.0
48 48
  */
49 49
 interface IUserManager {
50
-	/**
51
-	 * register a user backend
52
-	 *
53
-	 * @param \OCP\UserInterface $backend
54
-	 * @since 8.0.0
55
-	 */
56
-	public function registerBackend($backend);
57
-
58
-	/**
59
-	 * Get the active backends
60
-	 * @return \OCP\UserInterface[]
61
-	 * @since 8.0.0
62
-	 */
63
-	public function getBackends();
64
-
65
-	/**
66
-	 * remove a user backend
67
-	 *
68
-	 * @param \OCP\UserInterface $backend
69
-	 * @since 8.0.0
70
-	 */
71
-	public function removeBackend($backend);
72
-
73
-	/**
74
-	 * remove all user backends
75
-	 * @since 8.0.0
76
-	 */
77
-	public function clearBackends() ;
78
-
79
-	/**
80
-	 * get a user by user id
81
-	 *
82
-	 * @param string $uid
83
-	 * @return \OCP\IUser|null Either the user or null if the specified user does not exist
84
-	 * @since 8.0.0
85
-	 */
86
-	public function get($uid);
87
-
88
-	/**
89
-	 * check if a user exists
90
-	 *
91
-	 * @param string $uid
92
-	 * @return bool
93
-	 * @since 8.0.0
94
-	 */
95
-	public function userExists($uid);
96
-
97
-	/**
98
-	 * Check if the password is valid for the user
99
-	 *
100
-	 * @param string $loginName
101
-	 * @param string $password
102
-	 * @return mixed the User object on success, false otherwise
103
-	 * @since 8.0.0
104
-	 */
105
-	public function checkPassword($loginName, $password);
106
-
107
-	/**
108
-	 * search by user id
109
-	 *
110
-	 * @param string $pattern
111
-	 * @param int $limit
112
-	 * @param int $offset
113
-	 * @return \OCP\IUser[]
114
-	 * @since 8.0.0
115
-	 */
116
-	public function search($pattern, $limit = null, $offset = null);
117
-
118
-	/**
119
-	 * search by displayName
120
-	 *
121
-	 * @param string $pattern
122
-	 * @param int $limit
123
-	 * @param int $offset
124
-	 * @return \OCP\IUser[]
125
-	 * @since 8.0.0
126
-	 */
127
-	public function searchDisplayName($pattern, $limit = null, $offset = null);
128
-
129
-	/**
130
-	 * Search known users (from phonebook sync) by displayName
131
-	 *
132
-	 * @param string $searcher
133
-	 * @param string $pattern
134
-	 * @param int|null $limit
135
-	 * @param int|null $offset
136
-	 * @return IUser[]
137
-	 * @since 21.0.1
138
-	 */
139
-	public function searchKnownUsersByDisplayName(string $searcher, string $pattern, ?int $limit = null, ?int $offset = null): array;
140
-
141
-	/**
142
-	 * @param string $uid
143
-	 * @param string $password
144
-	 * @throws \InvalidArgumentException
145
-	 * @return bool|\OCP\IUser the created user or false
146
-	 * @since 8.0.0
147
-	 */
148
-	public function createUser($uid, $password);
149
-
150
-	/**
151
-	 * @param string $uid
152
-	 * @param string $password
153
-	 * @param UserInterface $backend
154
-	 * @return IUser|null
155
-	 * @throws \InvalidArgumentException
156
-	 * @since 12.0.0
157
-	 */
158
-	public function createUserFromBackend($uid, $password, UserInterface $backend);
159
-
160
-	/**
161
-	 * returns how many users per backend exist (if supported by backend)
162
-	 *
163
-	 * @return array an array of backend class as key and count number as value
164
-	 * @since 8.0.0
165
-	 */
166
-	public function countUsers();
167
-
168
-	/**
169
-	 * @param \Closure $callback
170
-	 * @psalm-param \Closure(\OCP\IUser):void $callback
171
-	 * @param string $search
172
-	 * @since 9.0.0
173
-	 */
174
-	public function callForAllUsers(\Closure $callback, $search = '');
175
-
176
-	/**
177
-	 * returns how many users have logged in once
178
-	 *
179
-	 * @return int
180
-	 * @since 11.0.0
181
-	 */
182
-	public function countDisabledUsers();
183
-
184
-	/**
185
-	 * returns how many users have logged in once
186
-	 *
187
-	 * @return int
188
-	 * @since 11.0.0
189
-	 */
190
-	public function countSeenUsers();
191
-
192
-	/**
193
-	 * @param \Closure $callback
194
-	 * @psalm-param \Closure(\OCP\IUser):?bool $callback
195
-	 * @since 11.0.0
196
-	 */
197
-	public function callForSeenUsers(\Closure $callback);
198
-
199
-	/**
200
-	 * @param string $email
201
-	 * @return IUser[]
202
-	 * @since 9.1.0
203
-	 */
204
-	public function getByEmail($email);
50
+    /**
51
+     * register a user backend
52
+     *
53
+     * @param \OCP\UserInterface $backend
54
+     * @since 8.0.0
55
+     */
56
+    public function registerBackend($backend);
57
+
58
+    /**
59
+     * Get the active backends
60
+     * @return \OCP\UserInterface[]
61
+     * @since 8.0.0
62
+     */
63
+    public function getBackends();
64
+
65
+    /**
66
+     * remove a user backend
67
+     *
68
+     * @param \OCP\UserInterface $backend
69
+     * @since 8.0.0
70
+     */
71
+    public function removeBackend($backend);
72
+
73
+    /**
74
+     * remove all user backends
75
+     * @since 8.0.0
76
+     */
77
+    public function clearBackends() ;
78
+
79
+    /**
80
+     * get a user by user id
81
+     *
82
+     * @param string $uid
83
+     * @return \OCP\IUser|null Either the user or null if the specified user does not exist
84
+     * @since 8.0.0
85
+     */
86
+    public function get($uid);
87
+
88
+    /**
89
+     * check if a user exists
90
+     *
91
+     * @param string $uid
92
+     * @return bool
93
+     * @since 8.0.0
94
+     */
95
+    public function userExists($uid);
96
+
97
+    /**
98
+     * Check if the password is valid for the user
99
+     *
100
+     * @param string $loginName
101
+     * @param string $password
102
+     * @return mixed the User object on success, false otherwise
103
+     * @since 8.0.0
104
+     */
105
+    public function checkPassword($loginName, $password);
106
+
107
+    /**
108
+     * search by user id
109
+     *
110
+     * @param string $pattern
111
+     * @param int $limit
112
+     * @param int $offset
113
+     * @return \OCP\IUser[]
114
+     * @since 8.0.0
115
+     */
116
+    public function search($pattern, $limit = null, $offset = null);
117
+
118
+    /**
119
+     * search by displayName
120
+     *
121
+     * @param string $pattern
122
+     * @param int $limit
123
+     * @param int $offset
124
+     * @return \OCP\IUser[]
125
+     * @since 8.0.0
126
+     */
127
+    public function searchDisplayName($pattern, $limit = null, $offset = null);
128
+
129
+    /**
130
+     * Search known users (from phonebook sync) by displayName
131
+     *
132
+     * @param string $searcher
133
+     * @param string $pattern
134
+     * @param int|null $limit
135
+     * @param int|null $offset
136
+     * @return IUser[]
137
+     * @since 21.0.1
138
+     */
139
+    public function searchKnownUsersByDisplayName(string $searcher, string $pattern, ?int $limit = null, ?int $offset = null): array;
140
+
141
+    /**
142
+     * @param string $uid
143
+     * @param string $password
144
+     * @throws \InvalidArgumentException
145
+     * @return bool|\OCP\IUser the created user or false
146
+     * @since 8.0.0
147
+     */
148
+    public function createUser($uid, $password);
149
+
150
+    /**
151
+     * @param string $uid
152
+     * @param string $password
153
+     * @param UserInterface $backend
154
+     * @return IUser|null
155
+     * @throws \InvalidArgumentException
156
+     * @since 12.0.0
157
+     */
158
+    public function createUserFromBackend($uid, $password, UserInterface $backend);
159
+
160
+    /**
161
+     * returns how many users per backend exist (if supported by backend)
162
+     *
163
+     * @return array an array of backend class as key and count number as value
164
+     * @since 8.0.0
165
+     */
166
+    public function countUsers();
167
+
168
+    /**
169
+     * @param \Closure $callback
170
+     * @psalm-param \Closure(\OCP\IUser):void $callback
171
+     * @param string $search
172
+     * @since 9.0.0
173
+     */
174
+    public function callForAllUsers(\Closure $callback, $search = '');
175
+
176
+    /**
177
+     * returns how many users have logged in once
178
+     *
179
+     * @return int
180
+     * @since 11.0.0
181
+     */
182
+    public function countDisabledUsers();
183
+
184
+    /**
185
+     * returns how many users have logged in once
186
+     *
187
+     * @return int
188
+     * @since 11.0.0
189
+     */
190
+    public function countSeenUsers();
191
+
192
+    /**
193
+     * @param \Closure $callback
194
+     * @psalm-param \Closure(\OCP\IUser):?bool $callback
195
+     * @since 11.0.0
196
+     */
197
+    public function callForSeenUsers(\Closure $callback);
198
+
199
+    /**
200
+     * @param string $email
201
+     * @return IUser[]
202
+     * @since 9.1.0
203
+     */
204
+    public function getByEmail($email);
205 205
 }
Please login to merge, or discard this patch.
lib/public/UserInterface.php 1 patch
Indentation   +58 added lines, -58 removed lines patch added patch discarded remove patch
@@ -41,68 +41,68 @@
 block discarded – undo
41 41
  */
42 42
 interface UserInterface {
43 43
 
44
-	/**
45
-	 * Check if backend implements actions
46
-	 * @param int $actions bitwise-or'ed actions
47
-	 * @return boolean
48
-	 *
49
-	 * Returns the supported actions as int to be
50
-	 * compared with \OC\User\Backend::CREATE_USER etc.
51
-	 * @since 4.5.0
52
-	 * @deprecated 14.0.0 Switch to the interfaces from OCP\User\Backend
53
-	 */
54
-	public function implementsActions($actions);
44
+    /**
45
+     * Check if backend implements actions
46
+     * @param int $actions bitwise-or'ed actions
47
+     * @return boolean
48
+     *
49
+     * Returns the supported actions as int to be
50
+     * compared with \OC\User\Backend::CREATE_USER etc.
51
+     * @since 4.5.0
52
+     * @deprecated 14.0.0 Switch to the interfaces from OCP\User\Backend
53
+     */
54
+    public function implementsActions($actions);
55 55
 
56
-	/**
57
-	 * delete a user
58
-	 * @param string $uid The username of the user to delete
59
-	 * @return bool
60
-	 * @since 4.5.0
61
-	 */
62
-	public function deleteUser($uid);
56
+    /**
57
+     * delete a user
58
+     * @param string $uid The username of the user to delete
59
+     * @return bool
60
+     * @since 4.5.0
61
+     */
62
+    public function deleteUser($uid);
63 63
 
64
-	/**
65
-	 * Get a list of all users
66
-	 *
67
-	 * @param string $search
68
-	 * @param null|int $limit
69
-	 * @param null|int $offset
70
-	 * @return string[] an array of all uids
71
-	 * @since 4.5.0
72
-	 */
73
-	public function getUsers($search = '', $limit = null, $offset = null);
64
+    /**
65
+     * Get a list of all users
66
+     *
67
+     * @param string $search
68
+     * @param null|int $limit
69
+     * @param null|int $offset
70
+     * @return string[] an array of all uids
71
+     * @since 4.5.0
72
+     */
73
+    public function getUsers($search = '', $limit = null, $offset = null);
74 74
 
75
-	/**
76
-	 * check if a user exists
77
-	 * @param string $uid the username
78
-	 * @return boolean
79
-	 * @since 4.5.0
80
-	 */
81
-	public function userExists($uid);
75
+    /**
76
+     * check if a user exists
77
+     * @param string $uid the username
78
+     * @return boolean
79
+     * @since 4.5.0
80
+     */
81
+    public function userExists($uid);
82 82
 
83
-	/**
84
-	 * get display name of the user
85
-	 * @param string $uid user ID of the user
86
-	 * @return string display name
87
-	 * @since 4.5.0
88
-	 */
89
-	public function getDisplayName($uid);
83
+    /**
84
+     * get display name of the user
85
+     * @param string $uid user ID of the user
86
+     * @return string display name
87
+     * @since 4.5.0
88
+     */
89
+    public function getDisplayName($uid);
90 90
 
91
-	/**
92
-	 * Get a list of all display names and user ids.
93
-	 *
94
-	 * @param string $search
95
-	 * @param int|null $limit
96
-	 * @param int|null $offset
97
-	 * @return array an array of all displayNames (value) and the corresponding uids (key)
98
-	 * @since 4.5.0
99
-	 */
100
-	public function getDisplayNames($search = '', $limit = null, $offset = null);
91
+    /**
92
+     * Get a list of all display names and user ids.
93
+     *
94
+     * @param string $search
95
+     * @param int|null $limit
96
+     * @param int|null $offset
97
+     * @return array an array of all displayNames (value) and the corresponding uids (key)
98
+     * @since 4.5.0
99
+     */
100
+    public function getDisplayNames($search = '', $limit = null, $offset = null);
101 101
 
102
-	/**
103
-	 * Check if a user list is available or not
104
-	 * @return boolean if users can be listed or not
105
-	 * @since 4.5.0
106
-	 */
107
-	public function hasUserListings();
102
+    /**
103
+     * Check if a user list is available or not
104
+     * @return boolean if users can be listed or not
105
+     * @since 4.5.0
106
+     */
107
+    public function hasUserListings();
108 108
 }
Please login to merge, or discard this patch.
lib/private/User/Database.php 2 patches
Indentation   +459 added lines, -459 removed lines patch added patch discarded remove patch
@@ -78,463 +78,463 @@
 block discarded – undo
78 78
  * Class for user management in a SQL Database (e.g. MySQL, SQLite)
79 79
  */
80 80
 class Database extends ABackend implements
81
-	ICreateUserBackend,
82
-			   ISetPasswordBackend,
83
-			   ISetDisplayNameBackend,
84
-			   IGetDisplayNameBackend,
85
-			   ICheckPasswordBackend,
86
-			   IGetHomeBackend,
87
-			   ICountUsersBackend,
88
-			   ISearchKnownUsersBackend,
89
-			   IGetRealUIDBackend {
90
-	/** @var CappedMemoryCache */
91
-	private $cache;
92
-
93
-	/** @var IEventDispatcher */
94
-	private $eventDispatcher;
95
-
96
-	/** @var IDBConnection */
97
-	private $dbConn;
98
-
99
-	/** @var string */
100
-	private $table;
101
-
102
-	/**
103
-	 * \OC\User\Database constructor.
104
-	 *
105
-	 * @param IEventDispatcher $eventDispatcher
106
-	 * @param string $table
107
-	 */
108
-	public function __construct($eventDispatcher = null, $table = 'users') {
109
-		$this->cache = new CappedMemoryCache();
110
-		$this->table = $table;
111
-		$this->eventDispatcher = $eventDispatcher ? $eventDispatcher : \OC::$server->query(IEventDispatcher::class);
112
-	}
113
-
114
-	/**
115
-	 * FIXME: This function should not be required!
116
-	 */
117
-	private function fixDI() {
118
-		if ($this->dbConn === null) {
119
-			$this->dbConn = \OC::$server->getDatabaseConnection();
120
-		}
121
-	}
122
-
123
-	/**
124
-	 * Create a new user
125
-	 *
126
-	 * @param string $uid The username of the user to create
127
-	 * @param string $password The password of the new user
128
-	 * @return bool
129
-	 *
130
-	 * Creates a new user. Basic checking of username is done in OC_User
131
-	 * itself, not in its subclasses.
132
-	 */
133
-	public function createUser(string $uid, string $password): bool {
134
-		$this->fixDI();
135
-
136
-		if (!$this->userExists($uid)) {
137
-			$this->eventDispatcher->dispatchTyped(new ValidatePasswordPolicyEvent($password));
138
-
139
-			$qb = $this->dbConn->getQueryBuilder();
140
-			$qb->insert($this->table)
141
-				->values([
142
-					'uid' => $qb->createNamedParameter($uid),
143
-					'password' => $qb->createNamedParameter(\OC::$server->getHasher()->hash($password)),
144
-					'uid_lower' => $qb->createNamedParameter(mb_strtolower($uid)),
145
-				]);
146
-
147
-			$result = $qb->execute();
148
-
149
-			// Clear cache
150
-			unset($this->cache[$uid]);
151
-
152
-			return $result ? true : false;
153
-		}
154
-
155
-		return false;
156
-	}
157
-
158
-	/**
159
-	 * delete a user
160
-	 *
161
-	 * @param string $uid The username of the user to delete
162
-	 * @return bool
163
-	 *
164
-	 * Deletes a user
165
-	 */
166
-	public function deleteUser($uid) {
167
-		$this->fixDI();
168
-
169
-		// Delete user-group-relation
170
-		$query = $this->dbConn->getQueryBuilder();
171
-		$query->delete($this->table)
172
-			->where($query->expr()->eq('uid_lower', $query->createNamedParameter(mb_strtolower($uid))));
173
-		$result = $query->execute();
174
-
175
-		if (isset($this->cache[$uid])) {
176
-			unset($this->cache[$uid]);
177
-		}
178
-
179
-		return $result ? true : false;
180
-	}
181
-
182
-	private function updatePassword(string $uid, string $passwordHash): bool {
183
-		$query = $this->dbConn->getQueryBuilder();
184
-		$query->update($this->table)
185
-			->set('password', $query->createNamedParameter($passwordHash))
186
-			->where($query->expr()->eq('uid_lower', $query->createNamedParameter(mb_strtolower($uid))));
187
-		$result = $query->execute();
188
-
189
-		return $result ? true : false;
190
-	}
191
-
192
-	/**
193
-	 * Set password
194
-	 *
195
-	 * @param string $uid The username
196
-	 * @param string $password The new password
197
-	 * @return bool
198
-	 *
199
-	 * Change the password of a user
200
-	 */
201
-	public function setPassword(string $uid, string $password): bool {
202
-		$this->fixDI();
203
-
204
-		if ($this->userExists($uid)) {
205
-			$this->eventDispatcher->dispatchTyped(new ValidatePasswordPolicyEvent($password));
206
-
207
-			$hasher = \OC::$server->getHasher();
208
-			$hashedPassword = $hasher->hash($password);
209
-
210
-			return $this->updatePassword($uid, $hashedPassword);
211
-		}
212
-
213
-		return false;
214
-	}
215
-
216
-	/**
217
-	 * Set display name
218
-	 *
219
-	 * @param string $uid The username
220
-	 * @param string $displayName The new display name
221
-	 * @return bool
222
-	 *
223
-	 * Change the display name of a user
224
-	 */
225
-	public function setDisplayName(string $uid, string $displayName): bool {
226
-		$this->fixDI();
227
-
228
-		if ($this->userExists($uid)) {
229
-			$query = $this->dbConn->getQueryBuilder();
230
-			$query->update($this->table)
231
-				->set('displayname', $query->createNamedParameter($displayName))
232
-				->where($query->expr()->eq('uid_lower', $query->createNamedParameter(mb_strtolower($uid))));
233
-			$query->execute();
234
-
235
-			$this->cache[$uid]['displayname'] = $displayName;
236
-
237
-			return true;
238
-		}
239
-
240
-		return false;
241
-	}
242
-
243
-	/**
244
-	 * get display name of the user
245
-	 *
246
-	 * @param string $uid user ID of the user
247
-	 * @return string display name
248
-	 */
249
-	public function getDisplayName($uid): string {
250
-		$uid = (string)$uid;
251
-		$this->loadUser($uid);
252
-		return empty($this->cache[$uid]['displayname']) ? $uid : $this->cache[$uid]['displayname'];
253
-	}
254
-
255
-	/**
256
-	 * Get a list of all display names and user ids.
257
-	 *
258
-	 * @param string $search
259
-	 * @param int|null $limit
260
-	 * @param int|null $offset
261
-	 * @return array an array of all displayNames (value) and the corresponding uids (key)
262
-	 */
263
-	public function getDisplayNames($search = '', $limit = null, $offset = null) {
264
-		$limit = $this->fixLimit($limit);
265
-
266
-		$this->fixDI();
267
-
268
-		$query = $this->dbConn->getQueryBuilder();
269
-
270
-		$query->select('uid', 'displayname')
271
-			->from($this->table, 'u')
272
-			->leftJoin('u', 'preferences', 'p', $query->expr()->andX(
273
-				$query->expr()->eq('userid', 'uid'),
274
-				$query->expr()->eq('appid', $query->expr()->literal('settings')),
275
-				$query->expr()->eq('configkey', $query->expr()->literal('email')))
276
-			)
277
-			// sqlite doesn't like re-using a single named parameter here
278
-			->where($query->expr()->iLike('uid', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%')))
279
-			->orWhere($query->expr()->iLike('displayname', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%')))
280
-			->orWhere($query->expr()->iLike('configvalue', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%')))
281
-			->orderBy($query->func()->lower('displayname'), 'ASC')
282
-			->addOrderBy('uid_lower', 'ASC')
283
-			->setMaxResults($limit)
284
-			->setFirstResult($offset);
285
-
286
-		$result = $query->execute();
287
-		$displayNames = [];
288
-		while ($row = $result->fetch()) {
289
-			$displayNames[(string)$row['uid']] = (string)$row['displayname'];
290
-		}
291
-
292
-		return $displayNames;
293
-	}
294
-
295
-	/**
296
-	 * @param string $searcher
297
-	 * @param string $pattern
298
-	 * @param int|null $limit
299
-	 * @param int|null $offset
300
-	 * @return array
301
-	 * @since 21.0.1
302
-	 */
303
-	public function searchKnownUsersByDisplayName(string $searcher, string $pattern, ?int $limit = null, ?int $offset = null): array {
304
-		$limit = $this->fixLimit($limit);
305
-
306
-		$this->fixDI();
307
-
308
-		$query = $this->dbConn->getQueryBuilder();
309
-
310
-		$query->select('u.uid', 'u.displayname')
311
-			->from($this->table, 'u')
312
-			->leftJoin('u', 'known_users', 'k', $query->expr()->andX(
313
-				$query->expr()->eq('k.known_user', 'u.uid'),
314
-				$query->expr()->eq('k.known_to', $query->createNamedParameter($searcher))
315
-			))
316
-			->where($query->expr()->eq('k.known_to', $query->createNamedParameter($searcher)))
317
-			->andWhere($query->expr()->orX(
318
-				$query->expr()->iLike('u.uid', $query->createNamedParameter('%' . $this->dbConn->escapeLikeParameter($pattern) . '%')),
319
-				$query->expr()->iLike('u.displayname', $query->createNamedParameter('%' . $this->dbConn->escapeLikeParameter($pattern) . '%'))
320
-			))
321
-			->orderBy('u.displayname', 'ASC')
322
-			->addOrderBy('u.uid_lower', 'ASC')
323
-			->setMaxResults($limit)
324
-			->setFirstResult($offset);
325
-
326
-		$result = $query->execute();
327
-		$displayNames = [];
328
-		while ($row = $result->fetch()) {
329
-			$displayNames[(string)$row['uid']] = (string)$row['displayname'];
330
-		}
331
-
332
-		return $displayNames;
333
-	}
334
-
335
-	/**
336
-	 * Check if the password is correct
337
-	 *
338
-	 * @param string $loginName The loginname
339
-	 * @param string $password The password
340
-	 * @return string
341
-	 *
342
-	 * Check if the password is correct without logging in the user
343
-	 * returns the user id or false
344
-	 */
345
-	public function checkPassword(string $loginName, string $password) {
346
-		$this->fixDI();
347
-
348
-		$qb = $this->dbConn->getQueryBuilder();
349
-		$qb->select('uid', 'password')
350
-			->from($this->table)
351
-			->where(
352
-				$qb->expr()->eq(
353
-					'uid_lower', $qb->createNamedParameter(mb_strtolower($loginName))
354
-				)
355
-			);
356
-		$result = $qb->execute();
357
-		$row = $result->fetch();
358
-		$result->closeCursor();
359
-
360
-		if ($row) {
361
-			$storedHash = $row['password'];
362
-			$newHash = '';
363
-			if (\OC::$server->getHasher()->verify($password, $storedHash, $newHash)) {
364
-				if (!empty($newHash)) {
365
-					$this->updatePassword($loginName, $newHash);
366
-				}
367
-				return (string)$row['uid'];
368
-			}
369
-		}
370
-
371
-		return false;
372
-	}
373
-
374
-	/**
375
-	 * Load an user in the cache
376
-	 *
377
-	 * @param string $uid the username
378
-	 * @return boolean true if user was found, false otherwise
379
-	 */
380
-	private function loadUser($uid) {
381
-		$this->fixDI();
382
-
383
-		$uid = (string)$uid;
384
-		if (!isset($this->cache[$uid])) {
385
-			//guests $uid could be NULL or ''
386
-			if ($uid === '') {
387
-				$this->cache[$uid] = false;
388
-				return true;
389
-			}
390
-
391
-			$qb = $this->dbConn->getQueryBuilder();
392
-			$qb->select('uid', 'displayname')
393
-				->from($this->table)
394
-				->where(
395
-					$qb->expr()->eq(
396
-						'uid_lower', $qb->createNamedParameter(mb_strtolower($uid))
397
-					)
398
-				);
399
-			$result = $qb->execute();
400
-			$row = $result->fetch();
401
-			$result->closeCursor();
402
-
403
-			$this->cache[$uid] = false;
404
-
405
-			// "uid" is primary key, so there can only be a single result
406
-			if ($row !== false) {
407
-				$this->cache[$uid]['uid'] = (string)$row['uid'];
408
-				$this->cache[$uid]['displayname'] = (string)$row['displayname'];
409
-			} else {
410
-				return false;
411
-			}
412
-		}
413
-
414
-		return true;
415
-	}
416
-
417
-	/**
418
-	 * Get a list of all users
419
-	 *
420
-	 * @param string $search
421
-	 * @param null|int $limit
422
-	 * @param null|int $offset
423
-	 * @return string[] an array of all uids
424
-	 */
425
-	public function getUsers($search = '', $limit = null, $offset = null) {
426
-		$limit = $this->fixLimit($limit);
427
-
428
-		$users = $this->getDisplayNames($search, $limit, $offset);
429
-		$userIds = array_map(function ($uid) {
430
-			return (string)$uid;
431
-		}, array_keys($users));
432
-		sort($userIds, SORT_STRING | SORT_FLAG_CASE);
433
-		return $userIds;
434
-	}
435
-
436
-	/**
437
-	 * check if a user exists
438
-	 *
439
-	 * @param string $uid the username
440
-	 * @return boolean
441
-	 */
442
-	public function userExists($uid) {
443
-		$this->loadUser($uid);
444
-		return $this->cache[$uid] !== false;
445
-	}
446
-
447
-	/**
448
-	 * get the user's home directory
449
-	 *
450
-	 * @param string $uid the username
451
-	 * @return string|false
452
-	 */
453
-	public function getHome(string $uid) {
454
-		if ($this->userExists($uid)) {
455
-			return \OC::$server->getConfig()->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/' . $uid;
456
-		}
457
-
458
-		return false;
459
-	}
460
-
461
-	/**
462
-	 * @return bool
463
-	 */
464
-	public function hasUserListings() {
465
-		return true;
466
-	}
467
-
468
-	/**
469
-	 * counts the users in the database
470
-	 *
471
-	 * @return int|bool
472
-	 */
473
-	public function countUsers() {
474
-		$this->fixDI();
475
-
476
-		$query = $this->dbConn->getQueryBuilder();
477
-		$query->select($query->func()->count('uid'))
478
-			->from($this->table);
479
-		$result = $query->execute();
480
-
481
-		return $result->fetchOne();
482
-	}
483
-
484
-	/**
485
-	 * returns the username for the given login name in the correct casing
486
-	 *
487
-	 * @param string $loginName
488
-	 * @return string|false
489
-	 */
490
-	public function loginName2UserName($loginName) {
491
-		if ($this->userExists($loginName)) {
492
-			return $this->cache[$loginName]['uid'];
493
-		}
494
-
495
-		return false;
496
-	}
497
-
498
-	/**
499
-	 * Backend name to be shown in user management
500
-	 *
501
-	 * @return string the name of the backend to be shown
502
-	 */
503
-	public function getBackendName() {
504
-		return 'Database';
505
-	}
506
-
507
-	public static function preLoginNameUsedAsUserName($param) {
508
-		if (!isset($param['uid'])) {
509
-			throw new \Exception('key uid is expected to be set in $param');
510
-		}
511
-
512
-		$backends = \OC::$server->getUserManager()->getBackends();
513
-		foreach ($backends as $backend) {
514
-			if ($backend instanceof Database) {
515
-				/** @var \OC\User\Database $backend */
516
-				$uid = $backend->loginName2UserName($param['uid']);
517
-				if ($uid !== false) {
518
-					$param['uid'] = $uid;
519
-					return;
520
-				}
521
-			}
522
-		}
523
-	}
524
-
525
-	public function getRealUID(string $uid): string {
526
-		if (!$this->userExists($uid)) {
527
-			throw new \RuntimeException($uid . ' does not exist');
528
-		}
529
-
530
-		return $this->cache[$uid]['uid'];
531
-	}
532
-
533
-	private function fixLimit($limit) {
534
-		if (is_int($limit) && $limit >= 0) {
535
-			return $limit;
536
-		}
537
-
538
-		return null;
539
-	}
81
+    ICreateUserBackend,
82
+                ISetPasswordBackend,
83
+                ISetDisplayNameBackend,
84
+                IGetDisplayNameBackend,
85
+                ICheckPasswordBackend,
86
+                IGetHomeBackend,
87
+                ICountUsersBackend,
88
+                ISearchKnownUsersBackend,
89
+                IGetRealUIDBackend {
90
+    /** @var CappedMemoryCache */
91
+    private $cache;
92
+
93
+    /** @var IEventDispatcher */
94
+    private $eventDispatcher;
95
+
96
+    /** @var IDBConnection */
97
+    private $dbConn;
98
+
99
+    /** @var string */
100
+    private $table;
101
+
102
+    /**
103
+     * \OC\User\Database constructor.
104
+     *
105
+     * @param IEventDispatcher $eventDispatcher
106
+     * @param string $table
107
+     */
108
+    public function __construct($eventDispatcher = null, $table = 'users') {
109
+        $this->cache = new CappedMemoryCache();
110
+        $this->table = $table;
111
+        $this->eventDispatcher = $eventDispatcher ? $eventDispatcher : \OC::$server->query(IEventDispatcher::class);
112
+    }
113
+
114
+    /**
115
+     * FIXME: This function should not be required!
116
+     */
117
+    private function fixDI() {
118
+        if ($this->dbConn === null) {
119
+            $this->dbConn = \OC::$server->getDatabaseConnection();
120
+        }
121
+    }
122
+
123
+    /**
124
+     * Create a new user
125
+     *
126
+     * @param string $uid The username of the user to create
127
+     * @param string $password The password of the new user
128
+     * @return bool
129
+     *
130
+     * Creates a new user. Basic checking of username is done in OC_User
131
+     * itself, not in its subclasses.
132
+     */
133
+    public function createUser(string $uid, string $password): bool {
134
+        $this->fixDI();
135
+
136
+        if (!$this->userExists($uid)) {
137
+            $this->eventDispatcher->dispatchTyped(new ValidatePasswordPolicyEvent($password));
138
+
139
+            $qb = $this->dbConn->getQueryBuilder();
140
+            $qb->insert($this->table)
141
+                ->values([
142
+                    'uid' => $qb->createNamedParameter($uid),
143
+                    'password' => $qb->createNamedParameter(\OC::$server->getHasher()->hash($password)),
144
+                    'uid_lower' => $qb->createNamedParameter(mb_strtolower($uid)),
145
+                ]);
146
+
147
+            $result = $qb->execute();
148
+
149
+            // Clear cache
150
+            unset($this->cache[$uid]);
151
+
152
+            return $result ? true : false;
153
+        }
154
+
155
+        return false;
156
+    }
157
+
158
+    /**
159
+     * delete a user
160
+     *
161
+     * @param string $uid The username of the user to delete
162
+     * @return bool
163
+     *
164
+     * Deletes a user
165
+     */
166
+    public function deleteUser($uid) {
167
+        $this->fixDI();
168
+
169
+        // Delete user-group-relation
170
+        $query = $this->dbConn->getQueryBuilder();
171
+        $query->delete($this->table)
172
+            ->where($query->expr()->eq('uid_lower', $query->createNamedParameter(mb_strtolower($uid))));
173
+        $result = $query->execute();
174
+
175
+        if (isset($this->cache[$uid])) {
176
+            unset($this->cache[$uid]);
177
+        }
178
+
179
+        return $result ? true : false;
180
+    }
181
+
182
+    private function updatePassword(string $uid, string $passwordHash): bool {
183
+        $query = $this->dbConn->getQueryBuilder();
184
+        $query->update($this->table)
185
+            ->set('password', $query->createNamedParameter($passwordHash))
186
+            ->where($query->expr()->eq('uid_lower', $query->createNamedParameter(mb_strtolower($uid))));
187
+        $result = $query->execute();
188
+
189
+        return $result ? true : false;
190
+    }
191
+
192
+    /**
193
+     * Set password
194
+     *
195
+     * @param string $uid The username
196
+     * @param string $password The new password
197
+     * @return bool
198
+     *
199
+     * Change the password of a user
200
+     */
201
+    public function setPassword(string $uid, string $password): bool {
202
+        $this->fixDI();
203
+
204
+        if ($this->userExists($uid)) {
205
+            $this->eventDispatcher->dispatchTyped(new ValidatePasswordPolicyEvent($password));
206
+
207
+            $hasher = \OC::$server->getHasher();
208
+            $hashedPassword = $hasher->hash($password);
209
+
210
+            return $this->updatePassword($uid, $hashedPassword);
211
+        }
212
+
213
+        return false;
214
+    }
215
+
216
+    /**
217
+     * Set display name
218
+     *
219
+     * @param string $uid The username
220
+     * @param string $displayName The new display name
221
+     * @return bool
222
+     *
223
+     * Change the display name of a user
224
+     */
225
+    public function setDisplayName(string $uid, string $displayName): bool {
226
+        $this->fixDI();
227
+
228
+        if ($this->userExists($uid)) {
229
+            $query = $this->dbConn->getQueryBuilder();
230
+            $query->update($this->table)
231
+                ->set('displayname', $query->createNamedParameter($displayName))
232
+                ->where($query->expr()->eq('uid_lower', $query->createNamedParameter(mb_strtolower($uid))));
233
+            $query->execute();
234
+
235
+            $this->cache[$uid]['displayname'] = $displayName;
236
+
237
+            return true;
238
+        }
239
+
240
+        return false;
241
+    }
242
+
243
+    /**
244
+     * get display name of the user
245
+     *
246
+     * @param string $uid user ID of the user
247
+     * @return string display name
248
+     */
249
+    public function getDisplayName($uid): string {
250
+        $uid = (string)$uid;
251
+        $this->loadUser($uid);
252
+        return empty($this->cache[$uid]['displayname']) ? $uid : $this->cache[$uid]['displayname'];
253
+    }
254
+
255
+    /**
256
+     * Get a list of all display names and user ids.
257
+     *
258
+     * @param string $search
259
+     * @param int|null $limit
260
+     * @param int|null $offset
261
+     * @return array an array of all displayNames (value) and the corresponding uids (key)
262
+     */
263
+    public function getDisplayNames($search = '', $limit = null, $offset = null) {
264
+        $limit = $this->fixLimit($limit);
265
+
266
+        $this->fixDI();
267
+
268
+        $query = $this->dbConn->getQueryBuilder();
269
+
270
+        $query->select('uid', 'displayname')
271
+            ->from($this->table, 'u')
272
+            ->leftJoin('u', 'preferences', 'p', $query->expr()->andX(
273
+                $query->expr()->eq('userid', 'uid'),
274
+                $query->expr()->eq('appid', $query->expr()->literal('settings')),
275
+                $query->expr()->eq('configkey', $query->expr()->literal('email')))
276
+            )
277
+            // sqlite doesn't like re-using a single named parameter here
278
+            ->where($query->expr()->iLike('uid', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%')))
279
+            ->orWhere($query->expr()->iLike('displayname', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%')))
280
+            ->orWhere($query->expr()->iLike('configvalue', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%')))
281
+            ->orderBy($query->func()->lower('displayname'), 'ASC')
282
+            ->addOrderBy('uid_lower', 'ASC')
283
+            ->setMaxResults($limit)
284
+            ->setFirstResult($offset);
285
+
286
+        $result = $query->execute();
287
+        $displayNames = [];
288
+        while ($row = $result->fetch()) {
289
+            $displayNames[(string)$row['uid']] = (string)$row['displayname'];
290
+        }
291
+
292
+        return $displayNames;
293
+    }
294
+
295
+    /**
296
+     * @param string $searcher
297
+     * @param string $pattern
298
+     * @param int|null $limit
299
+     * @param int|null $offset
300
+     * @return array
301
+     * @since 21.0.1
302
+     */
303
+    public function searchKnownUsersByDisplayName(string $searcher, string $pattern, ?int $limit = null, ?int $offset = null): array {
304
+        $limit = $this->fixLimit($limit);
305
+
306
+        $this->fixDI();
307
+
308
+        $query = $this->dbConn->getQueryBuilder();
309
+
310
+        $query->select('u.uid', 'u.displayname')
311
+            ->from($this->table, 'u')
312
+            ->leftJoin('u', 'known_users', 'k', $query->expr()->andX(
313
+                $query->expr()->eq('k.known_user', 'u.uid'),
314
+                $query->expr()->eq('k.known_to', $query->createNamedParameter($searcher))
315
+            ))
316
+            ->where($query->expr()->eq('k.known_to', $query->createNamedParameter($searcher)))
317
+            ->andWhere($query->expr()->orX(
318
+                $query->expr()->iLike('u.uid', $query->createNamedParameter('%' . $this->dbConn->escapeLikeParameter($pattern) . '%')),
319
+                $query->expr()->iLike('u.displayname', $query->createNamedParameter('%' . $this->dbConn->escapeLikeParameter($pattern) . '%'))
320
+            ))
321
+            ->orderBy('u.displayname', 'ASC')
322
+            ->addOrderBy('u.uid_lower', 'ASC')
323
+            ->setMaxResults($limit)
324
+            ->setFirstResult($offset);
325
+
326
+        $result = $query->execute();
327
+        $displayNames = [];
328
+        while ($row = $result->fetch()) {
329
+            $displayNames[(string)$row['uid']] = (string)$row['displayname'];
330
+        }
331
+
332
+        return $displayNames;
333
+    }
334
+
335
+    /**
336
+     * Check if the password is correct
337
+     *
338
+     * @param string $loginName The loginname
339
+     * @param string $password The password
340
+     * @return string
341
+     *
342
+     * Check if the password is correct without logging in the user
343
+     * returns the user id or false
344
+     */
345
+    public function checkPassword(string $loginName, string $password) {
346
+        $this->fixDI();
347
+
348
+        $qb = $this->dbConn->getQueryBuilder();
349
+        $qb->select('uid', 'password')
350
+            ->from($this->table)
351
+            ->where(
352
+                $qb->expr()->eq(
353
+                    'uid_lower', $qb->createNamedParameter(mb_strtolower($loginName))
354
+                )
355
+            );
356
+        $result = $qb->execute();
357
+        $row = $result->fetch();
358
+        $result->closeCursor();
359
+
360
+        if ($row) {
361
+            $storedHash = $row['password'];
362
+            $newHash = '';
363
+            if (\OC::$server->getHasher()->verify($password, $storedHash, $newHash)) {
364
+                if (!empty($newHash)) {
365
+                    $this->updatePassword($loginName, $newHash);
366
+                }
367
+                return (string)$row['uid'];
368
+            }
369
+        }
370
+
371
+        return false;
372
+    }
373
+
374
+    /**
375
+     * Load an user in the cache
376
+     *
377
+     * @param string $uid the username
378
+     * @return boolean true if user was found, false otherwise
379
+     */
380
+    private function loadUser($uid) {
381
+        $this->fixDI();
382
+
383
+        $uid = (string)$uid;
384
+        if (!isset($this->cache[$uid])) {
385
+            //guests $uid could be NULL or ''
386
+            if ($uid === '') {
387
+                $this->cache[$uid] = false;
388
+                return true;
389
+            }
390
+
391
+            $qb = $this->dbConn->getQueryBuilder();
392
+            $qb->select('uid', 'displayname')
393
+                ->from($this->table)
394
+                ->where(
395
+                    $qb->expr()->eq(
396
+                        'uid_lower', $qb->createNamedParameter(mb_strtolower($uid))
397
+                    )
398
+                );
399
+            $result = $qb->execute();
400
+            $row = $result->fetch();
401
+            $result->closeCursor();
402
+
403
+            $this->cache[$uid] = false;
404
+
405
+            // "uid" is primary key, so there can only be a single result
406
+            if ($row !== false) {
407
+                $this->cache[$uid]['uid'] = (string)$row['uid'];
408
+                $this->cache[$uid]['displayname'] = (string)$row['displayname'];
409
+            } else {
410
+                return false;
411
+            }
412
+        }
413
+
414
+        return true;
415
+    }
416
+
417
+    /**
418
+     * Get a list of all users
419
+     *
420
+     * @param string $search
421
+     * @param null|int $limit
422
+     * @param null|int $offset
423
+     * @return string[] an array of all uids
424
+     */
425
+    public function getUsers($search = '', $limit = null, $offset = null) {
426
+        $limit = $this->fixLimit($limit);
427
+
428
+        $users = $this->getDisplayNames($search, $limit, $offset);
429
+        $userIds = array_map(function ($uid) {
430
+            return (string)$uid;
431
+        }, array_keys($users));
432
+        sort($userIds, SORT_STRING | SORT_FLAG_CASE);
433
+        return $userIds;
434
+    }
435
+
436
+    /**
437
+     * check if a user exists
438
+     *
439
+     * @param string $uid the username
440
+     * @return boolean
441
+     */
442
+    public function userExists($uid) {
443
+        $this->loadUser($uid);
444
+        return $this->cache[$uid] !== false;
445
+    }
446
+
447
+    /**
448
+     * get the user's home directory
449
+     *
450
+     * @param string $uid the username
451
+     * @return string|false
452
+     */
453
+    public function getHome(string $uid) {
454
+        if ($this->userExists($uid)) {
455
+            return \OC::$server->getConfig()->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/' . $uid;
456
+        }
457
+
458
+        return false;
459
+    }
460
+
461
+    /**
462
+     * @return bool
463
+     */
464
+    public function hasUserListings() {
465
+        return true;
466
+    }
467
+
468
+    /**
469
+     * counts the users in the database
470
+     *
471
+     * @return int|bool
472
+     */
473
+    public function countUsers() {
474
+        $this->fixDI();
475
+
476
+        $query = $this->dbConn->getQueryBuilder();
477
+        $query->select($query->func()->count('uid'))
478
+            ->from($this->table);
479
+        $result = $query->execute();
480
+
481
+        return $result->fetchOne();
482
+    }
483
+
484
+    /**
485
+     * returns the username for the given login name in the correct casing
486
+     *
487
+     * @param string $loginName
488
+     * @return string|false
489
+     */
490
+    public function loginName2UserName($loginName) {
491
+        if ($this->userExists($loginName)) {
492
+            return $this->cache[$loginName]['uid'];
493
+        }
494
+
495
+        return false;
496
+    }
497
+
498
+    /**
499
+     * Backend name to be shown in user management
500
+     *
501
+     * @return string the name of the backend to be shown
502
+     */
503
+    public function getBackendName() {
504
+        return 'Database';
505
+    }
506
+
507
+    public static function preLoginNameUsedAsUserName($param) {
508
+        if (!isset($param['uid'])) {
509
+            throw new \Exception('key uid is expected to be set in $param');
510
+        }
511
+
512
+        $backends = \OC::$server->getUserManager()->getBackends();
513
+        foreach ($backends as $backend) {
514
+            if ($backend instanceof Database) {
515
+                /** @var \OC\User\Database $backend */
516
+                $uid = $backend->loginName2UserName($param['uid']);
517
+                if ($uid !== false) {
518
+                    $param['uid'] = $uid;
519
+                    return;
520
+                }
521
+            }
522
+        }
523
+    }
524
+
525
+    public function getRealUID(string $uid): string {
526
+        if (!$this->userExists($uid)) {
527
+            throw new \RuntimeException($uid . ' does not exist');
528
+        }
529
+
530
+        return $this->cache[$uid]['uid'];
531
+    }
532
+
533
+    private function fixLimit($limit) {
534
+        if (is_int($limit) && $limit >= 0) {
535
+            return $limit;
536
+        }
537
+
538
+        return null;
539
+    }
540 540
 }
Please login to merge, or discard this patch.
Spacing   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -247,7 +247,7 @@  discard block
 block discarded – undo
247 247
 	 * @return string display name
248 248
 	 */
249 249
 	public function getDisplayName($uid): string {
250
-		$uid = (string)$uid;
250
+		$uid = (string) $uid;
251 251
 		$this->loadUser($uid);
252 252
 		return empty($this->cache[$uid]['displayname']) ? $uid : $this->cache[$uid]['displayname'];
253 253
 	}
@@ -275,9 +275,9 @@  discard block
 block discarded – undo
275 275
 				$query->expr()->eq('configkey', $query->expr()->literal('email')))
276 276
 			)
277 277
 			// sqlite doesn't like re-using a single named parameter here
278
-			->where($query->expr()->iLike('uid', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%')))
279
-			->orWhere($query->expr()->iLike('displayname', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%')))
280
-			->orWhere($query->expr()->iLike('configvalue', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%')))
278
+			->where($query->expr()->iLike('uid', $query->createPositionalParameter('%'.$this->dbConn->escapeLikeParameter($search).'%')))
279
+			->orWhere($query->expr()->iLike('displayname', $query->createPositionalParameter('%'.$this->dbConn->escapeLikeParameter($search).'%')))
280
+			->orWhere($query->expr()->iLike('configvalue', $query->createPositionalParameter('%'.$this->dbConn->escapeLikeParameter($search).'%')))
281 281
 			->orderBy($query->func()->lower('displayname'), 'ASC')
282 282
 			->addOrderBy('uid_lower', 'ASC')
283 283
 			->setMaxResults($limit)
@@ -286,7 +286,7 @@  discard block
 block discarded – undo
286 286
 		$result = $query->execute();
287 287
 		$displayNames = [];
288 288
 		while ($row = $result->fetch()) {
289
-			$displayNames[(string)$row['uid']] = (string)$row['displayname'];
289
+			$displayNames[(string) $row['uid']] = (string) $row['displayname'];
290 290
 		}
291 291
 
292 292
 		return $displayNames;
@@ -315,8 +315,8 @@  discard block
 block discarded – undo
315 315
 			))
316 316
 			->where($query->expr()->eq('k.known_to', $query->createNamedParameter($searcher)))
317 317
 			->andWhere($query->expr()->orX(
318
-				$query->expr()->iLike('u.uid', $query->createNamedParameter('%' . $this->dbConn->escapeLikeParameter($pattern) . '%')),
319
-				$query->expr()->iLike('u.displayname', $query->createNamedParameter('%' . $this->dbConn->escapeLikeParameter($pattern) . '%'))
318
+				$query->expr()->iLike('u.uid', $query->createNamedParameter('%'.$this->dbConn->escapeLikeParameter($pattern).'%')),
319
+				$query->expr()->iLike('u.displayname', $query->createNamedParameter('%'.$this->dbConn->escapeLikeParameter($pattern).'%'))
320 320
 			))
321 321
 			->orderBy('u.displayname', 'ASC')
322 322
 			->addOrderBy('u.uid_lower', 'ASC')
@@ -326,7 +326,7 @@  discard block
 block discarded – undo
326 326
 		$result = $query->execute();
327 327
 		$displayNames = [];
328 328
 		while ($row = $result->fetch()) {
329
-			$displayNames[(string)$row['uid']] = (string)$row['displayname'];
329
+			$displayNames[(string) $row['uid']] = (string) $row['displayname'];
330 330
 		}
331 331
 
332 332
 		return $displayNames;
@@ -364,7 +364,7 @@  discard block
 block discarded – undo
364 364
 				if (!empty($newHash)) {
365 365
 					$this->updatePassword($loginName, $newHash);
366 366
 				}
367
-				return (string)$row['uid'];
367
+				return (string) $row['uid'];
368 368
 			}
369 369
 		}
370 370
 
@@ -380,7 +380,7 @@  discard block
 block discarded – undo
380 380
 	private function loadUser($uid) {
381 381
 		$this->fixDI();
382 382
 
383
-		$uid = (string)$uid;
383
+		$uid = (string) $uid;
384 384
 		if (!isset($this->cache[$uid])) {
385 385
 			//guests $uid could be NULL or ''
386 386
 			if ($uid === '') {
@@ -404,8 +404,8 @@  discard block
 block discarded – undo
404 404
 
405 405
 			// "uid" is primary key, so there can only be a single result
406 406
 			if ($row !== false) {
407
-				$this->cache[$uid]['uid'] = (string)$row['uid'];
408
-				$this->cache[$uid]['displayname'] = (string)$row['displayname'];
407
+				$this->cache[$uid]['uid'] = (string) $row['uid'];
408
+				$this->cache[$uid]['displayname'] = (string) $row['displayname'];
409 409
 			} else {
410 410
 				return false;
411 411
 			}
@@ -426,8 +426,8 @@  discard block
 block discarded – undo
426 426
 		$limit = $this->fixLimit($limit);
427 427
 
428 428
 		$users = $this->getDisplayNames($search, $limit, $offset);
429
-		$userIds = array_map(function ($uid) {
430
-			return (string)$uid;
429
+		$userIds = array_map(function($uid) {
430
+			return (string) $uid;
431 431
 		}, array_keys($users));
432 432
 		sort($userIds, SORT_STRING | SORT_FLAG_CASE);
433 433
 		return $userIds;
@@ -452,7 +452,7 @@  discard block
 block discarded – undo
452 452
 	 */
453 453
 	public function getHome(string $uid) {
454 454
 		if ($this->userExists($uid)) {
455
-			return \OC::$server->getConfig()->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/' . $uid;
455
+			return \OC::$server->getConfig()->getSystemValue('datadirectory', \OC::$SERVERROOT.'/data').'/'.$uid;
456 456
 		}
457 457
 
458 458
 		return false;
@@ -524,7 +524,7 @@  discard block
 block discarded – undo
524 524
 
525 525
 	public function getRealUID(string $uid): string {
526 526
 		if (!$this->userExists($uid)) {
527
-			throw new \RuntimeException($uid . ' does not exist');
527
+			throw new \RuntimeException($uid.' does not exist');
528 528
 		}
529 529
 
530 530
 		return $this->cache[$uid]['uid'];
Please login to merge, or discard this patch.
lib/private/User/Manager.php 2 patches
Indentation   +658 added lines, -658 removed lines patch added patch discarded remove patch
@@ -71,662 +71,662 @@
 block discarded – undo
71 71
  * @package OC\User
72 72
  */
73 73
 class Manager extends PublicEmitter implements IUserManager {
74
-	/**
75
-	 * @var \OCP\UserInterface[] $backends
76
-	 */
77
-	private $backends = [];
78
-
79
-	/**
80
-	 * @var \OC\User\User[] $cachedUsers
81
-	 */
82
-	private $cachedUsers = [];
83
-
84
-	/** @var IConfig */
85
-	private $config;
86
-
87
-	/** @var EventDispatcherInterface */
88
-	private $dispatcher;
89
-
90
-	/** @var ICache */
91
-	private $cache;
92
-
93
-	/** @var IEventDispatcher */
94
-	private $eventDispatcher;
95
-
96
-	public function __construct(IConfig $config,
97
-								EventDispatcherInterface $oldDispatcher,
98
-								ICacheFactory $cacheFactory,
99
-								IEventDispatcher $eventDispatcher) {
100
-		$this->config = $config;
101
-		$this->dispatcher = $oldDispatcher;
102
-		$this->cache = $cacheFactory->createDistributed('user_backend_map');
103
-		$cachedUsers = &$this->cachedUsers;
104
-		$this->listen('\OC\User', 'postDelete', function ($user) use (&$cachedUsers) {
105
-			/** @var \OC\User\User $user */
106
-			unset($cachedUsers[$user->getUID()]);
107
-		});
108
-		$this->eventDispatcher = $eventDispatcher;
109
-	}
110
-
111
-	/**
112
-	 * Get the active backends
113
-	 * @return \OCP\UserInterface[]
114
-	 */
115
-	public function getBackends() {
116
-		return $this->backends;
117
-	}
118
-
119
-	/**
120
-	 * register a user backend
121
-	 *
122
-	 * @param \OCP\UserInterface $backend
123
-	 */
124
-	public function registerBackend($backend) {
125
-		$this->backends[] = $backend;
126
-	}
127
-
128
-	/**
129
-	 * remove a user backend
130
-	 *
131
-	 * @param \OCP\UserInterface $backend
132
-	 */
133
-	public function removeBackend($backend) {
134
-		$this->cachedUsers = [];
135
-		if (($i = array_search($backend, $this->backends)) !== false) {
136
-			unset($this->backends[$i]);
137
-		}
138
-	}
139
-
140
-	/**
141
-	 * remove all user backends
142
-	 */
143
-	public function clearBackends() {
144
-		$this->cachedUsers = [];
145
-		$this->backends = [];
146
-	}
147
-
148
-	/**
149
-	 * get a user by user id
150
-	 *
151
-	 * @param string $uid
152
-	 * @return \OC\User\User|null Either the user or null if the specified user does not exist
153
-	 */
154
-	public function get($uid) {
155
-		if (is_null($uid) || $uid === '' || $uid === false) {
156
-			return null;
157
-		}
158
-		if (isset($this->cachedUsers[$uid])) { //check the cache first to prevent having to loop over the backends
159
-			return $this->cachedUsers[$uid];
160
-		}
161
-
162
-		$cachedBackend = $this->cache->get($uid);
163
-		if ($cachedBackend !== null && isset($this->backends[$cachedBackend])) {
164
-			// Cache has the info of the user backend already, so ask that one directly
165
-			$backend = $this->backends[$cachedBackend];
166
-			if ($backend->userExists($uid)) {
167
-				return $this->getUserObject($uid, $backend);
168
-			}
169
-		}
170
-
171
-		foreach ($this->backends as $i => $backend) {
172
-			if ($i === $cachedBackend) {
173
-				// Tried that one already
174
-				continue;
175
-			}
176
-
177
-			if ($backend->userExists($uid)) {
178
-				$this->cache->set($uid, $i, 300);
179
-				return $this->getUserObject($uid, $backend);
180
-			}
181
-		}
182
-		return null;
183
-	}
184
-
185
-	/**
186
-	 * get or construct the user object
187
-	 *
188
-	 * @param string $uid
189
-	 * @param \OCP\UserInterface $backend
190
-	 * @param bool $cacheUser If false the newly created user object will not be cached
191
-	 * @return \OC\User\User
192
-	 */
193
-	protected function getUserObject($uid, $backend, $cacheUser = true) {
194
-		if ($backend instanceof IGetRealUIDBackend) {
195
-			$uid = $backend->getRealUID($uid);
196
-		}
197
-
198
-		if (isset($this->cachedUsers[$uid])) {
199
-			return $this->cachedUsers[$uid];
200
-		}
201
-
202
-		$user = new User($uid, $backend, $this->dispatcher, $this, $this->config);
203
-		if ($cacheUser) {
204
-			$this->cachedUsers[$uid] = $user;
205
-		}
206
-		return $user;
207
-	}
208
-
209
-	/**
210
-	 * check if a user exists
211
-	 *
212
-	 * @param string $uid
213
-	 * @return bool
214
-	 */
215
-	public function userExists($uid) {
216
-		$user = $this->get($uid);
217
-		return ($user !== null);
218
-	}
219
-
220
-	/**
221
-	 * Check if the password is valid for the user
222
-	 *
223
-	 * @param string $loginName
224
-	 * @param string $password
225
-	 * @return mixed the User object on success, false otherwise
226
-	 */
227
-	public function checkPassword($loginName, $password) {
228
-		$result = $this->checkPasswordNoLogging($loginName, $password);
229
-
230
-		if ($result === false) {
231
-			\OC::$server->getLogger()->warning('Login failed: \''. $loginName .'\' (Remote IP: \''. \OC::$server->getRequest()->getRemoteAddress(). '\')', ['app' => 'core']);
232
-		}
233
-
234
-		return $result;
235
-	}
236
-
237
-	/**
238
-	 * Check if the password is valid for the user
239
-	 *
240
-	 * @internal
241
-	 * @param string $loginName
242
-	 * @param string $password
243
-	 * @return IUser|false the User object on success, false otherwise
244
-	 */
245
-	public function checkPasswordNoLogging($loginName, $password) {
246
-		$loginName = str_replace("\0", '', $loginName);
247
-		$password = str_replace("\0", '', $password);
248
-
249
-		foreach ($this->backends as $backend) {
250
-			if ($backend->implementsActions(Backend::CHECK_PASSWORD)) {
251
-				$uid = $backend->checkPassword($loginName, $password);
252
-				if ($uid !== false) {
253
-					return $this->getUserObject($uid, $backend);
254
-				}
255
-			}
256
-		}
257
-
258
-		// since http basic auth doesn't provide a standard way of handling non ascii password we allow password to be urlencoded
259
-		// we only do this decoding after using the plain password fails to maintain compatibility with any password that happens
260
-		// to contains urlencoded patterns by "accident".
261
-		$password = urldecode($password);
262
-
263
-		foreach ($this->backends as $backend) {
264
-			if ($backend->implementsActions(Backend::CHECK_PASSWORD)) {
265
-				$uid = $backend->checkPassword($loginName, $password);
266
-				if ($uid !== false) {
267
-					return $this->getUserObject($uid, $backend);
268
-				}
269
-			}
270
-		}
271
-
272
-		return false;
273
-	}
274
-
275
-	/**
276
-	 * search by user id
277
-	 *
278
-	 * @param string $pattern
279
-	 * @param int $limit
280
-	 * @param int $offset
281
-	 * @return \OC\User\User[]
282
-	 */
283
-	public function search($pattern, $limit = null, $offset = null) {
284
-		$users = [];
285
-		foreach ($this->backends as $backend) {
286
-			$backendUsers = $backend->getUsers($pattern, $limit, $offset);
287
-			if (is_array($backendUsers)) {
288
-				foreach ($backendUsers as $uid) {
289
-					$users[$uid] = $this->getUserObject($uid, $backend);
290
-				}
291
-			}
292
-		}
293
-
294
-		uasort($users, function ($a, $b) {
295
-			/**
296
-			 * @var \OC\User\User $a
297
-			 * @var \OC\User\User $b
298
-			 */
299
-			return strcasecmp($a->getUID(), $b->getUID());
300
-		});
301
-		return $users;
302
-	}
303
-
304
-	/**
305
-	 * search by displayName
306
-	 *
307
-	 * @param string $pattern
308
-	 * @param int $limit
309
-	 * @param int $offset
310
-	 * @return \OC\User\User[]
311
-	 */
312
-	public function searchDisplayName($pattern, $limit = null, $offset = null) {
313
-		$users = [];
314
-		foreach ($this->backends as $backend) {
315
-			$backendUsers = $backend->getDisplayNames($pattern, $limit, $offset);
316
-			if (is_array($backendUsers)) {
317
-				foreach ($backendUsers as $uid => $displayName) {
318
-					$users[] = $this->getUserObject($uid, $backend);
319
-				}
320
-			}
321
-		}
322
-
323
-		usort($users, function ($a, $b) {
324
-			/**
325
-			 * @var \OC\User\User $a
326
-			 * @var \OC\User\User $b
327
-			 */
328
-			return strcasecmp($a->getDisplayName(), $b->getDisplayName());
329
-		});
330
-		return $users;
331
-	}
332
-
333
-	/**
334
-	 * Search known users (from phonebook sync) by displayName
335
-	 *
336
-	 * @param string $searcher
337
-	 * @param string $pattern
338
-	 * @param int|null $limit
339
-	 * @param int|null $offset
340
-	 * @return IUser[]
341
-	 */
342
-	public function searchKnownUsersByDisplayName(string $searcher, string $pattern, ?int $limit = null, ?int $offset = null): array {
343
-		$users = [];
344
-		foreach ($this->backends as $backend) {
345
-			if ($backend instanceof ISearchKnownUsersBackend) {
346
-				$backendUsers = $backend->searchKnownUsersByDisplayName($searcher, $pattern, $limit, $offset);
347
-			} else {
348
-				// Better than nothing, but filtering after pagination can remove lots of results.
349
-				$backendUsers = $backend->getDisplayNames($pattern, $limit, $offset);
350
-			}
351
-			if (is_array($backendUsers)) {
352
-				foreach ($backendUsers as $uid => $displayName) {
353
-					$users[] = $this->getUserObject($uid, $backend);
354
-				}
355
-			}
356
-		}
357
-
358
-		usort($users, function ($a, $b) {
359
-			/**
360
-			 * @var IUser $a
361
-			 * @var IUser $b
362
-			 */
363
-			return strcasecmp($a->getDisplayName(), $b->getDisplayName());
364
-		});
365
-		return $users;
366
-	}
367
-
368
-	/**
369
-	 * @param string $uid
370
-	 * @param string $password
371
-	 * @throws \InvalidArgumentException
372
-	 * @return bool|IUser the created user or false
373
-	 */
374
-	public function createUser($uid, $password) {
375
-		// DI injection is not used here as IRegistry needs the user manager itself for user count and thus it would create a cyclic dependency
376
-		if (\OC::$server->get(IRegistry::class)->delegateIsHardUserLimitReached()) {
377
-			$l = \OC::$server->getL10N('lib');
378
-			throw new HintException($l->t('The user limit has been reached and the user was not created.'));
379
-		}
380
-
381
-		$localBackends = [];
382
-		foreach ($this->backends as $backend) {
383
-			if ($backend instanceof Database) {
384
-				// First check if there is another user backend
385
-				$localBackends[] = $backend;
386
-				continue;
387
-			}
388
-
389
-			if ($backend->implementsActions(Backend::CREATE_USER)) {
390
-				return $this->createUserFromBackend($uid, $password, $backend);
391
-			}
392
-		}
393
-
394
-		foreach ($localBackends as $backend) {
395
-			if ($backend->implementsActions(Backend::CREATE_USER)) {
396
-				return $this->createUserFromBackend($uid, $password, $backend);
397
-			}
398
-		}
399
-
400
-		return false;
401
-	}
402
-
403
-	/**
404
-	 * @param string $uid
405
-	 * @param string $password
406
-	 * @param UserInterface $backend
407
-	 * @return IUser|null
408
-	 * @throws \InvalidArgumentException
409
-	 */
410
-	public function createUserFromBackend($uid, $password, UserInterface $backend) {
411
-		$l = \OC::$server->getL10N('lib');
412
-
413
-		// Check the name for bad characters
414
-		// Allowed are: "a-z", "A-Z", "0-9" and "_.@-'"
415
-		if (preg_match('/[^a-zA-Z0-9 _.@\-\']/', $uid)) {
416
-			throw new \InvalidArgumentException($l->t('Only the following characters are allowed in a username:'
417
-				. ' "a-z", "A-Z", "0-9", and "_.@-\'"'));
418
-		}
419
-
420
-		// No empty username
421
-		if (trim($uid) === '') {
422
-			throw new \InvalidArgumentException($l->t('A valid username must be provided'));
423
-		}
424
-
425
-		// No whitespace at the beginning or at the end
426
-		if (trim($uid) !== $uid) {
427
-			throw new \InvalidArgumentException($l->t('Username contains whitespace at the beginning or at the end'));
428
-		}
429
-
430
-		// Username only consists of 1 or 2 dots (directory traversal)
431
-		if ($uid === '.' || $uid === '..') {
432
-			throw new \InvalidArgumentException($l->t('Username must not consist of dots only'));
433
-		}
434
-
435
-		if (!$this->verifyUid($uid)) {
436
-			throw new \InvalidArgumentException($l->t('Username is invalid because files already exist for this user'));
437
-		}
438
-
439
-		// No empty password
440
-		if (trim($password) === '') {
441
-			throw new \InvalidArgumentException($l->t('A valid password must be provided'));
442
-		}
443
-
444
-		// Check if user already exists
445
-		if ($this->userExists($uid)) {
446
-			throw new \InvalidArgumentException($l->t('The username is already being used'));
447
-		}
448
-
449
-		/** @deprecated 21.0.0 use BeforeUserCreatedEvent event with the IEventDispatcher instead */
450
-		$this->emit('\OC\User', 'preCreateUser', [$uid, $password]);
451
-		$this->eventDispatcher->dispatchTyped(new BeforeUserCreatedEvent($uid, $password));
452
-		$state = $backend->createUser($uid, $password);
453
-		if ($state === false) {
454
-			throw new \InvalidArgumentException($l->t('Could not create user'));
455
-		}
456
-		$user = $this->getUserObject($uid, $backend);
457
-		if ($user instanceof IUser) {
458
-			/** @deprecated 21.0.0 use UserCreatedEvent event with the IEventDispatcher instead */
459
-			$this->emit('\OC\User', 'postCreateUser', [$user, $password]);
460
-			$this->eventDispatcher->dispatchTyped(new UserCreatedEvent($user, $password));
461
-		}
462
-		return $user;
463
-	}
464
-
465
-	/**
466
-	 * returns how many users per backend exist (if supported by backend)
467
-	 *
468
-	 * @param boolean $hasLoggedIn when true only users that have a lastLogin
469
-	 *                entry in the preferences table will be affected
470
-	 * @return array|int an array of backend class as key and count number as value
471
-	 *                if $hasLoggedIn is true only an int is returned
472
-	 */
473
-	public function countUsers($hasLoggedIn = false) {
474
-		if ($hasLoggedIn) {
475
-			return $this->countSeenUsers();
476
-		}
477
-		$userCountStatistics = [];
478
-		foreach ($this->backends as $backend) {
479
-			if ($backend->implementsActions(Backend::COUNT_USERS)) {
480
-				$backendUsers = $backend->countUsers();
481
-				if ($backendUsers !== false) {
482
-					if ($backend instanceof IUserBackend) {
483
-						$name = $backend->getBackendName();
484
-					} else {
485
-						$name = get_class($backend);
486
-					}
487
-					if (isset($userCountStatistics[$name])) {
488
-						$userCountStatistics[$name] += $backendUsers;
489
-					} else {
490
-						$userCountStatistics[$name] = $backendUsers;
491
-					}
492
-				}
493
-			}
494
-		}
495
-		return $userCountStatistics;
496
-	}
497
-
498
-	/**
499
-	 * returns how many users per backend exist in the requested groups (if supported by backend)
500
-	 *
501
-	 * @param IGroup[] $groups an array of gid to search in
502
-	 * @return array|int an array of backend class as key and count number as value
503
-	 *                if $hasLoggedIn is true only an int is returned
504
-	 */
505
-	public function countUsersOfGroups(array $groups) {
506
-		$users = [];
507
-		foreach ($groups as $group) {
508
-			$usersIds = array_map(function ($user) {
509
-				return $user->getUID();
510
-			}, $group->getUsers());
511
-			$users = array_merge($users, $usersIds);
512
-		}
513
-		return count(array_unique($users));
514
-	}
515
-
516
-	/**
517
-	 * The callback is executed for each user on each backend.
518
-	 * If the callback returns false no further users will be retrieved.
519
-	 *
520
-	 * @param \Closure $callback
521
-	 * @param string $search
522
-	 * @param boolean $onlySeen when true only users that have a lastLogin entry
523
-	 *                in the preferences table will be affected
524
-	 * @since 9.0.0
525
-	 */
526
-	public function callForAllUsers(\Closure $callback, $search = '', $onlySeen = false) {
527
-		if ($onlySeen) {
528
-			$this->callForSeenUsers($callback);
529
-		} else {
530
-			foreach ($this->getBackends() as $backend) {
531
-				$limit = 500;
532
-				$offset = 0;
533
-				do {
534
-					$users = $backend->getUsers($search, $limit, $offset);
535
-					foreach ($users as $uid) {
536
-						if (!$backend->userExists($uid)) {
537
-							continue;
538
-						}
539
-						$user = $this->getUserObject($uid, $backend, false);
540
-						$return = $callback($user);
541
-						if ($return === false) {
542
-							break;
543
-						}
544
-					}
545
-					$offset += $limit;
546
-				} while (count($users) >= $limit);
547
-			}
548
-		}
549
-	}
550
-
551
-	/**
552
-	 * returns how many users are disabled
553
-	 *
554
-	 * @return int
555
-	 * @since 12.0.0
556
-	 */
557
-	public function countDisabledUsers(): int {
558
-		$queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
559
-		$queryBuilder->select($queryBuilder->func()->count('*'))
560
-			->from('preferences')
561
-			->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('core')))
562
-			->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('enabled')))
563
-			->andWhere($queryBuilder->expr()->eq('configvalue', $queryBuilder->createNamedParameter('false'), IQueryBuilder::PARAM_STR));
564
-
565
-
566
-		$result = $queryBuilder->execute();
567
-		$count = $result->fetchOne();
568
-		$result->closeCursor();
569
-
570
-		if ($count !== false) {
571
-			$count = (int)$count;
572
-		} else {
573
-			$count = 0;
574
-		}
575
-
576
-		return $count;
577
-	}
578
-
579
-	/**
580
-	 * returns how many users are disabled in the requested groups
581
-	 *
582
-	 * @param array $groups groupids to search
583
-	 * @return int
584
-	 * @since 14.0.0
585
-	 */
586
-	public function countDisabledUsersOfGroups(array $groups): int {
587
-		$queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
588
-		$queryBuilder->select($queryBuilder->createFunction('COUNT(DISTINCT ' . $queryBuilder->getColumnName('uid') . ')'))
589
-			->from('preferences', 'p')
590
-			->innerJoin('p', 'group_user', 'g', $queryBuilder->expr()->eq('p.userid', 'g.uid'))
591
-			->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('core')))
592
-			->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('enabled')))
593
-			->andWhere($queryBuilder->expr()->eq('configvalue', $queryBuilder->createNamedParameter('false'), IQueryBuilder::PARAM_STR))
594
-			->andWhere($queryBuilder->expr()->in('gid', $queryBuilder->createNamedParameter($groups, IQueryBuilder::PARAM_STR_ARRAY)));
595
-
596
-		$result = $queryBuilder->execute();
597
-		$count = $result->fetchOne();
598
-		$result->closeCursor();
599
-
600
-		if ($count !== false) {
601
-			$count = (int)$count;
602
-		} else {
603
-			$count = 0;
604
-		}
605
-
606
-		return $count;
607
-	}
608
-
609
-	/**
610
-	 * returns how many users have logged in once
611
-	 *
612
-	 * @return int
613
-	 * @since 11.0.0
614
-	 */
615
-	public function countSeenUsers() {
616
-		$queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
617
-		$queryBuilder->select($queryBuilder->func()->count('*'))
618
-			->from('preferences')
619
-			->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('login')))
620
-			->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('lastLogin')))
621
-			->andWhere($queryBuilder->expr()->isNotNull('configvalue'));
622
-
623
-		$query = $queryBuilder->execute();
624
-
625
-		$result = (int)$query->fetchOne();
626
-		$query->closeCursor();
627
-
628
-		return $result;
629
-	}
630
-
631
-	/**
632
-	 * @param \Closure $callback
633
-	 * @psalm-param \Closure(\OCP\IUser):?bool $callback
634
-	 * @since 11.0.0
635
-	 */
636
-	public function callForSeenUsers(\Closure $callback) {
637
-		$limit = 1000;
638
-		$offset = 0;
639
-		do {
640
-			$userIds = $this->getSeenUserIds($limit, $offset);
641
-			$offset += $limit;
642
-			foreach ($userIds as $userId) {
643
-				foreach ($this->backends as $backend) {
644
-					if ($backend->userExists($userId)) {
645
-						$user = $this->getUserObject($userId, $backend, false);
646
-						$return = $callback($user);
647
-						if ($return === false) {
648
-							return;
649
-						}
650
-						break;
651
-					}
652
-				}
653
-			}
654
-		} while (count($userIds) >= $limit);
655
-	}
656
-
657
-	/**
658
-	 * Getting all userIds that have a listLogin value requires checking the
659
-	 * value in php because on oracle you cannot use a clob in a where clause,
660
-	 * preventing us from doing a not null or length(value) > 0 check.
661
-	 *
662
-	 * @param int $limit
663
-	 * @param int $offset
664
-	 * @return string[] with user ids
665
-	 */
666
-	private function getSeenUserIds($limit = null, $offset = null) {
667
-		$queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
668
-		$queryBuilder->select(['userid'])
669
-			->from('preferences')
670
-			->where($queryBuilder->expr()->eq(
671
-				'appid', $queryBuilder->createNamedParameter('login'))
672
-			)
673
-			->andWhere($queryBuilder->expr()->eq(
674
-				'configkey', $queryBuilder->createNamedParameter('lastLogin'))
675
-			)
676
-			->andWhere($queryBuilder->expr()->isNotNull('configvalue')
677
-			);
678
-
679
-		if ($limit !== null) {
680
-			$queryBuilder->setMaxResults($limit);
681
-		}
682
-		if ($offset !== null) {
683
-			$queryBuilder->setFirstResult($offset);
684
-		}
685
-		$query = $queryBuilder->execute();
686
-		$result = [];
687
-
688
-		while ($row = $query->fetch()) {
689
-			$result[] = $row['userid'];
690
-		}
691
-
692
-		$query->closeCursor();
693
-
694
-		return $result;
695
-	}
696
-
697
-	/**
698
-	 * @param string $email
699
-	 * @return IUser[]
700
-	 * @since 9.1.0
701
-	 */
702
-	public function getByEmail($email) {
703
-		$userIds = $this->config->getUsersForUserValueCaseInsensitive('settings', 'email', $email);
704
-
705
-		$users = array_map(function ($uid) {
706
-			return $this->get($uid);
707
-		}, $userIds);
708
-
709
-		return array_values(array_filter($users, function ($u) {
710
-			return ($u instanceof IUser);
711
-		}));
712
-	}
713
-
714
-	private function verifyUid(string $uid): bool {
715
-		$appdata = 'appdata_' . $this->config->getSystemValueString('instanceid');
716
-
717
-		if (\in_array($uid, [
718
-			'.htaccess',
719
-			'files_external',
720
-			'__groupfolders',
721
-			'.ocdata',
722
-			'owncloud.log',
723
-			'nextcloud.log',
724
-			$appdata], true)) {
725
-			return false;
726
-		}
727
-
728
-		$dataDirectory = $this->config->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data');
729
-
730
-		return !file_exists(rtrim($dataDirectory, '/') . '/' . $uid);
731
-	}
74
+    /**
75
+     * @var \OCP\UserInterface[] $backends
76
+     */
77
+    private $backends = [];
78
+
79
+    /**
80
+     * @var \OC\User\User[] $cachedUsers
81
+     */
82
+    private $cachedUsers = [];
83
+
84
+    /** @var IConfig */
85
+    private $config;
86
+
87
+    /** @var EventDispatcherInterface */
88
+    private $dispatcher;
89
+
90
+    /** @var ICache */
91
+    private $cache;
92
+
93
+    /** @var IEventDispatcher */
94
+    private $eventDispatcher;
95
+
96
+    public function __construct(IConfig $config,
97
+                                EventDispatcherInterface $oldDispatcher,
98
+                                ICacheFactory $cacheFactory,
99
+                                IEventDispatcher $eventDispatcher) {
100
+        $this->config = $config;
101
+        $this->dispatcher = $oldDispatcher;
102
+        $this->cache = $cacheFactory->createDistributed('user_backend_map');
103
+        $cachedUsers = &$this->cachedUsers;
104
+        $this->listen('\OC\User', 'postDelete', function ($user) use (&$cachedUsers) {
105
+            /** @var \OC\User\User $user */
106
+            unset($cachedUsers[$user->getUID()]);
107
+        });
108
+        $this->eventDispatcher = $eventDispatcher;
109
+    }
110
+
111
+    /**
112
+     * Get the active backends
113
+     * @return \OCP\UserInterface[]
114
+     */
115
+    public function getBackends() {
116
+        return $this->backends;
117
+    }
118
+
119
+    /**
120
+     * register a user backend
121
+     *
122
+     * @param \OCP\UserInterface $backend
123
+     */
124
+    public function registerBackend($backend) {
125
+        $this->backends[] = $backend;
126
+    }
127
+
128
+    /**
129
+     * remove a user backend
130
+     *
131
+     * @param \OCP\UserInterface $backend
132
+     */
133
+    public function removeBackend($backend) {
134
+        $this->cachedUsers = [];
135
+        if (($i = array_search($backend, $this->backends)) !== false) {
136
+            unset($this->backends[$i]);
137
+        }
138
+    }
139
+
140
+    /**
141
+     * remove all user backends
142
+     */
143
+    public function clearBackends() {
144
+        $this->cachedUsers = [];
145
+        $this->backends = [];
146
+    }
147
+
148
+    /**
149
+     * get a user by user id
150
+     *
151
+     * @param string $uid
152
+     * @return \OC\User\User|null Either the user or null if the specified user does not exist
153
+     */
154
+    public function get($uid) {
155
+        if (is_null($uid) || $uid === '' || $uid === false) {
156
+            return null;
157
+        }
158
+        if (isset($this->cachedUsers[$uid])) { //check the cache first to prevent having to loop over the backends
159
+            return $this->cachedUsers[$uid];
160
+        }
161
+
162
+        $cachedBackend = $this->cache->get($uid);
163
+        if ($cachedBackend !== null && isset($this->backends[$cachedBackend])) {
164
+            // Cache has the info of the user backend already, so ask that one directly
165
+            $backend = $this->backends[$cachedBackend];
166
+            if ($backend->userExists($uid)) {
167
+                return $this->getUserObject($uid, $backend);
168
+            }
169
+        }
170
+
171
+        foreach ($this->backends as $i => $backend) {
172
+            if ($i === $cachedBackend) {
173
+                // Tried that one already
174
+                continue;
175
+            }
176
+
177
+            if ($backend->userExists($uid)) {
178
+                $this->cache->set($uid, $i, 300);
179
+                return $this->getUserObject($uid, $backend);
180
+            }
181
+        }
182
+        return null;
183
+    }
184
+
185
+    /**
186
+     * get or construct the user object
187
+     *
188
+     * @param string $uid
189
+     * @param \OCP\UserInterface $backend
190
+     * @param bool $cacheUser If false the newly created user object will not be cached
191
+     * @return \OC\User\User
192
+     */
193
+    protected function getUserObject($uid, $backend, $cacheUser = true) {
194
+        if ($backend instanceof IGetRealUIDBackend) {
195
+            $uid = $backend->getRealUID($uid);
196
+        }
197
+
198
+        if (isset($this->cachedUsers[$uid])) {
199
+            return $this->cachedUsers[$uid];
200
+        }
201
+
202
+        $user = new User($uid, $backend, $this->dispatcher, $this, $this->config);
203
+        if ($cacheUser) {
204
+            $this->cachedUsers[$uid] = $user;
205
+        }
206
+        return $user;
207
+    }
208
+
209
+    /**
210
+     * check if a user exists
211
+     *
212
+     * @param string $uid
213
+     * @return bool
214
+     */
215
+    public function userExists($uid) {
216
+        $user = $this->get($uid);
217
+        return ($user !== null);
218
+    }
219
+
220
+    /**
221
+     * Check if the password is valid for the user
222
+     *
223
+     * @param string $loginName
224
+     * @param string $password
225
+     * @return mixed the User object on success, false otherwise
226
+     */
227
+    public function checkPassword($loginName, $password) {
228
+        $result = $this->checkPasswordNoLogging($loginName, $password);
229
+
230
+        if ($result === false) {
231
+            \OC::$server->getLogger()->warning('Login failed: \''. $loginName .'\' (Remote IP: \''. \OC::$server->getRequest()->getRemoteAddress(). '\')', ['app' => 'core']);
232
+        }
233
+
234
+        return $result;
235
+    }
236
+
237
+    /**
238
+     * Check if the password is valid for the user
239
+     *
240
+     * @internal
241
+     * @param string $loginName
242
+     * @param string $password
243
+     * @return IUser|false the User object on success, false otherwise
244
+     */
245
+    public function checkPasswordNoLogging($loginName, $password) {
246
+        $loginName = str_replace("\0", '', $loginName);
247
+        $password = str_replace("\0", '', $password);
248
+
249
+        foreach ($this->backends as $backend) {
250
+            if ($backend->implementsActions(Backend::CHECK_PASSWORD)) {
251
+                $uid = $backend->checkPassword($loginName, $password);
252
+                if ($uid !== false) {
253
+                    return $this->getUserObject($uid, $backend);
254
+                }
255
+            }
256
+        }
257
+
258
+        // since http basic auth doesn't provide a standard way of handling non ascii password we allow password to be urlencoded
259
+        // we only do this decoding after using the plain password fails to maintain compatibility with any password that happens
260
+        // to contains urlencoded patterns by "accident".
261
+        $password = urldecode($password);
262
+
263
+        foreach ($this->backends as $backend) {
264
+            if ($backend->implementsActions(Backend::CHECK_PASSWORD)) {
265
+                $uid = $backend->checkPassword($loginName, $password);
266
+                if ($uid !== false) {
267
+                    return $this->getUserObject($uid, $backend);
268
+                }
269
+            }
270
+        }
271
+
272
+        return false;
273
+    }
274
+
275
+    /**
276
+     * search by user id
277
+     *
278
+     * @param string $pattern
279
+     * @param int $limit
280
+     * @param int $offset
281
+     * @return \OC\User\User[]
282
+     */
283
+    public function search($pattern, $limit = null, $offset = null) {
284
+        $users = [];
285
+        foreach ($this->backends as $backend) {
286
+            $backendUsers = $backend->getUsers($pattern, $limit, $offset);
287
+            if (is_array($backendUsers)) {
288
+                foreach ($backendUsers as $uid) {
289
+                    $users[$uid] = $this->getUserObject($uid, $backend);
290
+                }
291
+            }
292
+        }
293
+
294
+        uasort($users, function ($a, $b) {
295
+            /**
296
+             * @var \OC\User\User $a
297
+             * @var \OC\User\User $b
298
+             */
299
+            return strcasecmp($a->getUID(), $b->getUID());
300
+        });
301
+        return $users;
302
+    }
303
+
304
+    /**
305
+     * search by displayName
306
+     *
307
+     * @param string $pattern
308
+     * @param int $limit
309
+     * @param int $offset
310
+     * @return \OC\User\User[]
311
+     */
312
+    public function searchDisplayName($pattern, $limit = null, $offset = null) {
313
+        $users = [];
314
+        foreach ($this->backends as $backend) {
315
+            $backendUsers = $backend->getDisplayNames($pattern, $limit, $offset);
316
+            if (is_array($backendUsers)) {
317
+                foreach ($backendUsers as $uid => $displayName) {
318
+                    $users[] = $this->getUserObject($uid, $backend);
319
+                }
320
+            }
321
+        }
322
+
323
+        usort($users, function ($a, $b) {
324
+            /**
325
+             * @var \OC\User\User $a
326
+             * @var \OC\User\User $b
327
+             */
328
+            return strcasecmp($a->getDisplayName(), $b->getDisplayName());
329
+        });
330
+        return $users;
331
+    }
332
+
333
+    /**
334
+     * Search known users (from phonebook sync) by displayName
335
+     *
336
+     * @param string $searcher
337
+     * @param string $pattern
338
+     * @param int|null $limit
339
+     * @param int|null $offset
340
+     * @return IUser[]
341
+     */
342
+    public function searchKnownUsersByDisplayName(string $searcher, string $pattern, ?int $limit = null, ?int $offset = null): array {
343
+        $users = [];
344
+        foreach ($this->backends as $backend) {
345
+            if ($backend instanceof ISearchKnownUsersBackend) {
346
+                $backendUsers = $backend->searchKnownUsersByDisplayName($searcher, $pattern, $limit, $offset);
347
+            } else {
348
+                // Better than nothing, but filtering after pagination can remove lots of results.
349
+                $backendUsers = $backend->getDisplayNames($pattern, $limit, $offset);
350
+            }
351
+            if (is_array($backendUsers)) {
352
+                foreach ($backendUsers as $uid => $displayName) {
353
+                    $users[] = $this->getUserObject($uid, $backend);
354
+                }
355
+            }
356
+        }
357
+
358
+        usort($users, function ($a, $b) {
359
+            /**
360
+             * @var IUser $a
361
+             * @var IUser $b
362
+             */
363
+            return strcasecmp($a->getDisplayName(), $b->getDisplayName());
364
+        });
365
+        return $users;
366
+    }
367
+
368
+    /**
369
+     * @param string $uid
370
+     * @param string $password
371
+     * @throws \InvalidArgumentException
372
+     * @return bool|IUser the created user or false
373
+     */
374
+    public function createUser($uid, $password) {
375
+        // DI injection is not used here as IRegistry needs the user manager itself for user count and thus it would create a cyclic dependency
376
+        if (\OC::$server->get(IRegistry::class)->delegateIsHardUserLimitReached()) {
377
+            $l = \OC::$server->getL10N('lib');
378
+            throw new HintException($l->t('The user limit has been reached and the user was not created.'));
379
+        }
380
+
381
+        $localBackends = [];
382
+        foreach ($this->backends as $backend) {
383
+            if ($backend instanceof Database) {
384
+                // First check if there is another user backend
385
+                $localBackends[] = $backend;
386
+                continue;
387
+            }
388
+
389
+            if ($backend->implementsActions(Backend::CREATE_USER)) {
390
+                return $this->createUserFromBackend($uid, $password, $backend);
391
+            }
392
+        }
393
+
394
+        foreach ($localBackends as $backend) {
395
+            if ($backend->implementsActions(Backend::CREATE_USER)) {
396
+                return $this->createUserFromBackend($uid, $password, $backend);
397
+            }
398
+        }
399
+
400
+        return false;
401
+    }
402
+
403
+    /**
404
+     * @param string $uid
405
+     * @param string $password
406
+     * @param UserInterface $backend
407
+     * @return IUser|null
408
+     * @throws \InvalidArgumentException
409
+     */
410
+    public function createUserFromBackend($uid, $password, UserInterface $backend) {
411
+        $l = \OC::$server->getL10N('lib');
412
+
413
+        // Check the name for bad characters
414
+        // Allowed are: "a-z", "A-Z", "0-9" and "_.@-'"
415
+        if (preg_match('/[^a-zA-Z0-9 _.@\-\']/', $uid)) {
416
+            throw new \InvalidArgumentException($l->t('Only the following characters are allowed in a username:'
417
+                . ' "a-z", "A-Z", "0-9", and "_.@-\'"'));
418
+        }
419
+
420
+        // No empty username
421
+        if (trim($uid) === '') {
422
+            throw new \InvalidArgumentException($l->t('A valid username must be provided'));
423
+        }
424
+
425
+        // No whitespace at the beginning or at the end
426
+        if (trim($uid) !== $uid) {
427
+            throw new \InvalidArgumentException($l->t('Username contains whitespace at the beginning or at the end'));
428
+        }
429
+
430
+        // Username only consists of 1 or 2 dots (directory traversal)
431
+        if ($uid === '.' || $uid === '..') {
432
+            throw new \InvalidArgumentException($l->t('Username must not consist of dots only'));
433
+        }
434
+
435
+        if (!$this->verifyUid($uid)) {
436
+            throw new \InvalidArgumentException($l->t('Username is invalid because files already exist for this user'));
437
+        }
438
+
439
+        // No empty password
440
+        if (trim($password) === '') {
441
+            throw new \InvalidArgumentException($l->t('A valid password must be provided'));
442
+        }
443
+
444
+        // Check if user already exists
445
+        if ($this->userExists($uid)) {
446
+            throw new \InvalidArgumentException($l->t('The username is already being used'));
447
+        }
448
+
449
+        /** @deprecated 21.0.0 use BeforeUserCreatedEvent event with the IEventDispatcher instead */
450
+        $this->emit('\OC\User', 'preCreateUser', [$uid, $password]);
451
+        $this->eventDispatcher->dispatchTyped(new BeforeUserCreatedEvent($uid, $password));
452
+        $state = $backend->createUser($uid, $password);
453
+        if ($state === false) {
454
+            throw new \InvalidArgumentException($l->t('Could not create user'));
455
+        }
456
+        $user = $this->getUserObject($uid, $backend);
457
+        if ($user instanceof IUser) {
458
+            /** @deprecated 21.0.0 use UserCreatedEvent event with the IEventDispatcher instead */
459
+            $this->emit('\OC\User', 'postCreateUser', [$user, $password]);
460
+            $this->eventDispatcher->dispatchTyped(new UserCreatedEvent($user, $password));
461
+        }
462
+        return $user;
463
+    }
464
+
465
+    /**
466
+     * returns how many users per backend exist (if supported by backend)
467
+     *
468
+     * @param boolean $hasLoggedIn when true only users that have a lastLogin
469
+     *                entry in the preferences table will be affected
470
+     * @return array|int an array of backend class as key and count number as value
471
+     *                if $hasLoggedIn is true only an int is returned
472
+     */
473
+    public function countUsers($hasLoggedIn = false) {
474
+        if ($hasLoggedIn) {
475
+            return $this->countSeenUsers();
476
+        }
477
+        $userCountStatistics = [];
478
+        foreach ($this->backends as $backend) {
479
+            if ($backend->implementsActions(Backend::COUNT_USERS)) {
480
+                $backendUsers = $backend->countUsers();
481
+                if ($backendUsers !== false) {
482
+                    if ($backend instanceof IUserBackend) {
483
+                        $name = $backend->getBackendName();
484
+                    } else {
485
+                        $name = get_class($backend);
486
+                    }
487
+                    if (isset($userCountStatistics[$name])) {
488
+                        $userCountStatistics[$name] += $backendUsers;
489
+                    } else {
490
+                        $userCountStatistics[$name] = $backendUsers;
491
+                    }
492
+                }
493
+            }
494
+        }
495
+        return $userCountStatistics;
496
+    }
497
+
498
+    /**
499
+     * returns how many users per backend exist in the requested groups (if supported by backend)
500
+     *
501
+     * @param IGroup[] $groups an array of gid to search in
502
+     * @return array|int an array of backend class as key and count number as value
503
+     *                if $hasLoggedIn is true only an int is returned
504
+     */
505
+    public function countUsersOfGroups(array $groups) {
506
+        $users = [];
507
+        foreach ($groups as $group) {
508
+            $usersIds = array_map(function ($user) {
509
+                return $user->getUID();
510
+            }, $group->getUsers());
511
+            $users = array_merge($users, $usersIds);
512
+        }
513
+        return count(array_unique($users));
514
+    }
515
+
516
+    /**
517
+     * The callback is executed for each user on each backend.
518
+     * If the callback returns false no further users will be retrieved.
519
+     *
520
+     * @param \Closure $callback
521
+     * @param string $search
522
+     * @param boolean $onlySeen when true only users that have a lastLogin entry
523
+     *                in the preferences table will be affected
524
+     * @since 9.0.0
525
+     */
526
+    public function callForAllUsers(\Closure $callback, $search = '', $onlySeen = false) {
527
+        if ($onlySeen) {
528
+            $this->callForSeenUsers($callback);
529
+        } else {
530
+            foreach ($this->getBackends() as $backend) {
531
+                $limit = 500;
532
+                $offset = 0;
533
+                do {
534
+                    $users = $backend->getUsers($search, $limit, $offset);
535
+                    foreach ($users as $uid) {
536
+                        if (!$backend->userExists($uid)) {
537
+                            continue;
538
+                        }
539
+                        $user = $this->getUserObject($uid, $backend, false);
540
+                        $return = $callback($user);
541
+                        if ($return === false) {
542
+                            break;
543
+                        }
544
+                    }
545
+                    $offset += $limit;
546
+                } while (count($users) >= $limit);
547
+            }
548
+        }
549
+    }
550
+
551
+    /**
552
+     * returns how many users are disabled
553
+     *
554
+     * @return int
555
+     * @since 12.0.0
556
+     */
557
+    public function countDisabledUsers(): int {
558
+        $queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
559
+        $queryBuilder->select($queryBuilder->func()->count('*'))
560
+            ->from('preferences')
561
+            ->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('core')))
562
+            ->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('enabled')))
563
+            ->andWhere($queryBuilder->expr()->eq('configvalue', $queryBuilder->createNamedParameter('false'), IQueryBuilder::PARAM_STR));
564
+
565
+
566
+        $result = $queryBuilder->execute();
567
+        $count = $result->fetchOne();
568
+        $result->closeCursor();
569
+
570
+        if ($count !== false) {
571
+            $count = (int)$count;
572
+        } else {
573
+            $count = 0;
574
+        }
575
+
576
+        return $count;
577
+    }
578
+
579
+    /**
580
+     * returns how many users are disabled in the requested groups
581
+     *
582
+     * @param array $groups groupids to search
583
+     * @return int
584
+     * @since 14.0.0
585
+     */
586
+    public function countDisabledUsersOfGroups(array $groups): int {
587
+        $queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
588
+        $queryBuilder->select($queryBuilder->createFunction('COUNT(DISTINCT ' . $queryBuilder->getColumnName('uid') . ')'))
589
+            ->from('preferences', 'p')
590
+            ->innerJoin('p', 'group_user', 'g', $queryBuilder->expr()->eq('p.userid', 'g.uid'))
591
+            ->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('core')))
592
+            ->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('enabled')))
593
+            ->andWhere($queryBuilder->expr()->eq('configvalue', $queryBuilder->createNamedParameter('false'), IQueryBuilder::PARAM_STR))
594
+            ->andWhere($queryBuilder->expr()->in('gid', $queryBuilder->createNamedParameter($groups, IQueryBuilder::PARAM_STR_ARRAY)));
595
+
596
+        $result = $queryBuilder->execute();
597
+        $count = $result->fetchOne();
598
+        $result->closeCursor();
599
+
600
+        if ($count !== false) {
601
+            $count = (int)$count;
602
+        } else {
603
+            $count = 0;
604
+        }
605
+
606
+        return $count;
607
+    }
608
+
609
+    /**
610
+     * returns how many users have logged in once
611
+     *
612
+     * @return int
613
+     * @since 11.0.0
614
+     */
615
+    public function countSeenUsers() {
616
+        $queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
617
+        $queryBuilder->select($queryBuilder->func()->count('*'))
618
+            ->from('preferences')
619
+            ->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('login')))
620
+            ->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('lastLogin')))
621
+            ->andWhere($queryBuilder->expr()->isNotNull('configvalue'));
622
+
623
+        $query = $queryBuilder->execute();
624
+
625
+        $result = (int)$query->fetchOne();
626
+        $query->closeCursor();
627
+
628
+        return $result;
629
+    }
630
+
631
+    /**
632
+     * @param \Closure $callback
633
+     * @psalm-param \Closure(\OCP\IUser):?bool $callback
634
+     * @since 11.0.0
635
+     */
636
+    public function callForSeenUsers(\Closure $callback) {
637
+        $limit = 1000;
638
+        $offset = 0;
639
+        do {
640
+            $userIds = $this->getSeenUserIds($limit, $offset);
641
+            $offset += $limit;
642
+            foreach ($userIds as $userId) {
643
+                foreach ($this->backends as $backend) {
644
+                    if ($backend->userExists($userId)) {
645
+                        $user = $this->getUserObject($userId, $backend, false);
646
+                        $return = $callback($user);
647
+                        if ($return === false) {
648
+                            return;
649
+                        }
650
+                        break;
651
+                    }
652
+                }
653
+            }
654
+        } while (count($userIds) >= $limit);
655
+    }
656
+
657
+    /**
658
+     * Getting all userIds that have a listLogin value requires checking the
659
+     * value in php because on oracle you cannot use a clob in a where clause,
660
+     * preventing us from doing a not null or length(value) > 0 check.
661
+     *
662
+     * @param int $limit
663
+     * @param int $offset
664
+     * @return string[] with user ids
665
+     */
666
+    private function getSeenUserIds($limit = null, $offset = null) {
667
+        $queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
668
+        $queryBuilder->select(['userid'])
669
+            ->from('preferences')
670
+            ->where($queryBuilder->expr()->eq(
671
+                'appid', $queryBuilder->createNamedParameter('login'))
672
+            )
673
+            ->andWhere($queryBuilder->expr()->eq(
674
+                'configkey', $queryBuilder->createNamedParameter('lastLogin'))
675
+            )
676
+            ->andWhere($queryBuilder->expr()->isNotNull('configvalue')
677
+            );
678
+
679
+        if ($limit !== null) {
680
+            $queryBuilder->setMaxResults($limit);
681
+        }
682
+        if ($offset !== null) {
683
+            $queryBuilder->setFirstResult($offset);
684
+        }
685
+        $query = $queryBuilder->execute();
686
+        $result = [];
687
+
688
+        while ($row = $query->fetch()) {
689
+            $result[] = $row['userid'];
690
+        }
691
+
692
+        $query->closeCursor();
693
+
694
+        return $result;
695
+    }
696
+
697
+    /**
698
+     * @param string $email
699
+     * @return IUser[]
700
+     * @since 9.1.0
701
+     */
702
+    public function getByEmail($email) {
703
+        $userIds = $this->config->getUsersForUserValueCaseInsensitive('settings', 'email', $email);
704
+
705
+        $users = array_map(function ($uid) {
706
+            return $this->get($uid);
707
+        }, $userIds);
708
+
709
+        return array_values(array_filter($users, function ($u) {
710
+            return ($u instanceof IUser);
711
+        }));
712
+    }
713
+
714
+    private function verifyUid(string $uid): bool {
715
+        $appdata = 'appdata_' . $this->config->getSystemValueString('instanceid');
716
+
717
+        if (\in_array($uid, [
718
+            '.htaccess',
719
+            'files_external',
720
+            '__groupfolders',
721
+            '.ocdata',
722
+            'owncloud.log',
723
+            'nextcloud.log',
724
+            $appdata], true)) {
725
+            return false;
726
+        }
727
+
728
+        $dataDirectory = $this->config->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data');
729
+
730
+        return !file_exists(rtrim($dataDirectory, '/') . '/' . $uid);
731
+    }
732 732
 }
Please login to merge, or discard this patch.
Spacing   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -101,7 +101,7 @@  discard block
 block discarded – undo
101 101
 		$this->dispatcher = $oldDispatcher;
102 102
 		$this->cache = $cacheFactory->createDistributed('user_backend_map');
103 103
 		$cachedUsers = &$this->cachedUsers;
104
-		$this->listen('\OC\User', 'postDelete', function ($user) use (&$cachedUsers) {
104
+		$this->listen('\OC\User', 'postDelete', function($user) use (&$cachedUsers) {
105 105
 			/** @var \OC\User\User $user */
106 106
 			unset($cachedUsers[$user->getUID()]);
107 107
 		});
@@ -228,7 +228,7 @@  discard block
 block discarded – undo
228 228
 		$result = $this->checkPasswordNoLogging($loginName, $password);
229 229
 
230 230
 		if ($result === false) {
231
-			\OC::$server->getLogger()->warning('Login failed: \''. $loginName .'\' (Remote IP: \''. \OC::$server->getRequest()->getRemoteAddress(). '\')', ['app' => 'core']);
231
+			\OC::$server->getLogger()->warning('Login failed: \''.$loginName.'\' (Remote IP: \''.\OC::$server->getRequest()->getRemoteAddress().'\')', ['app' => 'core']);
232 232
 		}
233 233
 
234 234
 		return $result;
@@ -291,7 +291,7 @@  discard block
 block discarded – undo
291 291
 			}
292 292
 		}
293 293
 
294
-		uasort($users, function ($a, $b) {
294
+		uasort($users, function($a, $b) {
295 295
 			/**
296 296
 			 * @var \OC\User\User $a
297 297
 			 * @var \OC\User\User $b
@@ -320,7 +320,7 @@  discard block
 block discarded – undo
320 320
 			}
321 321
 		}
322 322
 
323
-		usort($users, function ($a, $b) {
323
+		usort($users, function($a, $b) {
324 324
 			/**
325 325
 			 * @var \OC\User\User $a
326 326
 			 * @var \OC\User\User $b
@@ -355,7 +355,7 @@  discard block
 block discarded – undo
355 355
 			}
356 356
 		}
357 357
 
358
-		usort($users, function ($a, $b) {
358
+		usort($users, function($a, $b) {
359 359
 			/**
360 360
 			 * @var IUser $a
361 361
 			 * @var IUser $b
@@ -505,7 +505,7 @@  discard block
 block discarded – undo
505 505
 	public function countUsersOfGroups(array $groups) {
506 506
 		$users = [];
507 507
 		foreach ($groups as $group) {
508
-			$usersIds = array_map(function ($user) {
508
+			$usersIds = array_map(function($user) {
509 509
 				return $user->getUID();
510 510
 			}, $group->getUsers());
511 511
 			$users = array_merge($users, $usersIds);
@@ -568,7 +568,7 @@  discard block
 block discarded – undo
568 568
 		$result->closeCursor();
569 569
 
570 570
 		if ($count !== false) {
571
-			$count = (int)$count;
571
+			$count = (int) $count;
572 572
 		} else {
573 573
 			$count = 0;
574 574
 		}
@@ -585,7 +585,7 @@  discard block
 block discarded – undo
585 585
 	 */
586 586
 	public function countDisabledUsersOfGroups(array $groups): int {
587 587
 		$queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
588
-		$queryBuilder->select($queryBuilder->createFunction('COUNT(DISTINCT ' . $queryBuilder->getColumnName('uid') . ')'))
588
+		$queryBuilder->select($queryBuilder->createFunction('COUNT(DISTINCT '.$queryBuilder->getColumnName('uid').')'))
589 589
 			->from('preferences', 'p')
590 590
 			->innerJoin('p', 'group_user', 'g', $queryBuilder->expr()->eq('p.userid', 'g.uid'))
591 591
 			->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('core')))
@@ -598,7 +598,7 @@  discard block
 block discarded – undo
598 598
 		$result->closeCursor();
599 599
 
600 600
 		if ($count !== false) {
601
-			$count = (int)$count;
601
+			$count = (int) $count;
602 602
 		} else {
603 603
 			$count = 0;
604 604
 		}
@@ -622,7 +622,7 @@  discard block
 block discarded – undo
622 622
 
623 623
 		$query = $queryBuilder->execute();
624 624
 
625
-		$result = (int)$query->fetchOne();
625
+		$result = (int) $query->fetchOne();
626 626
 		$query->closeCursor();
627 627
 
628 628
 		return $result;
@@ -702,17 +702,17 @@  discard block
 block discarded – undo
702 702
 	public function getByEmail($email) {
703 703
 		$userIds = $this->config->getUsersForUserValueCaseInsensitive('settings', 'email', $email);
704 704
 
705
-		$users = array_map(function ($uid) {
705
+		$users = array_map(function($uid) {
706 706
 			return $this->get($uid);
707 707
 		}, $userIds);
708 708
 
709
-		return array_values(array_filter($users, function ($u) {
709
+		return array_values(array_filter($users, function($u) {
710 710
 			return ($u instanceof IUser);
711 711
 		}));
712 712
 	}
713 713
 
714 714
 	private function verifyUid(string $uid): bool {
715
-		$appdata = 'appdata_' . $this->config->getSystemValueString('instanceid');
715
+		$appdata = 'appdata_'.$this->config->getSystemValueString('instanceid');
716 716
 
717 717
 		if (\in_array($uid, [
718 718
 			'.htaccess',
@@ -725,8 +725,8 @@  discard block
 block discarded – undo
725 725
 			return false;
726 726
 		}
727 727
 
728
-		$dataDirectory = $this->config->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data');
728
+		$dataDirectory = $this->config->getSystemValueString('datadirectory', \OC::$SERVERROOT.'/data');
729 729
 
730
-		return !file_exists(rtrim($dataDirectory, '/') . '/' . $uid);
730
+		return !file_exists(rtrim($dataDirectory, '/').'/'.$uid);
731 731
 	}
732 732
 }
Please login to merge, or discard this patch.