Passed
Push — master ( 9bf55c...e105d1 )
by Blizzz
11:12 queued 10s
created
apps/user_ldap/lib/User/User.php 2 patches
Indentation   +722 added lines, -722 removed lines patch added patch discarded remove patch
@@ -49,732 +49,732 @@
 block discarded – undo
49 49
  * represents an LDAP user, gets and holds user-specific information from LDAP
50 50
  */
51 51
 class User {
52
-	/**
53
-	 * @var Access
54
-	 */
55
-	protected $access;
56
-	/**
57
-	 * @var Connection
58
-	 */
59
-	protected $connection;
60
-	/**
61
-	 * @var IConfig
62
-	 */
63
-	protected $config;
64
-	/**
65
-	 * @var FilesystemHelper
66
-	 */
67
-	protected $fs;
68
-	/**
69
-	 * @var Image
70
-	 */
71
-	protected $image;
72
-	/**
73
-	 * @var LogWrapper
74
-	 */
75
-	protected $log;
76
-	/**
77
-	 * @var IAvatarManager
78
-	 */
79
-	protected $avatarManager;
80
-	/**
81
-	 * @var IUserManager
82
-	 */
83
-	protected $userManager;
84
-	/**
85
-	 * @var INotificationManager
86
-	 */
87
-	protected $notificationManager;
88
-	/**
89
-	 * @var string
90
-	 */
91
-	protected $dn;
92
-	/**
93
-	 * @var string
94
-	 */
95
-	protected $uid;
96
-	/**
97
-	 * @var string[]
98
-	 */
99
-	protected $refreshedFeatures = array();
100
-	/**
101
-	 * @var string
102
-	 */
103
-	protected $avatarImage;
104
-
105
-	/**
106
-	 * DB config keys for user preferences
107
-	 */
108
-	const USER_PREFKEY_FIRSTLOGIN  = 'firstLoginAccomplished';
109
-	const USER_PREFKEY_LASTREFRESH = 'lastFeatureRefresh';
110
-
111
-	/**
112
-	 * @brief constructor, make sure the subclasses call this one!
113
-	 * @param string $username the internal username
114
-	 * @param string $dn the LDAP DN
115
-	 * @param Access $access
116
-	 * @param IConfig $config
117
-	 * @param FilesystemHelper $fs
118
-	 * @param Image $image any empty instance
119
-	 * @param LogWrapper $log
120
-	 * @param IAvatarManager $avatarManager
121
-	 * @param IUserManager $userManager
122
-	 * @param INotificationManager $notificationManager
123
-	 */
124
-	public function __construct($username, $dn, Access $access,
125
-		IConfig $config, FilesystemHelper $fs, Image $image,
126
-		LogWrapper $log, IAvatarManager $avatarManager, IUserManager $userManager,
127
-		INotificationManager $notificationManager) {
52
+    /**
53
+     * @var Access
54
+     */
55
+    protected $access;
56
+    /**
57
+     * @var Connection
58
+     */
59
+    protected $connection;
60
+    /**
61
+     * @var IConfig
62
+     */
63
+    protected $config;
64
+    /**
65
+     * @var FilesystemHelper
66
+     */
67
+    protected $fs;
68
+    /**
69
+     * @var Image
70
+     */
71
+    protected $image;
72
+    /**
73
+     * @var LogWrapper
74
+     */
75
+    protected $log;
76
+    /**
77
+     * @var IAvatarManager
78
+     */
79
+    protected $avatarManager;
80
+    /**
81
+     * @var IUserManager
82
+     */
83
+    protected $userManager;
84
+    /**
85
+     * @var INotificationManager
86
+     */
87
+    protected $notificationManager;
88
+    /**
89
+     * @var string
90
+     */
91
+    protected $dn;
92
+    /**
93
+     * @var string
94
+     */
95
+    protected $uid;
96
+    /**
97
+     * @var string[]
98
+     */
99
+    protected $refreshedFeatures = array();
100
+    /**
101
+     * @var string
102
+     */
103
+    protected $avatarImage;
104
+
105
+    /**
106
+     * DB config keys for user preferences
107
+     */
108
+    const USER_PREFKEY_FIRSTLOGIN  = 'firstLoginAccomplished';
109
+    const USER_PREFKEY_LASTREFRESH = 'lastFeatureRefresh';
110
+
111
+    /**
112
+     * @brief constructor, make sure the subclasses call this one!
113
+     * @param string $username the internal username
114
+     * @param string $dn the LDAP DN
115
+     * @param Access $access
116
+     * @param IConfig $config
117
+     * @param FilesystemHelper $fs
118
+     * @param Image $image any empty instance
119
+     * @param LogWrapper $log
120
+     * @param IAvatarManager $avatarManager
121
+     * @param IUserManager $userManager
122
+     * @param INotificationManager $notificationManager
123
+     */
124
+    public function __construct($username, $dn, Access $access,
125
+        IConfig $config, FilesystemHelper $fs, Image $image,
126
+        LogWrapper $log, IAvatarManager $avatarManager, IUserManager $userManager,
127
+        INotificationManager $notificationManager) {
128 128
 	
129
-		if ($username === null) {
130
-			$log->log("uid for '$dn' must not be null!", ILogger::ERROR);
131
-			throw new \InvalidArgumentException('uid must not be null!');
132
-		} else if ($username === '') {
133
-			$log->log("uid for '$dn' must not be an empty string", ILogger::ERROR);
134
-			throw new \InvalidArgumentException('uid must not be an empty string!');
135
-		}
136
-
137
-		$this->access              = $access;
138
-		$this->connection          = $access->getConnection();
139
-		$this->config              = $config;
140
-		$this->fs                  = $fs;
141
-		$this->dn                  = $dn;
142
-		$this->uid                 = $username;
143
-		$this->image               = $image;
144
-		$this->log                 = $log;
145
-		$this->avatarManager       = $avatarManager;
146
-		$this->userManager         = $userManager;
147
-		$this->notificationManager = $notificationManager;
148
-
149
-		\OCP\Util::connectHook('OC_User', 'post_login', $this, 'handlePasswordExpiry');
150
-	}
151
-
152
-	/**
153
-	 * @brief updates properties like email, quota or avatar provided by LDAP
154
-	 * @return null
155
-	 */
156
-	public function update() {
157
-		if(is_null($this->dn)) {
158
-			return null;
159
-		}
160
-
161
-		$hasLoggedIn = $this->config->getUserValue($this->uid, 'user_ldap',
162
-				self::USER_PREFKEY_FIRSTLOGIN, 0);
163
-
164
-		if($this->needsRefresh()) {
165
-			$this->updateEmail();
166
-			$this->updateQuota();
167
-			if($hasLoggedIn !== 0) {
168
-				//we do not need to try it, when the user has not been logged in
169
-				//before, because the file system will not be ready.
170
-				$this->updateAvatar();
171
-				//in order to get an avatar as soon as possible, mark the user
172
-				//as refreshed only when updating the avatar did happen
173
-				$this->markRefreshTime();
174
-			}
175
-		}
176
-	}
177
-
178
-	/**
179
-	 * processes results from LDAP for attributes as returned by getAttributesToRead()
180
-	 * @param array $ldapEntry the user entry as retrieved from LDAP
181
-	 */
182
-	public function processAttributes($ldapEntry) {
183
-		$this->markRefreshTime();
184
-		//Quota
185
-		$attr = strtolower($this->connection->ldapQuotaAttribute);
186
-		if(isset($ldapEntry[$attr])) {
187
-			$this->updateQuota($ldapEntry[$attr][0]);
188
-		} else {
189
-			if ($this->connection->ldapQuotaDefault !== '') {
190
-				$this->updateQuota();
191
-			}
192
-		}
193
-		unset($attr);
194
-
195
-		//displayName
196
-		$displayName = $displayName2 = '';
197
-		$attr = strtolower($this->connection->ldapUserDisplayName);
198
-		if(isset($ldapEntry[$attr])) {
199
-			$displayName = (string)$ldapEntry[$attr][0];
200
-		}
201
-		$attr = strtolower($this->connection->ldapUserDisplayName2);
202
-		if(isset($ldapEntry[$attr])) {
203
-			$displayName2 = (string)$ldapEntry[$attr][0];
204
-		}
205
-		if ($displayName !== '') {
206
-			$this->composeAndStoreDisplayName($displayName, $displayName2);
207
-			$this->access->cacheUserDisplayName(
208
-				$this->getUsername(),
209
-				$displayName,
210
-				$displayName2
211
-			);
212
-		}
213
-		unset($attr);
214
-
215
-		//Email
216
-		//email must be stored after displayname, because it would cause a user
217
-		//change event that will trigger fetching the display name again
218
-		$attr = strtolower($this->connection->ldapEmailAttribute);
219
-		if(isset($ldapEntry[$attr])) {
220
-			$this->updateEmail($ldapEntry[$attr][0]);
221
-		}
222
-		unset($attr);
223
-
224
-		// LDAP Username, needed for s2s sharing
225
-		if(isset($ldapEntry['uid'])) {
226
-			$this->storeLDAPUserName($ldapEntry['uid'][0]);
227
-		} else if(isset($ldapEntry['samaccountname'])) {
228
-			$this->storeLDAPUserName($ldapEntry['samaccountname'][0]);
229
-		}
230
-
231
-		//homePath
232
-		if(strpos($this->connection->homeFolderNamingRule, 'attr:') === 0) {
233
-			$attr = strtolower(substr($this->connection->homeFolderNamingRule, strlen('attr:')));
234
-			if(isset($ldapEntry[$attr])) {
235
-				$this->access->cacheUserHome(
236
-					$this->getUsername(), $this->getHomePath($ldapEntry[$attr][0]));
237
-			}
238
-		}
239
-
240
-		//memberOf groups
241
-		$cacheKey = 'getMemberOf'.$this->getUsername();
242
-		$groups = false;
243
-		if(isset($ldapEntry['memberof'])) {
244
-			$groups = $ldapEntry['memberof'];
245
-		}
246
-		$this->connection->writeToCache($cacheKey, $groups);
247
-
248
-		//external storage var
249
-		$attr = strtolower($this->connection->ldapExtStorageHomeAttribute);
250
-		if(isset($ldapEntry[$attr])) {
251
-			$this->updateExtStorageHome($ldapEntry[$attr][0]);
252
-		}
253
-		unset($attr);
254
-
255
-		//Avatar
256
-		/** @var Connection $connection */
257
-		$connection = $this->access->getConnection();
258
-		$attributes = $connection->resolveRule('avatar');
259
-		foreach ($attributes as $attribute)  {
260
-			if(isset($ldapEntry[$attribute])) {
261
-				$this->avatarImage = $ldapEntry[$attribute][0];
262
-				// the call to the method that saves the avatar in the file
263
-				// system must be postponed after the login. It is to ensure
264
-				// external mounts are mounted properly (e.g. with login
265
-				// credentials from the session).
266
-				\OCP\Util::connectHook('OC_User', 'post_login', $this, 'updateAvatarPostLogin');
267
-				break;
268
-			}
269
-		}
270
-	}
271
-
272
-	/**
273
-	 * @brief returns the LDAP DN of the user
274
-	 * @return string
275
-	 */
276
-	public function getDN() {
277
-		return $this->dn;
278
-	}
279
-
280
-	/**
281
-	 * @brief returns the Nextcloud internal username of the user
282
-	 * @return string
283
-	 */
284
-	public function getUsername() {
285
-		return $this->uid;
286
-	}
287
-
288
-	/**
289
-	 * returns the home directory of the user if specified by LDAP settings
290
-	 * @param string $valueFromLDAP
291
-	 * @return bool|string
292
-	 * @throws \Exception
293
-	 */
294
-	public function getHomePath($valueFromLDAP = null) {
295
-		$path = (string)$valueFromLDAP;
296
-		$attr = null;
297
-
298
-		if (is_null($valueFromLDAP)
299
-		   && strpos($this->access->connection->homeFolderNamingRule, 'attr:') === 0
300
-		   && $this->access->connection->homeFolderNamingRule !== 'attr:')
301
-		{
302
-			$attr = substr($this->access->connection->homeFolderNamingRule, strlen('attr:'));
303
-			$homedir = $this->access->readAttribute(
304
-				$this->access->username2dn($this->getUsername()), $attr);
305
-			if ($homedir && isset($homedir[0])) {
306
-				$path = $homedir[0];
307
-			}
308
-		}
309
-
310
-		if ($path !== '') {
311
-			//if attribute's value is an absolute path take this, otherwise append it to data dir
312
-			//check for / at the beginning or pattern c:\ resp. c:/
313
-			if(   '/' !== $path[0]
314
-			   && !(3 < strlen($path) && ctype_alpha($path[0])
315
-			       && $path[1] === ':' && ('\\' === $path[2] || '/' === $path[2]))
316
-			) {
317
-				$path = $this->config->getSystemValue('datadirectory',
318
-						\OC::$SERVERROOT.'/data' ) . '/' . $path;
319
-			}
320
-			//we need it to store it in the DB as well in case a user gets
321
-			//deleted so we can clean up afterwards
322
-			$this->config->setUserValue(
323
-				$this->getUsername(), 'user_ldap', 'homePath', $path
324
-			);
325
-			return $path;
326
-		}
327
-
328
-		if(    !is_null($attr)
329
-			&& $this->config->getAppValue('user_ldap', 'enforce_home_folder_naming_rule', true)
330
-		) {
331
-			// a naming rule attribute is defined, but it doesn't exist for that LDAP user
332
-			throw new \Exception('Home dir attribute can\'t be read from LDAP for uid: ' . $this->getUsername());
333
-		}
334
-
335
-		//false will apply default behaviour as defined and done by OC_User
336
-		$this->config->setUserValue($this->getUsername(), 'user_ldap', 'homePath', '');
337
-		return false;
338
-	}
339
-
340
-	public function getMemberOfGroups() {
341
-		$cacheKey = 'getMemberOf'.$this->getUsername();
342
-		$memberOfGroups = $this->connection->getFromCache($cacheKey);
343
-		if(!is_null($memberOfGroups)) {
344
-			return $memberOfGroups;
345
-		}
346
-		$groupDNs = $this->access->readAttribute($this->getDN(), 'memberOf');
347
-		$this->connection->writeToCache($cacheKey, $groupDNs);
348
-		return $groupDNs;
349
-	}
350
-
351
-	/**
352
-	 * @brief reads the image from LDAP that shall be used as Avatar
353
-	 * @return string data (provided by LDAP) | false
354
-	 */
355
-	public function getAvatarImage() {
356
-		if(!is_null($this->avatarImage)) {
357
-			return $this->avatarImage;
358
-		}
359
-
360
-		$this->avatarImage = false;
361
-		/** @var Connection $connection */
362
-		$connection = $this->access->getConnection();
363
-		$attributes = $connection->resolveRule('avatar');
364
-		foreach($attributes as $attribute) {
365
-			$result = $this->access->readAttribute($this->dn, $attribute);
366
-			if($result !== false && is_array($result) && isset($result[0])) {
367
-				$this->avatarImage = $result[0];
368
-				break;
369
-			}
370
-		}
371
-
372
-		return $this->avatarImage;
373
-	}
374
-
375
-	/**
376
-	 * @brief marks the user as having logged in at least once
377
-	 * @return null
378
-	 */
379
-	public function markLogin() {
380
-		$this->config->setUserValue(
381
-			$this->uid, 'user_ldap', self::USER_PREFKEY_FIRSTLOGIN, 1);
382
-	}
383
-
384
-	/**
385
-	 * @brief marks the time when user features like email have been updated
386
-	 * @return null
387
-	 */
388
-	public function markRefreshTime() {
389
-		$this->config->setUserValue(
390
-			$this->uid, 'user_ldap', self::USER_PREFKEY_LASTREFRESH, time());
391
-	}
392
-
393
-	/**
394
-	 * @brief checks whether user features needs to be updated again by
395
-	 * comparing the difference of time of the last refresh to now with the
396
-	 * desired interval
397
-	 * @return bool
398
-	 */
399
-	private function needsRefresh() {
400
-		$lastChecked = $this->config->getUserValue($this->uid, 'user_ldap',
401
-			self::USER_PREFKEY_LASTREFRESH, 0);
402
-
403
-		if((time() - (int)$lastChecked) < (int)$this->config->getAppValue('user_ldap', 'updateAttributesInterval', 86400)) {
404
-			return false;
405
-		}
406
-		return  true;
407
-	}
408
-
409
-	/**
410
-	 * Stores a key-value pair in relation to this user
411
-	 *
412
-	 * @param string $key
413
-	 * @param string $value
414
-	 */
415
-	private function store($key, $value) {
416
-		$this->config->setUserValue($this->uid, 'user_ldap', $key, $value);
417
-	}
418
-
419
-	/**
420
-	 * Composes the display name and stores it in the database. The final
421
-	 * display name is returned.
422
-	 *
423
-	 * @param string $displayName
424
-	 * @param string $displayName2
425
-	 * @return string the effective display name
426
-	 */
427
-	public function composeAndStoreDisplayName($displayName, $displayName2 = '') {
428
-		$displayName2 = (string)$displayName2;
429
-		if($displayName2 !== '') {
430
-			$displayName .= ' (' . $displayName2 . ')';
431
-		}
432
-		$oldName = $this->config->getUserValue($this->uid, 'user_ldap', 'displayName', null);
433
-		if ($oldName !== $displayName)  {
434
-			$this->store('displayName', $displayName);
435
-			$user = $this->userManager->get($this->getUsername());
436
-			if (!empty($oldName) && $user instanceof \OC\User\User) {
437
-				// if it was empty, it would be a new record, not a change emitting the trigger could
438
-				// potentially cause a UniqueConstraintViolationException, depending on some factors.
439
-				$user->triggerChange('displayName', $displayName, $oldName);
440
-			}
441
-		}
442
-		return $displayName;
443
-	}
444
-
445
-	/**
446
-	 * Stores the LDAP Username in the Database
447
-	 * @param string $userName
448
-	 */
449
-	public function storeLDAPUserName($userName) {
450
-		$this->store('uid', $userName);
451
-	}
452
-
453
-	/**
454
-	 * @brief checks whether an update method specified by feature was run
455
-	 * already. If not, it will marked like this, because it is expected that
456
-	 * the method will be run, when false is returned.
457
-	 * @param string $feature email | quota | avatar (can be extended)
458
-	 * @return bool
459
-	 */
460
-	private function wasRefreshed($feature) {
461
-		if(isset($this->refreshedFeatures[$feature])) {
462
-			return true;
463
-		}
464
-		$this->refreshedFeatures[$feature] = 1;
465
-		return false;
466
-	}
467
-
468
-	/**
469
-	 * fetches the email from LDAP and stores it as Nextcloud user value
470
-	 * @param string $valueFromLDAP if known, to save an LDAP read request
471
-	 * @return null
472
-	 */
473
-	public function updateEmail($valueFromLDAP = null) {
474
-		if($this->wasRefreshed('email')) {
475
-			return;
476
-		}
477
-		$email = (string)$valueFromLDAP;
478
-		if(is_null($valueFromLDAP)) {
479
-			$emailAttribute = $this->connection->ldapEmailAttribute;
480
-			if ($emailAttribute !== '') {
481
-				$aEmail = $this->access->readAttribute($this->dn, $emailAttribute);
482
-				if(is_array($aEmail) && (count($aEmail) > 0)) {
483
-					$email = (string)$aEmail[0];
484
-				}
485
-			}
486
-		}
487
-		if ($email !== '') {
488
-			$user = $this->userManager->get($this->uid);
489
-			if (!is_null($user)) {
490
-				$currentEmail = (string)$user->getEMailAddress();
491
-				if ($currentEmail !== $email) {
492
-					$user->setEMailAddress($email);
493
-				}
494
-			}
495
-		}
496
-	}
497
-
498
-	/**
499
-	 * Overall process goes as follow:
500
-	 * 1. fetch the quota from LDAP and check if it's parseable with the "verifyQuotaValue" function
501
-	 * 2. if the value can't be fetched, is empty or not parseable, use the default LDAP quota
502
-	 * 3. if the default LDAP quota can't be parsed, use the Nextcloud's default quota (use 'default')
503
-	 * 4. check if the target user exists and set the quota for the user.
504
-	 *
505
-	 * In order to improve performance and prevent an unwanted extra LDAP call, the $valueFromLDAP
506
-	 * parameter can be passed with the value of the attribute. This value will be considered as the
507
-	 * quota for the user coming from the LDAP server (step 1 of the process) It can be useful to
508
-	 * fetch all the user's attributes in one call and use the fetched values in this function.
509
-	 * The expected value for that parameter is a string describing the quota for the user. Valid
510
-	 * values are 'none' (unlimited), 'default' (the Nextcloud's default quota), '1234' (quota in
511
-	 * bytes), '1234 MB' (quota in MB - check the \OC_Helper::computerFileSize method for more info)
512
-	 *
513
-	 * fetches the quota from LDAP and stores it as Nextcloud user value
514
-	 * @param string $valueFromLDAP the quota attribute's value can be passed,
515
-	 * to save the readAttribute request
516
-	 * @return null
517
-	 */
518
-	public function updateQuota($valueFromLDAP = null) {
519
-		if($this->wasRefreshed('quota')) {
520
-			return;
521
-		}
522
-
523
-		$quotaAttribute = $this->connection->ldapQuotaAttribute;
524
-		$defaultQuota = $this->connection->ldapQuotaDefault;
525
-		if($quotaAttribute === '' && $defaultQuota === '') {
526
-			return;
527
-		}
528
-
529
-		$quota = false;
530
-		if(is_null($valueFromLDAP) && $quotaAttribute !== '') {
531
-			$aQuota = $this->access->readAttribute($this->dn, $quotaAttribute);
532
-			if($aQuota && (count($aQuota) > 0) && $this->verifyQuotaValue($aQuota[0])) {
533
-				$quota = $aQuota[0];
534
-			} else if(is_array($aQuota) && isset($aQuota[0])) {
535
-				$this->log->log('no suitable LDAP quota found for user ' . $this->uid . ': [' . $aQuota[0] . ']', ILogger::DEBUG);
536
-			}
537
-		} else if ($this->verifyQuotaValue($valueFromLDAP)) {
538
-			$quota = $valueFromLDAP;
539
-		} else {
540
-			$this->log->log('no suitable LDAP quota found for user ' . $this->uid . ': [' . $valueFromLDAP . ']', ILogger::DEBUG);
541
-		}
542
-
543
-		if ($quota === false && $this->verifyQuotaValue($defaultQuota)) {
544
-			// quota not found using the LDAP attribute (or not parseable). Try the default quota
545
-			$quota = $defaultQuota;
546
-		} else if($quota === false) {
547
-			$this->log->log('no suitable default quota found for user ' . $this->uid . ': [' . $defaultQuota . ']', ILogger::DEBUG);
548
-			return;
549
-		}
550
-
551
-		$targetUser = $this->userManager->get($this->uid);
552
-		if ($targetUser instanceof IUser) {
553
-			$targetUser->setQuota($quota);
554
-		} else {
555
-			$this->log->log('trying to set a quota for user ' . $this->uid . ' but the user is missing', ILogger::INFO);
556
-		}
557
-	}
558
-
559
-	private function verifyQuotaValue($quotaValue) {
560
-		return $quotaValue === 'none' || $quotaValue === 'default' || \OC_Helper::computerFileSize($quotaValue) !== false;
561
-	}
562
-
563
-	/**
564
-	 * called by a post_login hook to save the avatar picture
565
-	 *
566
-	 * @param array $params
567
-	 */
568
-	public function updateAvatarPostLogin($params) {
569
-		if(isset($params['uid']) && $params['uid'] === $this->getUsername()) {
570
-			$this->updateAvatar();
571
-		}
572
-	}
573
-
574
-	/**
575
-	 * @brief attempts to get an image from LDAP and sets it as Nextcloud avatar
576
-	 * @return bool
577
-	 */
578
-	public function updateAvatar($force = false) {
579
-		if(!$force && $this->wasRefreshed('avatar')) {
580
-			return false;
581
-		}
582
-		$avatarImage = $this->getAvatarImage();
583
-		if($avatarImage === false) {
584
-			//not set, nothing left to do;
585
-			return false;
586
-		}
587
-
588
-		if(!$this->image->loadFromBase64(base64_encode($avatarImage))) {
589
-			return false;
590
-		}
591
-
592
-		// use the checksum before modifications
593
-		$checksum = md5($this->image->data());
594
-
595
-		if($checksum === $this->config->getUserValue($this->uid, 'user_ldap', 'lastAvatarChecksum', '')) {
596
-			return true;
597
-		}
598
-
599
-		$isSet = $this->setOwnCloudAvatar();
600
-
601
-		if($isSet) {
602
-			// save checksum only after successful setting
603
-			$this->config->setUserValue($this->uid, 'user_ldap', 'lastAvatarChecksum', $checksum);
604
-		}
605
-
606
-		return $isSet;
607
-	}
608
-
609
-	/**
610
-	 * @brief sets an image as Nextcloud avatar
611
-	 * @return bool
612
-	 */
613
-	private function setOwnCloudAvatar() {
614
-		if(!$this->image->valid()) {
615
-			$this->log->log('avatar image data from LDAP invalid for '.$this->dn, ILogger::ERROR);
616
-			return false;
617
-		}
618
-
619
-
620
-		//make sure it is a square and not bigger than 128x128
621
-		$size = min([$this->image->width(), $this->image->height(), 128]);
622
-		if(!$this->image->centerCrop($size)) {
623
-			$this->log->log('croping image for avatar failed for '.$this->dn, ILogger::ERROR);
624
-			return false;
625
-		}
626
-
627
-		if(!$this->fs->isLoaded()) {
628
-			$this->fs->setup($this->uid);
629
-		}
630
-
631
-		try {
632
-			$avatar = $this->avatarManager->getAvatar($this->uid);
633
-			$avatar->set($this->image);
634
-			return true;
635
-		} catch (\Exception $e) {
636
-			\OC::$server->getLogger()->logException($e, [
637
-				'message' => 'Could not set avatar for ' . $this->dn,
638
-				'level' => ILogger::INFO,
639
-				'app' => 'user_ldap',
640
-			]);
641
-		}
642
-		return false;
643
-	}
644
-
645
-	/**
646
-	 * @throws AttributeNotSet
647
-	 * @throws \OC\ServerNotAvailableException
648
-	 * @throws \OCP\PreConditionNotMetException
649
-	 */
650
-	public function getExtStorageHome():string {
651
-		$value = $this->config->getUserValue($this->getUsername(), 'user_ldap', 'extStorageHome', '');
652
-		if ($value !== '') {
653
-			return $value;
654
-		}
655
-
656
-		$value = $this->updateExtStorageHome();
657
-		if ($value !== '') {
658
-			return $value;
659
-		}
660
-
661
-		throw new AttributeNotSet(sprintf(
662
-			'external home storage attribute yield no value for %s', $this->getUsername()
663
-		));
664
-	}
665
-
666
-	/**
667
-	 * @throws \OCP\PreConditionNotMetException
668
-	 * @throws \OC\ServerNotAvailableException
669
-	 */
670
-	public function updateExtStorageHome(string $valueFromLDAP = null):string {
671
-		if($valueFromLDAP === null) {
672
-			$extHomeValues = $this->access->readAttribute($this->getDN(), $this->connection->ldapExtStorageHomeAttribute);
673
-		} else {
674
-			$extHomeValues = [$valueFromLDAP];
675
-		}
676
-		if ($extHomeValues && isset($extHomeValues[0])) {
677
-			$extHome = $extHomeValues[0];
678
-			$this->config->setUserValue($this->getUsername(), 'user_ldap', 'extStorageHome', $extHome);
679
-			return $extHome;
680
-		} else {
681
-			$this->config->deleteUserValue($this->getUsername(), 'user_ldap', 'extStorageHome');
682
-			return '';
683
-		}
684
-	}
685
-
686
-	/**
687
-	 * called by a post_login hook to handle password expiry
688
-	 *
689
-	 * @param array $params
690
-	 */
691
-	public function handlePasswordExpiry($params) {
692
-		$ppolicyDN = $this->connection->ldapDefaultPPolicyDN;
693
-		if (empty($ppolicyDN) || ((int)$this->connection->turnOnPasswordChange !== 1)) {
694
-			return;//password expiry handling disabled
695
-		}
696
-		$uid = $params['uid'];
697
-		if(isset($uid) && $uid === $this->getUsername()) {
698
-			//retrieve relevant user attributes
699
-			$result = $this->access->search('objectclass=*', array($this->dn), ['pwdpolicysubentry', 'pwdgraceusetime', 'pwdreset', 'pwdchangedtime']);
129
+        if ($username === null) {
130
+            $log->log("uid for '$dn' must not be null!", ILogger::ERROR);
131
+            throw new \InvalidArgumentException('uid must not be null!');
132
+        } else if ($username === '') {
133
+            $log->log("uid for '$dn' must not be an empty string", ILogger::ERROR);
134
+            throw new \InvalidArgumentException('uid must not be an empty string!');
135
+        }
136
+
137
+        $this->access              = $access;
138
+        $this->connection          = $access->getConnection();
139
+        $this->config              = $config;
140
+        $this->fs                  = $fs;
141
+        $this->dn                  = $dn;
142
+        $this->uid                 = $username;
143
+        $this->image               = $image;
144
+        $this->log                 = $log;
145
+        $this->avatarManager       = $avatarManager;
146
+        $this->userManager         = $userManager;
147
+        $this->notificationManager = $notificationManager;
148
+
149
+        \OCP\Util::connectHook('OC_User', 'post_login', $this, 'handlePasswordExpiry');
150
+    }
151
+
152
+    /**
153
+     * @brief updates properties like email, quota or avatar provided by LDAP
154
+     * @return null
155
+     */
156
+    public function update() {
157
+        if(is_null($this->dn)) {
158
+            return null;
159
+        }
160
+
161
+        $hasLoggedIn = $this->config->getUserValue($this->uid, 'user_ldap',
162
+                self::USER_PREFKEY_FIRSTLOGIN, 0);
163
+
164
+        if($this->needsRefresh()) {
165
+            $this->updateEmail();
166
+            $this->updateQuota();
167
+            if($hasLoggedIn !== 0) {
168
+                //we do not need to try it, when the user has not been logged in
169
+                //before, because the file system will not be ready.
170
+                $this->updateAvatar();
171
+                //in order to get an avatar as soon as possible, mark the user
172
+                //as refreshed only when updating the avatar did happen
173
+                $this->markRefreshTime();
174
+            }
175
+        }
176
+    }
177
+
178
+    /**
179
+     * processes results from LDAP for attributes as returned by getAttributesToRead()
180
+     * @param array $ldapEntry the user entry as retrieved from LDAP
181
+     */
182
+    public function processAttributes($ldapEntry) {
183
+        $this->markRefreshTime();
184
+        //Quota
185
+        $attr = strtolower($this->connection->ldapQuotaAttribute);
186
+        if(isset($ldapEntry[$attr])) {
187
+            $this->updateQuota($ldapEntry[$attr][0]);
188
+        } else {
189
+            if ($this->connection->ldapQuotaDefault !== '') {
190
+                $this->updateQuota();
191
+            }
192
+        }
193
+        unset($attr);
194
+
195
+        //displayName
196
+        $displayName = $displayName2 = '';
197
+        $attr = strtolower($this->connection->ldapUserDisplayName);
198
+        if(isset($ldapEntry[$attr])) {
199
+            $displayName = (string)$ldapEntry[$attr][0];
200
+        }
201
+        $attr = strtolower($this->connection->ldapUserDisplayName2);
202
+        if(isset($ldapEntry[$attr])) {
203
+            $displayName2 = (string)$ldapEntry[$attr][0];
204
+        }
205
+        if ($displayName !== '') {
206
+            $this->composeAndStoreDisplayName($displayName, $displayName2);
207
+            $this->access->cacheUserDisplayName(
208
+                $this->getUsername(),
209
+                $displayName,
210
+                $displayName2
211
+            );
212
+        }
213
+        unset($attr);
214
+
215
+        //Email
216
+        //email must be stored after displayname, because it would cause a user
217
+        //change event that will trigger fetching the display name again
218
+        $attr = strtolower($this->connection->ldapEmailAttribute);
219
+        if(isset($ldapEntry[$attr])) {
220
+            $this->updateEmail($ldapEntry[$attr][0]);
221
+        }
222
+        unset($attr);
223
+
224
+        // LDAP Username, needed for s2s sharing
225
+        if(isset($ldapEntry['uid'])) {
226
+            $this->storeLDAPUserName($ldapEntry['uid'][0]);
227
+        } else if(isset($ldapEntry['samaccountname'])) {
228
+            $this->storeLDAPUserName($ldapEntry['samaccountname'][0]);
229
+        }
230
+
231
+        //homePath
232
+        if(strpos($this->connection->homeFolderNamingRule, 'attr:') === 0) {
233
+            $attr = strtolower(substr($this->connection->homeFolderNamingRule, strlen('attr:')));
234
+            if(isset($ldapEntry[$attr])) {
235
+                $this->access->cacheUserHome(
236
+                    $this->getUsername(), $this->getHomePath($ldapEntry[$attr][0]));
237
+            }
238
+        }
239
+
240
+        //memberOf groups
241
+        $cacheKey = 'getMemberOf'.$this->getUsername();
242
+        $groups = false;
243
+        if(isset($ldapEntry['memberof'])) {
244
+            $groups = $ldapEntry['memberof'];
245
+        }
246
+        $this->connection->writeToCache($cacheKey, $groups);
247
+
248
+        //external storage var
249
+        $attr = strtolower($this->connection->ldapExtStorageHomeAttribute);
250
+        if(isset($ldapEntry[$attr])) {
251
+            $this->updateExtStorageHome($ldapEntry[$attr][0]);
252
+        }
253
+        unset($attr);
254
+
255
+        //Avatar
256
+        /** @var Connection $connection */
257
+        $connection = $this->access->getConnection();
258
+        $attributes = $connection->resolveRule('avatar');
259
+        foreach ($attributes as $attribute)  {
260
+            if(isset($ldapEntry[$attribute])) {
261
+                $this->avatarImage = $ldapEntry[$attribute][0];
262
+                // the call to the method that saves the avatar in the file
263
+                // system must be postponed after the login. It is to ensure
264
+                // external mounts are mounted properly (e.g. with login
265
+                // credentials from the session).
266
+                \OCP\Util::connectHook('OC_User', 'post_login', $this, 'updateAvatarPostLogin');
267
+                break;
268
+            }
269
+        }
270
+    }
271
+
272
+    /**
273
+     * @brief returns the LDAP DN of the user
274
+     * @return string
275
+     */
276
+    public function getDN() {
277
+        return $this->dn;
278
+    }
279
+
280
+    /**
281
+     * @brief returns the Nextcloud internal username of the user
282
+     * @return string
283
+     */
284
+    public function getUsername() {
285
+        return $this->uid;
286
+    }
287
+
288
+    /**
289
+     * returns the home directory of the user if specified by LDAP settings
290
+     * @param string $valueFromLDAP
291
+     * @return bool|string
292
+     * @throws \Exception
293
+     */
294
+    public function getHomePath($valueFromLDAP = null) {
295
+        $path = (string)$valueFromLDAP;
296
+        $attr = null;
297
+
298
+        if (is_null($valueFromLDAP)
299
+           && strpos($this->access->connection->homeFolderNamingRule, 'attr:') === 0
300
+           && $this->access->connection->homeFolderNamingRule !== 'attr:')
301
+        {
302
+            $attr = substr($this->access->connection->homeFolderNamingRule, strlen('attr:'));
303
+            $homedir = $this->access->readAttribute(
304
+                $this->access->username2dn($this->getUsername()), $attr);
305
+            if ($homedir && isset($homedir[0])) {
306
+                $path = $homedir[0];
307
+            }
308
+        }
309
+
310
+        if ($path !== '') {
311
+            //if attribute's value is an absolute path take this, otherwise append it to data dir
312
+            //check for / at the beginning or pattern c:\ resp. c:/
313
+            if(   '/' !== $path[0]
314
+               && !(3 < strlen($path) && ctype_alpha($path[0])
315
+                   && $path[1] === ':' && ('\\' === $path[2] || '/' === $path[2]))
316
+            ) {
317
+                $path = $this->config->getSystemValue('datadirectory',
318
+                        \OC::$SERVERROOT.'/data' ) . '/' . $path;
319
+            }
320
+            //we need it to store it in the DB as well in case a user gets
321
+            //deleted so we can clean up afterwards
322
+            $this->config->setUserValue(
323
+                $this->getUsername(), 'user_ldap', 'homePath', $path
324
+            );
325
+            return $path;
326
+        }
327
+
328
+        if(    !is_null($attr)
329
+            && $this->config->getAppValue('user_ldap', 'enforce_home_folder_naming_rule', true)
330
+        ) {
331
+            // a naming rule attribute is defined, but it doesn't exist for that LDAP user
332
+            throw new \Exception('Home dir attribute can\'t be read from LDAP for uid: ' . $this->getUsername());
333
+        }
334
+
335
+        //false will apply default behaviour as defined and done by OC_User
336
+        $this->config->setUserValue($this->getUsername(), 'user_ldap', 'homePath', '');
337
+        return false;
338
+    }
339
+
340
+    public function getMemberOfGroups() {
341
+        $cacheKey = 'getMemberOf'.$this->getUsername();
342
+        $memberOfGroups = $this->connection->getFromCache($cacheKey);
343
+        if(!is_null($memberOfGroups)) {
344
+            return $memberOfGroups;
345
+        }
346
+        $groupDNs = $this->access->readAttribute($this->getDN(), 'memberOf');
347
+        $this->connection->writeToCache($cacheKey, $groupDNs);
348
+        return $groupDNs;
349
+    }
350
+
351
+    /**
352
+     * @brief reads the image from LDAP that shall be used as Avatar
353
+     * @return string data (provided by LDAP) | false
354
+     */
355
+    public function getAvatarImage() {
356
+        if(!is_null($this->avatarImage)) {
357
+            return $this->avatarImage;
358
+        }
359
+
360
+        $this->avatarImage = false;
361
+        /** @var Connection $connection */
362
+        $connection = $this->access->getConnection();
363
+        $attributes = $connection->resolveRule('avatar');
364
+        foreach($attributes as $attribute) {
365
+            $result = $this->access->readAttribute($this->dn, $attribute);
366
+            if($result !== false && is_array($result) && isset($result[0])) {
367
+                $this->avatarImage = $result[0];
368
+                break;
369
+            }
370
+        }
371
+
372
+        return $this->avatarImage;
373
+    }
374
+
375
+    /**
376
+     * @brief marks the user as having logged in at least once
377
+     * @return null
378
+     */
379
+    public function markLogin() {
380
+        $this->config->setUserValue(
381
+            $this->uid, 'user_ldap', self::USER_PREFKEY_FIRSTLOGIN, 1);
382
+    }
383
+
384
+    /**
385
+     * @brief marks the time when user features like email have been updated
386
+     * @return null
387
+     */
388
+    public function markRefreshTime() {
389
+        $this->config->setUserValue(
390
+            $this->uid, 'user_ldap', self::USER_PREFKEY_LASTREFRESH, time());
391
+    }
392
+
393
+    /**
394
+     * @brief checks whether user features needs to be updated again by
395
+     * comparing the difference of time of the last refresh to now with the
396
+     * desired interval
397
+     * @return bool
398
+     */
399
+    private function needsRefresh() {
400
+        $lastChecked = $this->config->getUserValue($this->uid, 'user_ldap',
401
+            self::USER_PREFKEY_LASTREFRESH, 0);
402
+
403
+        if((time() - (int)$lastChecked) < (int)$this->config->getAppValue('user_ldap', 'updateAttributesInterval', 86400)) {
404
+            return false;
405
+        }
406
+        return  true;
407
+    }
408
+
409
+    /**
410
+     * Stores a key-value pair in relation to this user
411
+     *
412
+     * @param string $key
413
+     * @param string $value
414
+     */
415
+    private function store($key, $value) {
416
+        $this->config->setUserValue($this->uid, 'user_ldap', $key, $value);
417
+    }
418
+
419
+    /**
420
+     * Composes the display name and stores it in the database. The final
421
+     * display name is returned.
422
+     *
423
+     * @param string $displayName
424
+     * @param string $displayName2
425
+     * @return string the effective display name
426
+     */
427
+    public function composeAndStoreDisplayName($displayName, $displayName2 = '') {
428
+        $displayName2 = (string)$displayName2;
429
+        if($displayName2 !== '') {
430
+            $displayName .= ' (' . $displayName2 . ')';
431
+        }
432
+        $oldName = $this->config->getUserValue($this->uid, 'user_ldap', 'displayName', null);
433
+        if ($oldName !== $displayName)  {
434
+            $this->store('displayName', $displayName);
435
+            $user = $this->userManager->get($this->getUsername());
436
+            if (!empty($oldName) && $user instanceof \OC\User\User) {
437
+                // if it was empty, it would be a new record, not a change emitting the trigger could
438
+                // potentially cause a UniqueConstraintViolationException, depending on some factors.
439
+                $user->triggerChange('displayName', $displayName, $oldName);
440
+            }
441
+        }
442
+        return $displayName;
443
+    }
444
+
445
+    /**
446
+     * Stores the LDAP Username in the Database
447
+     * @param string $userName
448
+     */
449
+    public function storeLDAPUserName($userName) {
450
+        $this->store('uid', $userName);
451
+    }
452
+
453
+    /**
454
+     * @brief checks whether an update method specified by feature was run
455
+     * already. If not, it will marked like this, because it is expected that
456
+     * the method will be run, when false is returned.
457
+     * @param string $feature email | quota | avatar (can be extended)
458
+     * @return bool
459
+     */
460
+    private function wasRefreshed($feature) {
461
+        if(isset($this->refreshedFeatures[$feature])) {
462
+            return true;
463
+        }
464
+        $this->refreshedFeatures[$feature] = 1;
465
+        return false;
466
+    }
467
+
468
+    /**
469
+     * fetches the email from LDAP and stores it as Nextcloud user value
470
+     * @param string $valueFromLDAP if known, to save an LDAP read request
471
+     * @return null
472
+     */
473
+    public function updateEmail($valueFromLDAP = null) {
474
+        if($this->wasRefreshed('email')) {
475
+            return;
476
+        }
477
+        $email = (string)$valueFromLDAP;
478
+        if(is_null($valueFromLDAP)) {
479
+            $emailAttribute = $this->connection->ldapEmailAttribute;
480
+            if ($emailAttribute !== '') {
481
+                $aEmail = $this->access->readAttribute($this->dn, $emailAttribute);
482
+                if(is_array($aEmail) && (count($aEmail) > 0)) {
483
+                    $email = (string)$aEmail[0];
484
+                }
485
+            }
486
+        }
487
+        if ($email !== '') {
488
+            $user = $this->userManager->get($this->uid);
489
+            if (!is_null($user)) {
490
+                $currentEmail = (string)$user->getEMailAddress();
491
+                if ($currentEmail !== $email) {
492
+                    $user->setEMailAddress($email);
493
+                }
494
+            }
495
+        }
496
+    }
497
+
498
+    /**
499
+     * Overall process goes as follow:
500
+     * 1. fetch the quota from LDAP and check if it's parseable with the "verifyQuotaValue" function
501
+     * 2. if the value can't be fetched, is empty or not parseable, use the default LDAP quota
502
+     * 3. if the default LDAP quota can't be parsed, use the Nextcloud's default quota (use 'default')
503
+     * 4. check if the target user exists and set the quota for the user.
504
+     *
505
+     * In order to improve performance and prevent an unwanted extra LDAP call, the $valueFromLDAP
506
+     * parameter can be passed with the value of the attribute. This value will be considered as the
507
+     * quota for the user coming from the LDAP server (step 1 of the process) It can be useful to
508
+     * fetch all the user's attributes in one call and use the fetched values in this function.
509
+     * The expected value for that parameter is a string describing the quota for the user. Valid
510
+     * values are 'none' (unlimited), 'default' (the Nextcloud's default quota), '1234' (quota in
511
+     * bytes), '1234 MB' (quota in MB - check the \OC_Helper::computerFileSize method for more info)
512
+     *
513
+     * fetches the quota from LDAP and stores it as Nextcloud user value
514
+     * @param string $valueFromLDAP the quota attribute's value can be passed,
515
+     * to save the readAttribute request
516
+     * @return null
517
+     */
518
+    public function updateQuota($valueFromLDAP = null) {
519
+        if($this->wasRefreshed('quota')) {
520
+            return;
521
+        }
522
+
523
+        $quotaAttribute = $this->connection->ldapQuotaAttribute;
524
+        $defaultQuota = $this->connection->ldapQuotaDefault;
525
+        if($quotaAttribute === '' && $defaultQuota === '') {
526
+            return;
527
+        }
528
+
529
+        $quota = false;
530
+        if(is_null($valueFromLDAP) && $quotaAttribute !== '') {
531
+            $aQuota = $this->access->readAttribute($this->dn, $quotaAttribute);
532
+            if($aQuota && (count($aQuota) > 0) && $this->verifyQuotaValue($aQuota[0])) {
533
+                $quota = $aQuota[0];
534
+            } else if(is_array($aQuota) && isset($aQuota[0])) {
535
+                $this->log->log('no suitable LDAP quota found for user ' . $this->uid . ': [' . $aQuota[0] . ']', ILogger::DEBUG);
536
+            }
537
+        } else if ($this->verifyQuotaValue($valueFromLDAP)) {
538
+            $quota = $valueFromLDAP;
539
+        } else {
540
+            $this->log->log('no suitable LDAP quota found for user ' . $this->uid . ': [' . $valueFromLDAP . ']', ILogger::DEBUG);
541
+        }
542
+
543
+        if ($quota === false && $this->verifyQuotaValue($defaultQuota)) {
544
+            // quota not found using the LDAP attribute (or not parseable). Try the default quota
545
+            $quota = $defaultQuota;
546
+        } else if($quota === false) {
547
+            $this->log->log('no suitable default quota found for user ' . $this->uid . ': [' . $defaultQuota . ']', ILogger::DEBUG);
548
+            return;
549
+        }
550
+
551
+        $targetUser = $this->userManager->get($this->uid);
552
+        if ($targetUser instanceof IUser) {
553
+            $targetUser->setQuota($quota);
554
+        } else {
555
+            $this->log->log('trying to set a quota for user ' . $this->uid . ' but the user is missing', ILogger::INFO);
556
+        }
557
+    }
558
+
559
+    private function verifyQuotaValue($quotaValue) {
560
+        return $quotaValue === 'none' || $quotaValue === 'default' || \OC_Helper::computerFileSize($quotaValue) !== false;
561
+    }
562
+
563
+    /**
564
+     * called by a post_login hook to save the avatar picture
565
+     *
566
+     * @param array $params
567
+     */
568
+    public function updateAvatarPostLogin($params) {
569
+        if(isset($params['uid']) && $params['uid'] === $this->getUsername()) {
570
+            $this->updateAvatar();
571
+        }
572
+    }
573
+
574
+    /**
575
+     * @brief attempts to get an image from LDAP and sets it as Nextcloud avatar
576
+     * @return bool
577
+     */
578
+    public function updateAvatar($force = false) {
579
+        if(!$force && $this->wasRefreshed('avatar')) {
580
+            return false;
581
+        }
582
+        $avatarImage = $this->getAvatarImage();
583
+        if($avatarImage === false) {
584
+            //not set, nothing left to do;
585
+            return false;
586
+        }
587
+
588
+        if(!$this->image->loadFromBase64(base64_encode($avatarImage))) {
589
+            return false;
590
+        }
591
+
592
+        // use the checksum before modifications
593
+        $checksum = md5($this->image->data());
594
+
595
+        if($checksum === $this->config->getUserValue($this->uid, 'user_ldap', 'lastAvatarChecksum', '')) {
596
+            return true;
597
+        }
598
+
599
+        $isSet = $this->setOwnCloudAvatar();
600
+
601
+        if($isSet) {
602
+            // save checksum only after successful setting
603
+            $this->config->setUserValue($this->uid, 'user_ldap', 'lastAvatarChecksum', $checksum);
604
+        }
605
+
606
+        return $isSet;
607
+    }
608
+
609
+    /**
610
+     * @brief sets an image as Nextcloud avatar
611
+     * @return bool
612
+     */
613
+    private function setOwnCloudAvatar() {
614
+        if(!$this->image->valid()) {
615
+            $this->log->log('avatar image data from LDAP invalid for '.$this->dn, ILogger::ERROR);
616
+            return false;
617
+        }
618
+
619
+
620
+        //make sure it is a square and not bigger than 128x128
621
+        $size = min([$this->image->width(), $this->image->height(), 128]);
622
+        if(!$this->image->centerCrop($size)) {
623
+            $this->log->log('croping image for avatar failed for '.$this->dn, ILogger::ERROR);
624
+            return false;
625
+        }
626
+
627
+        if(!$this->fs->isLoaded()) {
628
+            $this->fs->setup($this->uid);
629
+        }
630
+
631
+        try {
632
+            $avatar = $this->avatarManager->getAvatar($this->uid);
633
+            $avatar->set($this->image);
634
+            return true;
635
+        } catch (\Exception $e) {
636
+            \OC::$server->getLogger()->logException($e, [
637
+                'message' => 'Could not set avatar for ' . $this->dn,
638
+                'level' => ILogger::INFO,
639
+                'app' => 'user_ldap',
640
+            ]);
641
+        }
642
+        return false;
643
+    }
644
+
645
+    /**
646
+     * @throws AttributeNotSet
647
+     * @throws \OC\ServerNotAvailableException
648
+     * @throws \OCP\PreConditionNotMetException
649
+     */
650
+    public function getExtStorageHome():string {
651
+        $value = $this->config->getUserValue($this->getUsername(), 'user_ldap', 'extStorageHome', '');
652
+        if ($value !== '') {
653
+            return $value;
654
+        }
655
+
656
+        $value = $this->updateExtStorageHome();
657
+        if ($value !== '') {
658
+            return $value;
659
+        }
660
+
661
+        throw new AttributeNotSet(sprintf(
662
+            'external home storage attribute yield no value for %s', $this->getUsername()
663
+        ));
664
+    }
665
+
666
+    /**
667
+     * @throws \OCP\PreConditionNotMetException
668
+     * @throws \OC\ServerNotAvailableException
669
+     */
670
+    public function updateExtStorageHome(string $valueFromLDAP = null):string {
671
+        if($valueFromLDAP === null) {
672
+            $extHomeValues = $this->access->readAttribute($this->getDN(), $this->connection->ldapExtStorageHomeAttribute);
673
+        } else {
674
+            $extHomeValues = [$valueFromLDAP];
675
+        }
676
+        if ($extHomeValues && isset($extHomeValues[0])) {
677
+            $extHome = $extHomeValues[0];
678
+            $this->config->setUserValue($this->getUsername(), 'user_ldap', 'extStorageHome', $extHome);
679
+            return $extHome;
680
+        } else {
681
+            $this->config->deleteUserValue($this->getUsername(), 'user_ldap', 'extStorageHome');
682
+            return '';
683
+        }
684
+    }
685
+
686
+    /**
687
+     * called by a post_login hook to handle password expiry
688
+     *
689
+     * @param array $params
690
+     */
691
+    public function handlePasswordExpiry($params) {
692
+        $ppolicyDN = $this->connection->ldapDefaultPPolicyDN;
693
+        if (empty($ppolicyDN) || ((int)$this->connection->turnOnPasswordChange !== 1)) {
694
+            return;//password expiry handling disabled
695
+        }
696
+        $uid = $params['uid'];
697
+        if(isset($uid) && $uid === $this->getUsername()) {
698
+            //retrieve relevant user attributes
699
+            $result = $this->access->search('objectclass=*', array($this->dn), ['pwdpolicysubentry', 'pwdgraceusetime', 'pwdreset', 'pwdchangedtime']);
700 700
 			
701
-			if(array_key_exists('pwdpolicysubentry', $result[0])) {
702
-				$pwdPolicySubentry = $result[0]['pwdpolicysubentry'];
703
-				if($pwdPolicySubentry && (count($pwdPolicySubentry) > 0)){
704
-					$ppolicyDN = $pwdPolicySubentry[0];//custom ppolicy DN
705
-				}
706
-			}
701
+            if(array_key_exists('pwdpolicysubentry', $result[0])) {
702
+                $pwdPolicySubentry = $result[0]['pwdpolicysubentry'];
703
+                if($pwdPolicySubentry && (count($pwdPolicySubentry) > 0)){
704
+                    $ppolicyDN = $pwdPolicySubentry[0];//custom ppolicy DN
705
+                }
706
+            }
707 707
 			
708
-			$pwdGraceUseTime = array_key_exists('pwdgraceusetime', $result[0]) ? $result[0]['pwdgraceusetime'] : null;
709
-			$pwdReset = array_key_exists('pwdreset', $result[0]) ? $result[0]['pwdreset'] : null;
710
-			$pwdChangedTime = array_key_exists('pwdchangedtime', $result[0]) ? $result[0]['pwdchangedtime'] : null;
708
+            $pwdGraceUseTime = array_key_exists('pwdgraceusetime', $result[0]) ? $result[0]['pwdgraceusetime'] : null;
709
+            $pwdReset = array_key_exists('pwdreset', $result[0]) ? $result[0]['pwdreset'] : null;
710
+            $pwdChangedTime = array_key_exists('pwdchangedtime', $result[0]) ? $result[0]['pwdchangedtime'] : null;
711 711
 			
712
-			//retrieve relevant password policy attributes
713
-			$cacheKey = 'ppolicyAttributes' . $ppolicyDN;
714
-			$result = $this->connection->getFromCache($cacheKey);
715
-			if(is_null($result)) {
716
-				$result = $this->access->search('objectclass=*', array($ppolicyDN), ['pwdgraceauthnlimit', 'pwdmaxage', 'pwdexpirewarning']);
717
-				$this->connection->writeToCache($cacheKey, $result);
718
-			}
712
+            //retrieve relevant password policy attributes
713
+            $cacheKey = 'ppolicyAttributes' . $ppolicyDN;
714
+            $result = $this->connection->getFromCache($cacheKey);
715
+            if(is_null($result)) {
716
+                $result = $this->access->search('objectclass=*', array($ppolicyDN), ['pwdgraceauthnlimit', 'pwdmaxage', 'pwdexpirewarning']);
717
+                $this->connection->writeToCache($cacheKey, $result);
718
+            }
719 719
 			
720
-			$pwdGraceAuthNLimit = array_key_exists('pwdgraceauthnlimit', $result[0]) ? $result[0]['pwdgraceauthnlimit'] : null;
721
-			$pwdMaxAge = array_key_exists('pwdmaxage', $result[0]) ? $result[0]['pwdmaxage'] : null;
722
-			$pwdExpireWarning = array_key_exists('pwdexpirewarning', $result[0]) ? $result[0]['pwdexpirewarning'] : null;
720
+            $pwdGraceAuthNLimit = array_key_exists('pwdgraceauthnlimit', $result[0]) ? $result[0]['pwdgraceauthnlimit'] : null;
721
+            $pwdMaxAge = array_key_exists('pwdmaxage', $result[0]) ? $result[0]['pwdmaxage'] : null;
722
+            $pwdExpireWarning = array_key_exists('pwdexpirewarning', $result[0]) ? $result[0]['pwdexpirewarning'] : null;
723 723
 			
724
-			//handle grace login
725
-			$pwdGraceUseTimeCount = count($pwdGraceUseTime);
726
-			if($pwdGraceUseTime && $pwdGraceUseTimeCount > 0) { //was this a grace login?
727
-				if($pwdGraceAuthNLimit 
728
-					&& (count($pwdGraceAuthNLimit) > 0)
729
-					&&($pwdGraceUseTimeCount < (int)$pwdGraceAuthNLimit[0])) { //at least one more grace login available?
730
-					$this->config->setUserValue($uid, 'user_ldap', 'needsPasswordReset', 'true');
731
-					header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute(
732
-					'user_ldap.renewPassword.showRenewPasswordForm', array('user' => $uid)));
733
-				} else { //no more grace login available
734
-					header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute(
735
-					'user_ldap.renewPassword.showLoginFormInvalidPassword', array('user' => $uid)));
736
-				}
737
-				exit();
738
-			}
739
-			//handle pwdReset attribute
740
-			if($pwdReset && (count($pwdReset) > 0) && $pwdReset[0] === 'TRUE') { //user must change his password
741
-				$this->config->setUserValue($uid, 'user_ldap', 'needsPasswordReset', 'true');
742
-				header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute(
743
-				'user_ldap.renewPassword.showRenewPasswordForm', array('user' => $uid)));
744
-				exit();
745
-			}
746
-			//handle password expiry warning
747
-			if($pwdChangedTime && (count($pwdChangedTime) > 0)) {
748
-				if($pwdMaxAge && (count($pwdMaxAge) > 0)
749
-					&& $pwdExpireWarning && (count($pwdExpireWarning) > 0)) {
750
-					$pwdMaxAgeInt = (int)$pwdMaxAge[0];
751
-					$pwdExpireWarningInt = (int)$pwdExpireWarning[0];
752
-					if($pwdMaxAgeInt > 0 && $pwdExpireWarningInt > 0){
753
-						$pwdChangedTimeDt = \DateTime::createFromFormat('YmdHisZ', $pwdChangedTime[0]);
754
-						$pwdChangedTimeDt->add(new \DateInterval('PT'.$pwdMaxAgeInt.'S'));
755
-						$currentDateTime = new \DateTime();
756
-						$secondsToExpiry = $pwdChangedTimeDt->getTimestamp() - $currentDateTime->getTimestamp();
757
-						if($secondsToExpiry <= $pwdExpireWarningInt) {
758
-							//remove last password expiry warning if any
759
-							$notification = $this->notificationManager->createNotification();
760
-							$notification->setApp('user_ldap')
761
-								->setUser($uid)
762
-								->setObject('pwd_exp_warn', $uid)
763
-							;
764
-							$this->notificationManager->markProcessed($notification);
765
-							//create new password expiry warning
766
-							$notification = $this->notificationManager->createNotification();
767
-							$notification->setApp('user_ldap')
768
-								->setUser($uid)
769
-								->setDateTime($currentDateTime)
770
-								->setObject('pwd_exp_warn', $uid) 
771
-								->setSubject('pwd_exp_warn_days', [(int) ceil($secondsToExpiry / 60 / 60 / 24)])
772
-							;
773
-							$this->notificationManager->notify($notification);
774
-						}
775
-					}
776
-				}
777
-			}
778
-		}
779
-	}
724
+            //handle grace login
725
+            $pwdGraceUseTimeCount = count($pwdGraceUseTime);
726
+            if($pwdGraceUseTime && $pwdGraceUseTimeCount > 0) { //was this a grace login?
727
+                if($pwdGraceAuthNLimit 
728
+                    && (count($pwdGraceAuthNLimit) > 0)
729
+                    &&($pwdGraceUseTimeCount < (int)$pwdGraceAuthNLimit[0])) { //at least one more grace login available?
730
+                    $this->config->setUserValue($uid, 'user_ldap', 'needsPasswordReset', 'true');
731
+                    header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute(
732
+                    'user_ldap.renewPassword.showRenewPasswordForm', array('user' => $uid)));
733
+                } else { //no more grace login available
734
+                    header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute(
735
+                    'user_ldap.renewPassword.showLoginFormInvalidPassword', array('user' => $uid)));
736
+                }
737
+                exit();
738
+            }
739
+            //handle pwdReset attribute
740
+            if($pwdReset && (count($pwdReset) > 0) && $pwdReset[0] === 'TRUE') { //user must change his password
741
+                $this->config->setUserValue($uid, 'user_ldap', 'needsPasswordReset', 'true');
742
+                header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute(
743
+                'user_ldap.renewPassword.showRenewPasswordForm', array('user' => $uid)));
744
+                exit();
745
+            }
746
+            //handle password expiry warning
747
+            if($pwdChangedTime && (count($pwdChangedTime) > 0)) {
748
+                if($pwdMaxAge && (count($pwdMaxAge) > 0)
749
+                    && $pwdExpireWarning && (count($pwdExpireWarning) > 0)) {
750
+                    $pwdMaxAgeInt = (int)$pwdMaxAge[0];
751
+                    $pwdExpireWarningInt = (int)$pwdExpireWarning[0];
752
+                    if($pwdMaxAgeInt > 0 && $pwdExpireWarningInt > 0){
753
+                        $pwdChangedTimeDt = \DateTime::createFromFormat('YmdHisZ', $pwdChangedTime[0]);
754
+                        $pwdChangedTimeDt->add(new \DateInterval('PT'.$pwdMaxAgeInt.'S'));
755
+                        $currentDateTime = new \DateTime();
756
+                        $secondsToExpiry = $pwdChangedTimeDt->getTimestamp() - $currentDateTime->getTimestamp();
757
+                        if($secondsToExpiry <= $pwdExpireWarningInt) {
758
+                            //remove last password expiry warning if any
759
+                            $notification = $this->notificationManager->createNotification();
760
+                            $notification->setApp('user_ldap')
761
+                                ->setUser($uid)
762
+                                ->setObject('pwd_exp_warn', $uid)
763
+                            ;
764
+                            $this->notificationManager->markProcessed($notification);
765
+                            //create new password expiry warning
766
+                            $notification = $this->notificationManager->createNotification();
767
+                            $notification->setApp('user_ldap')
768
+                                ->setUser($uid)
769
+                                ->setDateTime($currentDateTime)
770
+                                ->setObject('pwd_exp_warn', $uid) 
771
+                                ->setSubject('pwd_exp_warn_days', [(int) ceil($secondsToExpiry / 60 / 60 / 24)])
772
+                            ;
773
+                            $this->notificationManager->notify($notification);
774
+                        }
775
+                    }
776
+                }
777
+            }
778
+        }
779
+    }
780 780
 }
Please login to merge, or discard this patch.
Spacing   +77 added lines, -77 removed lines patch added patch discarded remove patch
@@ -154,17 +154,17 @@  discard block
 block discarded – undo
154 154
 	 * @return null
155 155
 	 */
156 156
 	public function update() {
157
-		if(is_null($this->dn)) {
157
+		if (is_null($this->dn)) {
158 158
 			return null;
159 159
 		}
160 160
 
161 161
 		$hasLoggedIn = $this->config->getUserValue($this->uid, 'user_ldap',
162 162
 				self::USER_PREFKEY_FIRSTLOGIN, 0);
163 163
 
164
-		if($this->needsRefresh()) {
164
+		if ($this->needsRefresh()) {
165 165
 			$this->updateEmail();
166 166
 			$this->updateQuota();
167
-			if($hasLoggedIn !== 0) {
167
+			if ($hasLoggedIn !== 0) {
168 168
 				//we do not need to try it, when the user has not been logged in
169 169
 				//before, because the file system will not be ready.
170 170
 				$this->updateAvatar();
@@ -183,7 +183,7 @@  discard block
 block discarded – undo
183 183
 		$this->markRefreshTime();
184 184
 		//Quota
185 185
 		$attr = strtolower($this->connection->ldapQuotaAttribute);
186
-		if(isset($ldapEntry[$attr])) {
186
+		if (isset($ldapEntry[$attr])) {
187 187
 			$this->updateQuota($ldapEntry[$attr][0]);
188 188
 		} else {
189 189
 			if ($this->connection->ldapQuotaDefault !== '') {
@@ -195,12 +195,12 @@  discard block
 block discarded – undo
195 195
 		//displayName
196 196
 		$displayName = $displayName2 = '';
197 197
 		$attr = strtolower($this->connection->ldapUserDisplayName);
198
-		if(isset($ldapEntry[$attr])) {
199
-			$displayName = (string)$ldapEntry[$attr][0];
198
+		if (isset($ldapEntry[$attr])) {
199
+			$displayName = (string) $ldapEntry[$attr][0];
200 200
 		}
201 201
 		$attr = strtolower($this->connection->ldapUserDisplayName2);
202
-		if(isset($ldapEntry[$attr])) {
203
-			$displayName2 = (string)$ldapEntry[$attr][0];
202
+		if (isset($ldapEntry[$attr])) {
203
+			$displayName2 = (string) $ldapEntry[$attr][0];
204 204
 		}
205 205
 		if ($displayName !== '') {
206 206
 			$this->composeAndStoreDisplayName($displayName, $displayName2);
@@ -216,22 +216,22 @@  discard block
 block discarded – undo
216 216
 		//email must be stored after displayname, because it would cause a user
217 217
 		//change event that will trigger fetching the display name again
218 218
 		$attr = strtolower($this->connection->ldapEmailAttribute);
219
-		if(isset($ldapEntry[$attr])) {
219
+		if (isset($ldapEntry[$attr])) {
220 220
 			$this->updateEmail($ldapEntry[$attr][0]);
221 221
 		}
222 222
 		unset($attr);
223 223
 
224 224
 		// LDAP Username, needed for s2s sharing
225
-		if(isset($ldapEntry['uid'])) {
225
+		if (isset($ldapEntry['uid'])) {
226 226
 			$this->storeLDAPUserName($ldapEntry['uid'][0]);
227
-		} else if(isset($ldapEntry['samaccountname'])) {
227
+		} else if (isset($ldapEntry['samaccountname'])) {
228 228
 			$this->storeLDAPUserName($ldapEntry['samaccountname'][0]);
229 229
 		}
230 230
 
231 231
 		//homePath
232
-		if(strpos($this->connection->homeFolderNamingRule, 'attr:') === 0) {
232
+		if (strpos($this->connection->homeFolderNamingRule, 'attr:') === 0) {
233 233
 			$attr = strtolower(substr($this->connection->homeFolderNamingRule, strlen('attr:')));
234
-			if(isset($ldapEntry[$attr])) {
234
+			if (isset($ldapEntry[$attr])) {
235 235
 				$this->access->cacheUserHome(
236 236
 					$this->getUsername(), $this->getHomePath($ldapEntry[$attr][0]));
237 237
 			}
@@ -240,14 +240,14 @@  discard block
 block discarded – undo
240 240
 		//memberOf groups
241 241
 		$cacheKey = 'getMemberOf'.$this->getUsername();
242 242
 		$groups = false;
243
-		if(isset($ldapEntry['memberof'])) {
243
+		if (isset($ldapEntry['memberof'])) {
244 244
 			$groups = $ldapEntry['memberof'];
245 245
 		}
246 246
 		$this->connection->writeToCache($cacheKey, $groups);
247 247
 
248 248
 		//external storage var
249 249
 		$attr = strtolower($this->connection->ldapExtStorageHomeAttribute);
250
-		if(isset($ldapEntry[$attr])) {
250
+		if (isset($ldapEntry[$attr])) {
251 251
 			$this->updateExtStorageHome($ldapEntry[$attr][0]);
252 252
 		}
253 253
 		unset($attr);
@@ -256,8 +256,8 @@  discard block
 block discarded – undo
256 256
 		/** @var Connection $connection */
257 257
 		$connection = $this->access->getConnection();
258 258
 		$attributes = $connection->resolveRule('avatar');
259
-		foreach ($attributes as $attribute)  {
260
-			if(isset($ldapEntry[$attribute])) {
259
+		foreach ($attributes as $attribute) {
260
+			if (isset($ldapEntry[$attribute])) {
261 261
 				$this->avatarImage = $ldapEntry[$attribute][0];
262 262
 				// the call to the method that saves the avatar in the file
263 263
 				// system must be postponed after the login. It is to ensure
@@ -292,7 +292,7 @@  discard block
 block discarded – undo
292 292
 	 * @throws \Exception
293 293
 	 */
294 294
 	public function getHomePath($valueFromLDAP = null) {
295
-		$path = (string)$valueFromLDAP;
295
+		$path = (string) $valueFromLDAP;
296 296
 		$attr = null;
297 297
 
298 298
 		if (is_null($valueFromLDAP)
@@ -310,12 +310,12 @@  discard block
 block discarded – undo
310 310
 		if ($path !== '') {
311 311
 			//if attribute's value is an absolute path take this, otherwise append it to data dir
312 312
 			//check for / at the beginning or pattern c:\ resp. c:/
313
-			if(   '/' !== $path[0]
313
+			if ('/' !== $path[0]
314 314
 			   && !(3 < strlen($path) && ctype_alpha($path[0])
315 315
 			       && $path[1] === ':' && ('\\' === $path[2] || '/' === $path[2]))
316 316
 			) {
317 317
 				$path = $this->config->getSystemValue('datadirectory',
318
-						\OC::$SERVERROOT.'/data' ) . '/' . $path;
318
+						\OC::$SERVERROOT.'/data').'/'.$path;
319 319
 			}
320 320
 			//we need it to store it in the DB as well in case a user gets
321 321
 			//deleted so we can clean up afterwards
@@ -325,11 +325,11 @@  discard block
 block discarded – undo
325 325
 			return $path;
326 326
 		}
327 327
 
328
-		if(    !is_null($attr)
328
+		if (!is_null($attr)
329 329
 			&& $this->config->getAppValue('user_ldap', 'enforce_home_folder_naming_rule', true)
330 330
 		) {
331 331
 			// a naming rule attribute is defined, but it doesn't exist for that LDAP user
332
-			throw new \Exception('Home dir attribute can\'t be read from LDAP for uid: ' . $this->getUsername());
332
+			throw new \Exception('Home dir attribute can\'t be read from LDAP for uid: '.$this->getUsername());
333 333
 		}
334 334
 
335 335
 		//false will apply default behaviour as defined and done by OC_User
@@ -340,7 +340,7 @@  discard block
 block discarded – undo
340 340
 	public function getMemberOfGroups() {
341 341
 		$cacheKey = 'getMemberOf'.$this->getUsername();
342 342
 		$memberOfGroups = $this->connection->getFromCache($cacheKey);
343
-		if(!is_null($memberOfGroups)) {
343
+		if (!is_null($memberOfGroups)) {
344 344
 			return $memberOfGroups;
345 345
 		}
346 346
 		$groupDNs = $this->access->readAttribute($this->getDN(), 'memberOf');
@@ -353,7 +353,7 @@  discard block
 block discarded – undo
353 353
 	 * @return string data (provided by LDAP) | false
354 354
 	 */
355 355
 	public function getAvatarImage() {
356
-		if(!is_null($this->avatarImage)) {
356
+		if (!is_null($this->avatarImage)) {
357 357
 			return $this->avatarImage;
358 358
 		}
359 359
 
@@ -361,9 +361,9 @@  discard block
 block discarded – undo
361 361
 		/** @var Connection $connection */
362 362
 		$connection = $this->access->getConnection();
363 363
 		$attributes = $connection->resolveRule('avatar');
364
-		foreach($attributes as $attribute) {
364
+		foreach ($attributes as $attribute) {
365 365
 			$result = $this->access->readAttribute($this->dn, $attribute);
366
-			if($result !== false && is_array($result) && isset($result[0])) {
366
+			if ($result !== false && is_array($result) && isset($result[0])) {
367 367
 				$this->avatarImage = $result[0];
368 368
 				break;
369 369
 			}
@@ -400,7 +400,7 @@  discard block
 block discarded – undo
400 400
 		$lastChecked = $this->config->getUserValue($this->uid, 'user_ldap',
401 401
 			self::USER_PREFKEY_LASTREFRESH, 0);
402 402
 
403
-		if((time() - (int)$lastChecked) < (int)$this->config->getAppValue('user_ldap', 'updateAttributesInterval', 86400)) {
403
+		if ((time() - (int) $lastChecked) < (int) $this->config->getAppValue('user_ldap', 'updateAttributesInterval', 86400)) {
404 404
 			return false;
405 405
 		}
406 406
 		return  true;
@@ -425,12 +425,12 @@  discard block
 block discarded – undo
425 425
 	 * @return string the effective display name
426 426
 	 */
427 427
 	public function composeAndStoreDisplayName($displayName, $displayName2 = '') {
428
-		$displayName2 = (string)$displayName2;
429
-		if($displayName2 !== '') {
430
-			$displayName .= ' (' . $displayName2 . ')';
428
+		$displayName2 = (string) $displayName2;
429
+		if ($displayName2 !== '') {
430
+			$displayName .= ' ('.$displayName2.')';
431 431
 		}
432 432
 		$oldName = $this->config->getUserValue($this->uid, 'user_ldap', 'displayName', null);
433
-		if ($oldName !== $displayName)  {
433
+		if ($oldName !== $displayName) {
434 434
 			$this->store('displayName', $displayName);
435 435
 			$user = $this->userManager->get($this->getUsername());
436 436
 			if (!empty($oldName) && $user instanceof \OC\User\User) {
@@ -458,7 +458,7 @@  discard block
 block discarded – undo
458 458
 	 * @return bool
459 459
 	 */
460 460
 	private function wasRefreshed($feature) {
461
-		if(isset($this->refreshedFeatures[$feature])) {
461
+		if (isset($this->refreshedFeatures[$feature])) {
462 462
 			return true;
463 463
 		}
464 464
 		$this->refreshedFeatures[$feature] = 1;
@@ -471,23 +471,23 @@  discard block
 block discarded – undo
471 471
 	 * @return null
472 472
 	 */
473 473
 	public function updateEmail($valueFromLDAP = null) {
474
-		if($this->wasRefreshed('email')) {
474
+		if ($this->wasRefreshed('email')) {
475 475
 			return;
476 476
 		}
477
-		$email = (string)$valueFromLDAP;
478
-		if(is_null($valueFromLDAP)) {
477
+		$email = (string) $valueFromLDAP;
478
+		if (is_null($valueFromLDAP)) {
479 479
 			$emailAttribute = $this->connection->ldapEmailAttribute;
480 480
 			if ($emailAttribute !== '') {
481 481
 				$aEmail = $this->access->readAttribute($this->dn, $emailAttribute);
482
-				if(is_array($aEmail) && (count($aEmail) > 0)) {
483
-					$email = (string)$aEmail[0];
482
+				if (is_array($aEmail) && (count($aEmail) > 0)) {
483
+					$email = (string) $aEmail[0];
484 484
 				}
485 485
 			}
486 486
 		}
487 487
 		if ($email !== '') {
488 488
 			$user = $this->userManager->get($this->uid);
489 489
 			if (!is_null($user)) {
490
-				$currentEmail = (string)$user->getEMailAddress();
490
+				$currentEmail = (string) $user->getEMailAddress();
491 491
 				if ($currentEmail !== $email) {
492 492
 					$user->setEMailAddress($email);
493 493
 				}
@@ -516,35 +516,35 @@  discard block
 block discarded – undo
516 516
 	 * @return null
517 517
 	 */
518 518
 	public function updateQuota($valueFromLDAP = null) {
519
-		if($this->wasRefreshed('quota')) {
519
+		if ($this->wasRefreshed('quota')) {
520 520
 			return;
521 521
 		}
522 522
 
523 523
 		$quotaAttribute = $this->connection->ldapQuotaAttribute;
524 524
 		$defaultQuota = $this->connection->ldapQuotaDefault;
525
-		if($quotaAttribute === '' && $defaultQuota === '') {
525
+		if ($quotaAttribute === '' && $defaultQuota === '') {
526 526
 			return;
527 527
 		}
528 528
 
529 529
 		$quota = false;
530
-		if(is_null($valueFromLDAP) && $quotaAttribute !== '') {
530
+		if (is_null($valueFromLDAP) && $quotaAttribute !== '') {
531 531
 			$aQuota = $this->access->readAttribute($this->dn, $quotaAttribute);
532
-			if($aQuota && (count($aQuota) > 0) && $this->verifyQuotaValue($aQuota[0])) {
532
+			if ($aQuota && (count($aQuota) > 0) && $this->verifyQuotaValue($aQuota[0])) {
533 533
 				$quota = $aQuota[0];
534
-			} else if(is_array($aQuota) && isset($aQuota[0])) {
535
-				$this->log->log('no suitable LDAP quota found for user ' . $this->uid . ': [' . $aQuota[0] . ']', ILogger::DEBUG);
534
+			} else if (is_array($aQuota) && isset($aQuota[0])) {
535
+				$this->log->log('no suitable LDAP quota found for user '.$this->uid.': ['.$aQuota[0].']', ILogger::DEBUG);
536 536
 			}
537 537
 		} else if ($this->verifyQuotaValue($valueFromLDAP)) {
538 538
 			$quota = $valueFromLDAP;
539 539
 		} else {
540
-			$this->log->log('no suitable LDAP quota found for user ' . $this->uid . ': [' . $valueFromLDAP . ']', ILogger::DEBUG);
540
+			$this->log->log('no suitable LDAP quota found for user '.$this->uid.': ['.$valueFromLDAP.']', ILogger::DEBUG);
541 541
 		}
542 542
 
543 543
 		if ($quota === false && $this->verifyQuotaValue($defaultQuota)) {
544 544
 			// quota not found using the LDAP attribute (or not parseable). Try the default quota
545 545
 			$quota = $defaultQuota;
546
-		} else if($quota === false) {
547
-			$this->log->log('no suitable default quota found for user ' . $this->uid . ': [' . $defaultQuota . ']', ILogger::DEBUG);
546
+		} else if ($quota === false) {
547
+			$this->log->log('no suitable default quota found for user '.$this->uid.': ['.$defaultQuota.']', ILogger::DEBUG);
548 548
 			return;
549 549
 		}
550 550
 
@@ -552,7 +552,7 @@  discard block
 block discarded – undo
552 552
 		if ($targetUser instanceof IUser) {
553 553
 			$targetUser->setQuota($quota);
554 554
 		} else {
555
-			$this->log->log('trying to set a quota for user ' . $this->uid . ' but the user is missing', ILogger::INFO);
555
+			$this->log->log('trying to set a quota for user '.$this->uid.' but the user is missing', ILogger::INFO);
556 556
 		}
557 557
 	}
558 558
 
@@ -566,7 +566,7 @@  discard block
 block discarded – undo
566 566
 	 * @param array $params
567 567
 	 */
568 568
 	public function updateAvatarPostLogin($params) {
569
-		if(isset($params['uid']) && $params['uid'] === $this->getUsername()) {
569
+		if (isset($params['uid']) && $params['uid'] === $this->getUsername()) {
570 570
 			$this->updateAvatar();
571 571
 		}
572 572
 	}
@@ -576,29 +576,29 @@  discard block
 block discarded – undo
576 576
 	 * @return bool
577 577
 	 */
578 578
 	public function updateAvatar($force = false) {
579
-		if(!$force && $this->wasRefreshed('avatar')) {
579
+		if (!$force && $this->wasRefreshed('avatar')) {
580 580
 			return false;
581 581
 		}
582 582
 		$avatarImage = $this->getAvatarImage();
583
-		if($avatarImage === false) {
583
+		if ($avatarImage === false) {
584 584
 			//not set, nothing left to do;
585 585
 			return false;
586 586
 		}
587 587
 
588
-		if(!$this->image->loadFromBase64(base64_encode($avatarImage))) {
588
+		if (!$this->image->loadFromBase64(base64_encode($avatarImage))) {
589 589
 			return false;
590 590
 		}
591 591
 
592 592
 		// use the checksum before modifications
593 593
 		$checksum = md5($this->image->data());
594 594
 
595
-		if($checksum === $this->config->getUserValue($this->uid, 'user_ldap', 'lastAvatarChecksum', '')) {
595
+		if ($checksum === $this->config->getUserValue($this->uid, 'user_ldap', 'lastAvatarChecksum', '')) {
596 596
 			return true;
597 597
 		}
598 598
 
599 599
 		$isSet = $this->setOwnCloudAvatar();
600 600
 
601
-		if($isSet) {
601
+		if ($isSet) {
602 602
 			// save checksum only after successful setting
603 603
 			$this->config->setUserValue($this->uid, 'user_ldap', 'lastAvatarChecksum', $checksum);
604 604
 		}
@@ -611,7 +611,7 @@  discard block
 block discarded – undo
611 611
 	 * @return bool
612 612
 	 */
613 613
 	private function setOwnCloudAvatar() {
614
-		if(!$this->image->valid()) {
614
+		if (!$this->image->valid()) {
615 615
 			$this->log->log('avatar image data from LDAP invalid for '.$this->dn, ILogger::ERROR);
616 616
 			return false;
617 617
 		}
@@ -619,12 +619,12 @@  discard block
 block discarded – undo
619 619
 
620 620
 		//make sure it is a square and not bigger than 128x128
621 621
 		$size = min([$this->image->width(), $this->image->height(), 128]);
622
-		if(!$this->image->centerCrop($size)) {
622
+		if (!$this->image->centerCrop($size)) {
623 623
 			$this->log->log('croping image for avatar failed for '.$this->dn, ILogger::ERROR);
624 624
 			return false;
625 625
 		}
626 626
 
627
-		if(!$this->fs->isLoaded()) {
627
+		if (!$this->fs->isLoaded()) {
628 628
 			$this->fs->setup($this->uid);
629 629
 		}
630 630
 
@@ -634,7 +634,7 @@  discard block
 block discarded – undo
634 634
 			return true;
635 635
 		} catch (\Exception $e) {
636 636
 			\OC::$server->getLogger()->logException($e, [
637
-				'message' => 'Could not set avatar for ' . $this->dn,
637
+				'message' => 'Could not set avatar for '.$this->dn,
638 638
 				'level' => ILogger::INFO,
639 639
 				'app' => 'user_ldap',
640 640
 			]);
@@ -668,7 +668,7 @@  discard block
 block discarded – undo
668 668
 	 * @throws \OC\ServerNotAvailableException
669 669
 	 */
670 670
 	public function updateExtStorageHome(string $valueFromLDAP = null):string {
671
-		if($valueFromLDAP === null) {
671
+		if ($valueFromLDAP === null) {
672 672
 			$extHomeValues = $this->access->readAttribute($this->getDN(), $this->connection->ldapExtStorageHomeAttribute);
673 673
 		} else {
674 674
 			$extHomeValues = [$valueFromLDAP];
@@ -690,18 +690,18 @@  discard block
 block discarded – undo
690 690
 	 */
691 691
 	public function handlePasswordExpiry($params) {
692 692
 		$ppolicyDN = $this->connection->ldapDefaultPPolicyDN;
693
-		if (empty($ppolicyDN) || ((int)$this->connection->turnOnPasswordChange !== 1)) {
694
-			return;//password expiry handling disabled
693
+		if (empty($ppolicyDN) || ((int) $this->connection->turnOnPasswordChange !== 1)) {
694
+			return; //password expiry handling disabled
695 695
 		}
696 696
 		$uid = $params['uid'];
697
-		if(isset($uid) && $uid === $this->getUsername()) {
697
+		if (isset($uid) && $uid === $this->getUsername()) {
698 698
 			//retrieve relevant user attributes
699 699
 			$result = $this->access->search('objectclass=*', array($this->dn), ['pwdpolicysubentry', 'pwdgraceusetime', 'pwdreset', 'pwdchangedtime']);
700 700
 			
701
-			if(array_key_exists('pwdpolicysubentry', $result[0])) {
701
+			if (array_key_exists('pwdpolicysubentry', $result[0])) {
702 702
 				$pwdPolicySubentry = $result[0]['pwdpolicysubentry'];
703
-				if($pwdPolicySubentry && (count($pwdPolicySubentry) > 0)){
704
-					$ppolicyDN = $pwdPolicySubentry[0];//custom ppolicy DN
703
+				if ($pwdPolicySubentry && (count($pwdPolicySubentry) > 0)) {
704
+					$ppolicyDN = $pwdPolicySubentry[0]; //custom ppolicy DN
705 705
 				}
706 706
 			}
707 707
 			
@@ -710,9 +710,9 @@  discard block
 block discarded – undo
710 710
 			$pwdChangedTime = array_key_exists('pwdchangedtime', $result[0]) ? $result[0]['pwdchangedtime'] : null;
711 711
 			
712 712
 			//retrieve relevant password policy attributes
713
-			$cacheKey = 'ppolicyAttributes' . $ppolicyDN;
713
+			$cacheKey = 'ppolicyAttributes'.$ppolicyDN;
714 714
 			$result = $this->connection->getFromCache($cacheKey);
715
-			if(is_null($result)) {
715
+			if (is_null($result)) {
716 716
 				$result = $this->access->search('objectclass=*', array($ppolicyDN), ['pwdgraceauthnlimit', 'pwdmaxage', 'pwdexpirewarning']);
717 717
 				$this->connection->writeToCache($cacheKey, $result);
718 718
 			}
@@ -723,10 +723,10 @@  discard block
 block discarded – undo
723 723
 			
724 724
 			//handle grace login
725 725
 			$pwdGraceUseTimeCount = count($pwdGraceUseTime);
726
-			if($pwdGraceUseTime && $pwdGraceUseTimeCount > 0) { //was this a grace login?
727
-				if($pwdGraceAuthNLimit 
726
+			if ($pwdGraceUseTime && $pwdGraceUseTimeCount > 0) { //was this a grace login?
727
+				if ($pwdGraceAuthNLimit 
728 728
 					&& (count($pwdGraceAuthNLimit) > 0)
729
-					&&($pwdGraceUseTimeCount < (int)$pwdGraceAuthNLimit[0])) { //at least one more grace login available?
729
+					&&($pwdGraceUseTimeCount < (int) $pwdGraceAuthNLimit[0])) { //at least one more grace login available?
730 730
 					$this->config->setUserValue($uid, 'user_ldap', 'needsPasswordReset', 'true');
731 731
 					header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute(
732 732
 					'user_ldap.renewPassword.showRenewPasswordForm', array('user' => $uid)));
@@ -737,24 +737,24 @@  discard block
 block discarded – undo
737 737
 				exit();
738 738
 			}
739 739
 			//handle pwdReset attribute
740
-			if($pwdReset && (count($pwdReset) > 0) && $pwdReset[0] === 'TRUE') { //user must change his password
740
+			if ($pwdReset && (count($pwdReset) > 0) && $pwdReset[0] === 'TRUE') { //user must change his password
741 741
 				$this->config->setUserValue($uid, 'user_ldap', 'needsPasswordReset', 'true');
742 742
 				header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute(
743 743
 				'user_ldap.renewPassword.showRenewPasswordForm', array('user' => $uid)));
744 744
 				exit();
745 745
 			}
746 746
 			//handle password expiry warning
747
-			if($pwdChangedTime && (count($pwdChangedTime) > 0)) {
748
-				if($pwdMaxAge && (count($pwdMaxAge) > 0)
747
+			if ($pwdChangedTime && (count($pwdChangedTime) > 0)) {
748
+				if ($pwdMaxAge && (count($pwdMaxAge) > 0)
749 749
 					&& $pwdExpireWarning && (count($pwdExpireWarning) > 0)) {
750
-					$pwdMaxAgeInt = (int)$pwdMaxAge[0];
751
-					$pwdExpireWarningInt = (int)$pwdExpireWarning[0];
752
-					if($pwdMaxAgeInt > 0 && $pwdExpireWarningInt > 0){
750
+					$pwdMaxAgeInt = (int) $pwdMaxAge[0];
751
+					$pwdExpireWarningInt = (int) $pwdExpireWarning[0];
752
+					if ($pwdMaxAgeInt > 0 && $pwdExpireWarningInt > 0) {
753 753
 						$pwdChangedTimeDt = \DateTime::createFromFormat('YmdHisZ', $pwdChangedTime[0]);
754 754
 						$pwdChangedTimeDt->add(new \DateInterval('PT'.$pwdMaxAgeInt.'S'));
755 755
 						$currentDateTime = new \DateTime();
756 756
 						$secondsToExpiry = $pwdChangedTimeDt->getTimestamp() - $currentDateTime->getTimestamp();
757
-						if($secondsToExpiry <= $pwdExpireWarningInt) {
757
+						if ($secondsToExpiry <= $pwdExpireWarningInt) {
758 758
 							//remove last password expiry warning if any
759 759
 							$notification = $this->notificationManager->createNotification();
760 760
 							$notification->setApp('user_ldap')
Please login to merge, or discard this patch.