Completed
Push — master ( 3f352d...7de6f7 )
by Lukas
84:08 queued 69:49
created
apps/user_ldap/lib/Connection.php 1 patch
Indentation   +577 added lines, -577 removed lines patch added patch discarded remove patch
@@ -52,582 +52,582 @@
 block discarded – undo
52 52
  * @property string ldapUuidGroupAttribute
53 53
  */
54 54
 class Connection extends LDAPUtility {
55
-	private $ldapConnectionRes = null;
56
-	private $configPrefix;
57
-	private $configID;
58
-	private $configured = false;
59
-	private $hasPagedResultSupport = true;
60
-	//whether connection should be kept on __destruct
61
-	private $dontDestruct = false;
62
-
63
-	/**
64
-	 * @var bool runtime flag that indicates whether supported primary groups are available
65
-	 */
66
-	public $hasPrimaryGroups = true;
67
-
68
-	/**
69
-	 * @var bool runtime flag that indicates whether supported POSIX gidNumber are available
70
-	 */
71
-	public $hasGidNumber = true;
72
-
73
-	//cache handler
74
-	protected $cache;
75
-
76
-	/** @var Configuration settings handler **/
77
-	protected $configuration;
78
-
79
-	protected $doNotValidate = false;
80
-
81
-	protected $ignoreValidation = false;
82
-
83
-	/**
84
-	 * Constructor
85
-	 * @param ILDAPWrapper $ldap
86
-	 * @param string $configPrefix a string with the prefix for the configkey column (appconfig table)
87
-	 * @param string|null $configID a string with the value for the appid column (appconfig table) or null for on-the-fly connections
88
-	 */
89
-	public function __construct(ILDAPWrapper $ldap, $configPrefix = '', $configID = 'user_ldap') {
90
-		parent::__construct($ldap);
91
-		$this->configPrefix = $configPrefix;
92
-		$this->configID = $configID;
93
-		$this->configuration = new Configuration($configPrefix,
94
-												 !is_null($configID));
95
-		$memcache = \OC::$server->getMemCacheFactory();
96
-		if($memcache->isAvailable()) {
97
-			$this->cache = $memcache->create();
98
-		}
99
-		$helper = new Helper(\OC::$server->getConfig());
100
-		$this->doNotValidate = !in_array($this->configPrefix,
101
-			$helper->getServerConfigurationPrefixes());
102
-		$this->hasPagedResultSupport =
103
-			intval($this->configuration->ldapPagingSize) !== 0
104
-			|| $this->ldap->hasPagedResultSupport();
105
-	}
106
-
107
-	public function __destruct() {
108
-		if(!$this->dontDestruct && $this->ldap->isResource($this->ldapConnectionRes)) {
109
-			@$this->ldap->unbind($this->ldapConnectionRes);
110
-		};
111
-	}
112
-
113
-	/**
114
-	 * defines behaviour when the instance is cloned
115
-	 */
116
-	public function __clone() {
117
-		$this->configuration = new Configuration($this->configPrefix,
118
-												 !is_null($this->configID));
119
-		$this->ldapConnectionRes = null;
120
-		$this->dontDestruct = true;
121
-	}
122
-
123
-	/**
124
-	 * @param string $name
125
-	 * @return bool|mixed|void
126
-	 */
127
-	public function __get($name) {
128
-		if(!$this->configured) {
129
-			$this->readConfiguration();
130
-		}
131
-
132
-		if($name === 'hasPagedResultSupport') {
133
-			return $this->hasPagedResultSupport;
134
-		}
135
-
136
-		return $this->configuration->$name;
137
-	}
138
-
139
-	/**
140
-	 * @param string $name
141
-	 * @param mixed $value
142
-	 */
143
-	public function __set($name, $value) {
144
-		$this->doNotValidate = false;
145
-		$before = $this->configuration->$name;
146
-		$this->configuration->$name = $value;
147
-		$after = $this->configuration->$name;
148
-		if($before !== $after) {
149
-			if ($this->configID !== '') {
150
-				$this->configuration->saveConfiguration();
151
-			}
152
-			$this->validateConfiguration();
153
-		}
154
-	}
155
-
156
-	/**
157
-	 * sets whether the result of the configuration validation shall
158
-	 * be ignored when establishing the connection. Used by the Wizard
159
-	 * in early configuration state.
160
-	 * @param bool $state
161
-	 */
162
-	public function setIgnoreValidation($state) {
163
-		$this->ignoreValidation = (bool)$state;
164
-	}
165
-
166
-	/**
167
-	 * initializes the LDAP backend
168
-	 * @param bool $force read the config settings no matter what
169
-	 */
170
-	public function init($force = false) {
171
-		$this->readConfiguration($force);
172
-		$this->establishConnection();
173
-	}
174
-
175
-	/**
176
-	 * Returns the LDAP handler
177
-	 */
178
-	public function getConnectionResource() {
179
-		if(!$this->ldapConnectionRes) {
180
-			$this->init();
181
-		} else if(!$this->ldap->isResource($this->ldapConnectionRes)) {
182
-			$this->ldapConnectionRes = null;
183
-			$this->establishConnection();
184
-		}
185
-		if(is_null($this->ldapConnectionRes)) {
186
-			\OCP\Util::writeLog('user_ldap', 'No LDAP Connection to server ' . $this->configuration->ldapHost, \OCP\Util::ERROR);
187
-			throw new ServerNotAvailableException('Connection to LDAP server could not be established');
188
-		}
189
-		return $this->ldapConnectionRes;
190
-	}
191
-
192
-	/**
193
-	 * resets the connection resource
194
-	 */
195
-	public function resetConnectionResource() {
196
-		if(!is_null($this->ldapConnectionRes)) {
197
-			@$this->ldap->unbind($this->ldapConnectionRes);
198
-			$this->ldapConnectionRes = null;
199
-		}
200
-	}
201
-
202
-	/**
203
-	 * @param string|null $key
204
-	 * @return string
205
-	 */
206
-	private function getCacheKey($key) {
207
-		$prefix = 'LDAP-'.$this->configID.'-'.$this->configPrefix.'-';
208
-		if(is_null($key)) {
209
-			return $prefix;
210
-		}
211
-		return $prefix.md5($key);
212
-	}
213
-
214
-	/**
215
-	 * @param string $key
216
-	 * @return mixed|null
217
-	 */
218
-	public function getFromCache($key) {
219
-		if(!$this->configured) {
220
-			$this->readConfiguration();
221
-		}
222
-		if(is_null($this->cache) || !$this->configuration->ldapCacheTTL) {
223
-			return null;
224
-		}
225
-		$key = $this->getCacheKey($key);
226
-
227
-		return json_decode(base64_decode($this->cache->get($key)), true);
228
-	}
229
-
230
-	/**
231
-	 * @param string $key
232
-	 * @param mixed $value
233
-	 *
234
-	 * @return string
235
-	 */
236
-	public function writeToCache($key, $value) {
237
-		if(!$this->configured) {
238
-			$this->readConfiguration();
239
-		}
240
-		if(is_null($this->cache)
241
-			|| !$this->configuration->ldapCacheTTL
242
-			|| !$this->configuration->ldapConfigurationActive) {
243
-			return null;
244
-		}
245
-		$key   = $this->getCacheKey($key);
246
-		$value = base64_encode(json_encode($value));
247
-		$this->cache->set($key, $value, $this->configuration->ldapCacheTTL);
248
-	}
249
-
250
-	public function clearCache() {
251
-		if(!is_null($this->cache)) {
252
-			$this->cache->clear($this->getCacheKey(null));
253
-		}
254
-	}
255
-
256
-	/**
257
-	 * Caches the general LDAP configuration.
258
-	 * @param bool $force optional. true, if the re-read should be forced. defaults
259
-	 * to false.
260
-	 * @return null
261
-	 */
262
-	private function readConfiguration($force = false) {
263
-		if((!$this->configured || $force) && !is_null($this->configID)) {
264
-			$this->configuration->readConfiguration();
265
-			$this->configured = $this->validateConfiguration();
266
-		}
267
-	}
268
-
269
-	/**
270
-	 * set LDAP configuration with values delivered by an array, not read from configuration
271
-	 * @param array $config array that holds the config parameters in an associated array
272
-	 * @param array &$setParameters optional; array where the set fields will be given to
273
-	 * @return boolean true if config validates, false otherwise. Check with $setParameters for detailed success on single parameters
274
-	 */
275
-	public function setConfiguration($config, &$setParameters = null) {
276
-		if(is_null($setParameters)) {
277
-			$setParameters = array();
278
-		}
279
-		$this->doNotValidate = false;
280
-		$this->configuration->setConfiguration($config, $setParameters);
281
-		if(count($setParameters) > 0) {
282
-			$this->configured = $this->validateConfiguration();
283
-		}
284
-
285
-
286
-		return $this->configured;
287
-	}
288
-
289
-	/**
290
-	 * saves the current Configuration in the database and empties the
291
-	 * cache
292
-	 * @return null
293
-	 */
294
-	public function saveConfiguration() {
295
-		$this->configuration->saveConfiguration();
296
-		$this->clearCache();
297
-	}
298
-
299
-	/**
300
-	 * get the current LDAP configuration
301
-	 * @return array
302
-	 */
303
-	public function getConfiguration() {
304
-		$this->readConfiguration();
305
-		$config = $this->configuration->getConfiguration();
306
-		$cta = $this->configuration->getConfigTranslationArray();
307
-		$result = array();
308
-		foreach($cta as $dbkey => $configkey) {
309
-			switch($configkey) {
310
-				case 'homeFolderNamingRule':
311
-					if(strpos($config[$configkey], 'attr:') === 0) {
312
-						$result[$dbkey] = substr($config[$configkey], 5);
313
-					} else {
314
-						$result[$dbkey] = '';
315
-					}
316
-					break;
317
-				case 'ldapBase':
318
-				case 'ldapBaseUsers':
319
-				case 'ldapBaseGroups':
320
-				case 'ldapAttributesForUserSearch':
321
-				case 'ldapAttributesForGroupSearch':
322
-					if(is_array($config[$configkey])) {
323
-						$result[$dbkey] = implode("\n", $config[$configkey]);
324
-						break;
325
-					} //else follows default
326
-				default:
327
-					$result[$dbkey] = $config[$configkey];
328
-			}
329
-		}
330
-		return $result;
331
-	}
332
-
333
-	private function doSoftValidation() {
334
-		//if User or Group Base are not set, take over Base DN setting
335
-		foreach(array('ldapBaseUsers', 'ldapBaseGroups') as $keyBase) {
336
-			$val = $this->configuration->$keyBase;
337
-			if(empty($val)) {
338
-				$this->configuration->$keyBase = $this->configuration->ldapBase;
339
-			}
340
-		}
341
-
342
-		foreach(array('ldapExpertUUIDUserAttr'  => 'ldapUuidUserAttribute',
343
-					  'ldapExpertUUIDGroupAttr' => 'ldapUuidGroupAttribute')
344
-				as $expertSetting => $effectiveSetting) {
345
-			$uuidOverride = $this->configuration->$expertSetting;
346
-			if(!empty($uuidOverride)) {
347
-				$this->configuration->$effectiveSetting = $uuidOverride;
348
-			} else {
349
-				$uuidAttributes = array('auto', 'entryuuid', 'nsuniqueid',
350
-										'objectguid', 'guid', 'ipauniqueid');
351
-				if(!in_array($this->configuration->$effectiveSetting,
352
-							$uuidAttributes)
353
-					&& (!is_null($this->configID))) {
354
-					$this->configuration->$effectiveSetting = 'auto';
355
-					$this->configuration->saveConfiguration();
356
-					\OCP\Util::writeLog('user_ldap',
357
-										'Illegal value for the '.
358
-										$effectiveSetting.', '.'reset to '.
359
-										'autodetect.', \OCP\Util::INFO);
360
-				}
361
-
362
-			}
363
-		}
364
-
365
-		$backupPort = intval($this->configuration->ldapBackupPort);
366
-		if ($backupPort <= 0) {
367
-			$this->configuration->backupPort = $this->configuration->ldapPort;
368
-		}
369
-
370
-		//make sure empty search attributes are saved as simple, empty array
371
-		$saKeys = array('ldapAttributesForUserSearch',
372
-						'ldapAttributesForGroupSearch');
373
-		foreach($saKeys as $key) {
374
-			$val = $this->configuration->$key;
375
-			if(is_array($val) && count($val) === 1 && empty($val[0])) {
376
-				$this->configuration->$key = array();
377
-			}
378
-		}
379
-
380
-		if((stripos($this->configuration->ldapHost, 'ldaps://') === 0)
381
-			&& $this->configuration->ldapTLS) {
382
-			$this->configuration->ldapTLS = false;
383
-			\OCP\Util::writeLog('user_ldap',
384
-								'LDAPS (already using secure connection) and '.
385
-								'TLS do not work together. Switched off TLS.',
386
-								\OCP\Util::INFO);
387
-		}
388
-	}
389
-
390
-	/**
391
-	 * @return bool
392
-	 */
393
-	private function doCriticalValidation() {
394
-		$configurationOK = true;
395
-		$errorStr = 'Configuration Error (prefix '.
396
-					strval($this->configPrefix).'): ';
397
-
398
-		//options that shall not be empty
399
-		$options = array('ldapHost', 'ldapPort', 'ldapUserDisplayName',
400
-						 'ldapGroupDisplayName', 'ldapLoginFilter');
401
-		foreach($options as $key) {
402
-			$val = $this->configuration->$key;
403
-			if(empty($val)) {
404
-				switch($key) {
405
-					case 'ldapHost':
406
-						$subj = 'LDAP Host';
407
-						break;
408
-					case 'ldapPort':
409
-						$subj = 'LDAP Port';
410
-						break;
411
-					case 'ldapUserDisplayName':
412
-						$subj = 'LDAP User Display Name';
413
-						break;
414
-					case 'ldapGroupDisplayName':
415
-						$subj = 'LDAP Group Display Name';
416
-						break;
417
-					case 'ldapLoginFilter':
418
-						$subj = 'LDAP Login Filter';
419
-						break;
420
-					default:
421
-						$subj = $key;
422
-						break;
423
-				}
424
-				$configurationOK = false;
425
-				\OCP\Util::writeLog('user_ldap',
426
-									$errorStr.'No '.$subj.' given!',
427
-									\OCP\Util::WARN);
428
-			}
429
-		}
430
-
431
-		//combinations
432
-		$agent = $this->configuration->ldapAgentName;
433
-		$pwd = $this->configuration->ldapAgentPassword;
434
-		if (
435
-			($agent === ''  && $pwd !== '')
436
-			|| ($agent !== '' && $pwd === '')
437
-		) {
438
-			\OCP\Util::writeLog('user_ldap',
439
-								$errorStr.'either no password is given for the '.
440
-								'user agent or a password is given, but not an '.
441
-								'LDAP agent.',
442
-				\OCP\Util::WARN);
443
-			$configurationOK = false;
444
-		}
445
-
446
-		$base = $this->configuration->ldapBase;
447
-		$baseUsers = $this->configuration->ldapBaseUsers;
448
-		$baseGroups = $this->configuration->ldapBaseGroups;
449
-
450
-		if(empty($base) && empty($baseUsers) && empty($baseGroups)) {
451
-			\OCP\Util::writeLog('user_ldap',
452
-								$errorStr.'Not a single Base DN given.',
453
-								\OCP\Util::WARN);
454
-			$configurationOK = false;
455
-		}
456
-
457
-		if(mb_strpos($this->configuration->ldapLoginFilter, '%uid', 0, 'UTF-8')
458
-		   === false) {
459
-			\OCP\Util::writeLog('user_ldap',
460
-								$errorStr.'login filter does not contain %uid '.
461
-								'place holder.',
462
-								\OCP\Util::WARN);
463
-			$configurationOK = false;
464
-		}
465
-
466
-		return $configurationOK;
467
-	}
468
-
469
-	/**
470
-	 * Validates the user specified configuration
471
-	 * @return bool true if configuration seems OK, false otherwise
472
-	 */
473
-	private function validateConfiguration() {
474
-
475
-		if($this->doNotValidate) {
476
-			//don't do a validation if it is a new configuration with pure
477
-			//default values. Will be allowed on changes via __set or
478
-			//setConfiguration
479
-			return false;
480
-		}
481
-
482
-		// first step: "soft" checks: settings that are not really
483
-		// necessary, but advisable. If left empty, give an info message
484
-		$this->doSoftValidation();
485
-
486
-		//second step: critical checks. If left empty or filled wrong, mark as
487
-		//not configured and give a warning.
488
-		return $this->doCriticalValidation();
489
-	}
490
-
491
-
492
-	/**
493
-	 * Connects and Binds to LDAP
494
-	 */
495
-	private function establishConnection() {
496
-		if(!$this->configuration->ldapConfigurationActive) {
497
-			return null;
498
-		}
499
-		static $phpLDAPinstalled = true;
500
-		if(!$phpLDAPinstalled) {
501
-			return false;
502
-		}
503
-		if(!$this->ignoreValidation && !$this->configured) {
504
-			\OCP\Util::writeLog('user_ldap',
505
-								'Configuration is invalid, cannot connect',
506
-								\OCP\Util::WARN);
507
-			return false;
508
-		}
509
-		if(!$this->ldapConnectionRes) {
510
-			if(!$this->ldap->areLDAPFunctionsAvailable()) {
511
-				$phpLDAPinstalled = false;
512
-				\OCP\Util::writeLog('user_ldap',
513
-									'function ldap_connect is not available. Make '.
514
-									'sure that the PHP ldap module is installed.',
515
-									\OCP\Util::ERROR);
516
-
517
-				return false;
518
-			}
519
-			if($this->configuration->turnOffCertCheck) {
520
-				if(putenv('LDAPTLS_REQCERT=never')) {
521
-					\OCP\Util::writeLog('user_ldap',
522
-						'Turned off SSL certificate validation successfully.',
523
-						\OCP\Util::DEBUG);
524
-				} else {
525
-					\OCP\Util::writeLog('user_ldap',
526
-										'Could not turn off SSL certificate validation.',
527
-										\OCP\Util::WARN);
528
-				}
529
-			}
530
-
531
-			$isOverrideMainServer = ($this->configuration->ldapOverrideMainServer
532
-				|| $this->getFromCache('overrideMainServer'));
533
-			$isBackupHost = (trim($this->configuration->ldapBackupHost) !== "");
534
-			$bindStatus = false;
535
-			$error = -1;
536
-			try {
537
-				if (!$isOverrideMainServer) {
538
-					$this->doConnect($this->configuration->ldapHost,
539
-						$this->configuration->ldapPort);
540
-					$bindStatus = $this->bind();
541
-					$error = $this->ldap->isResource($this->ldapConnectionRes) ?
542
-						$this->ldap->errno($this->ldapConnectionRes) : -1;
543
-				}
544
-				if($bindStatus === true) {
545
-					return $bindStatus;
546
-				}
547
-			} catch (ServerNotAvailableException $e) {
548
-				if(!$isBackupHost) {
549
-					throw $e;
550
-				}
551
-			}
552
-
553
-			//if LDAP server is not reachable, try the Backup (Replica!) Server
554
-			if($isBackupHost && ($error !== 0 || $isOverrideMainServer)) {
555
-				$this->doConnect($this->configuration->ldapBackupHost,
556
-								 $this->configuration->ldapBackupPort);
557
-				$bindStatus = $this->bind();
558
-				$error = $this->ldap->isResource($this->ldapConnectionRes) ?
559
-					$this->ldap->errno($this->ldapConnectionRes) : -1;
560
-				if($bindStatus && $error === 0 && !$this->getFromCache('overrideMainServer')) {
561
-					//when bind to backup server succeeded and failed to main server,
562
-					//skip contacting him until next cache refresh
563
-					$this->writeToCache('overrideMainServer', true);
564
-				}
565
-			}
566
-
567
-			return $bindStatus;
568
-		}
569
-		return null;
570
-	}
571
-
572
-	/**
573
-	 * @param string $host
574
-	 * @param string $port
575
-	 * @return bool
576
-	 * @throws \OC\ServerNotAvailableException
577
-	 */
578
-	private function doConnect($host, $port) {
579
-		if ($host === '') {
580
-			return false;
581
-		}
582
-
583
-		$this->ldapConnectionRes = $this->ldap->connect($host, $port);
584
-
585
-		if(!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
586
-			throw new ServerNotAvailableException('Could not set required LDAP Protocol version.');
587
-		}
588
-
589
-		if(!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
590
-			throw new ServerNotAvailableException('Could not disable LDAP referrals.');
591
-		}
592
-
593
-		if($this->configuration->ldapTLS) {
594
-			if(!$this->ldap->startTls($this->ldapConnectionRes)) {
595
-				throw new ServerNotAvailableException('Start TLS failed, when connecting to LDAP host ' . $host . '.');
596
-			}
597
-		}
598
-
599
-		return true;
600
-	}
601
-
602
-	/**
603
-	 * Binds to LDAP
604
-	 */
605
-	public function bind() {
606
-		if(!$this->configuration->ldapConfigurationActive) {
607
-			return false;
608
-		}
609
-		$cr = $this->getConnectionResource();
610
-		if(!$this->ldap->isResource($cr)) {
611
-			return false;
612
-		}
613
-		$ldapLogin = @$this->ldap->bind($cr,
614
-										$this->configuration->ldapAgentName,
615
-										$this->configuration->ldapAgentPassword);
616
-		if(!$ldapLogin) {
617
-			$errno = $this->ldap->errno($cr);
618
-
619
-			\OCP\Util::writeLog('user_ldap',
620
-				'Bind failed: ' . $errno . ': ' . $this->ldap->error($cr),
621
-				\OCP\Util::WARN);
622
-
623
-			// Set to failure mode, if LDAP error code is not LDAP_SUCCESS or LDAP_INVALID_CREDENTIALS
624
-			if($errno !== 0x00 && $errno !== 0x31) {
625
-				$this->ldapConnectionRes = null;
626
-			}
627
-
628
-			return false;
629
-		}
630
-		return true;
631
-	}
55
+    private $ldapConnectionRes = null;
56
+    private $configPrefix;
57
+    private $configID;
58
+    private $configured = false;
59
+    private $hasPagedResultSupport = true;
60
+    //whether connection should be kept on __destruct
61
+    private $dontDestruct = false;
62
+
63
+    /**
64
+     * @var bool runtime flag that indicates whether supported primary groups are available
65
+     */
66
+    public $hasPrimaryGroups = true;
67
+
68
+    /**
69
+     * @var bool runtime flag that indicates whether supported POSIX gidNumber are available
70
+     */
71
+    public $hasGidNumber = true;
72
+
73
+    //cache handler
74
+    protected $cache;
75
+
76
+    /** @var Configuration settings handler **/
77
+    protected $configuration;
78
+
79
+    protected $doNotValidate = false;
80
+
81
+    protected $ignoreValidation = false;
82
+
83
+    /**
84
+     * Constructor
85
+     * @param ILDAPWrapper $ldap
86
+     * @param string $configPrefix a string with the prefix for the configkey column (appconfig table)
87
+     * @param string|null $configID a string with the value for the appid column (appconfig table) or null for on-the-fly connections
88
+     */
89
+    public function __construct(ILDAPWrapper $ldap, $configPrefix = '', $configID = 'user_ldap') {
90
+        parent::__construct($ldap);
91
+        $this->configPrefix = $configPrefix;
92
+        $this->configID = $configID;
93
+        $this->configuration = new Configuration($configPrefix,
94
+                                                    !is_null($configID));
95
+        $memcache = \OC::$server->getMemCacheFactory();
96
+        if($memcache->isAvailable()) {
97
+            $this->cache = $memcache->create();
98
+        }
99
+        $helper = new Helper(\OC::$server->getConfig());
100
+        $this->doNotValidate = !in_array($this->configPrefix,
101
+            $helper->getServerConfigurationPrefixes());
102
+        $this->hasPagedResultSupport =
103
+            intval($this->configuration->ldapPagingSize) !== 0
104
+            || $this->ldap->hasPagedResultSupport();
105
+    }
106
+
107
+    public function __destruct() {
108
+        if(!$this->dontDestruct && $this->ldap->isResource($this->ldapConnectionRes)) {
109
+            @$this->ldap->unbind($this->ldapConnectionRes);
110
+        };
111
+    }
112
+
113
+    /**
114
+     * defines behaviour when the instance is cloned
115
+     */
116
+    public function __clone() {
117
+        $this->configuration = new Configuration($this->configPrefix,
118
+                                                    !is_null($this->configID));
119
+        $this->ldapConnectionRes = null;
120
+        $this->dontDestruct = true;
121
+    }
122
+
123
+    /**
124
+     * @param string $name
125
+     * @return bool|mixed|void
126
+     */
127
+    public function __get($name) {
128
+        if(!$this->configured) {
129
+            $this->readConfiguration();
130
+        }
131
+
132
+        if($name === 'hasPagedResultSupport') {
133
+            return $this->hasPagedResultSupport;
134
+        }
135
+
136
+        return $this->configuration->$name;
137
+    }
138
+
139
+    /**
140
+     * @param string $name
141
+     * @param mixed $value
142
+     */
143
+    public function __set($name, $value) {
144
+        $this->doNotValidate = false;
145
+        $before = $this->configuration->$name;
146
+        $this->configuration->$name = $value;
147
+        $after = $this->configuration->$name;
148
+        if($before !== $after) {
149
+            if ($this->configID !== '') {
150
+                $this->configuration->saveConfiguration();
151
+            }
152
+            $this->validateConfiguration();
153
+        }
154
+    }
155
+
156
+    /**
157
+     * sets whether the result of the configuration validation shall
158
+     * be ignored when establishing the connection. Used by the Wizard
159
+     * in early configuration state.
160
+     * @param bool $state
161
+     */
162
+    public function setIgnoreValidation($state) {
163
+        $this->ignoreValidation = (bool)$state;
164
+    }
165
+
166
+    /**
167
+     * initializes the LDAP backend
168
+     * @param bool $force read the config settings no matter what
169
+     */
170
+    public function init($force = false) {
171
+        $this->readConfiguration($force);
172
+        $this->establishConnection();
173
+    }
174
+
175
+    /**
176
+     * Returns the LDAP handler
177
+     */
178
+    public function getConnectionResource() {
179
+        if(!$this->ldapConnectionRes) {
180
+            $this->init();
181
+        } else if(!$this->ldap->isResource($this->ldapConnectionRes)) {
182
+            $this->ldapConnectionRes = null;
183
+            $this->establishConnection();
184
+        }
185
+        if(is_null($this->ldapConnectionRes)) {
186
+            \OCP\Util::writeLog('user_ldap', 'No LDAP Connection to server ' . $this->configuration->ldapHost, \OCP\Util::ERROR);
187
+            throw new ServerNotAvailableException('Connection to LDAP server could not be established');
188
+        }
189
+        return $this->ldapConnectionRes;
190
+    }
191
+
192
+    /**
193
+     * resets the connection resource
194
+     */
195
+    public function resetConnectionResource() {
196
+        if(!is_null($this->ldapConnectionRes)) {
197
+            @$this->ldap->unbind($this->ldapConnectionRes);
198
+            $this->ldapConnectionRes = null;
199
+        }
200
+    }
201
+
202
+    /**
203
+     * @param string|null $key
204
+     * @return string
205
+     */
206
+    private function getCacheKey($key) {
207
+        $prefix = 'LDAP-'.$this->configID.'-'.$this->configPrefix.'-';
208
+        if(is_null($key)) {
209
+            return $prefix;
210
+        }
211
+        return $prefix.md5($key);
212
+    }
213
+
214
+    /**
215
+     * @param string $key
216
+     * @return mixed|null
217
+     */
218
+    public function getFromCache($key) {
219
+        if(!$this->configured) {
220
+            $this->readConfiguration();
221
+        }
222
+        if(is_null($this->cache) || !$this->configuration->ldapCacheTTL) {
223
+            return null;
224
+        }
225
+        $key = $this->getCacheKey($key);
226
+
227
+        return json_decode(base64_decode($this->cache->get($key)), true);
228
+    }
229
+
230
+    /**
231
+     * @param string $key
232
+     * @param mixed $value
233
+     *
234
+     * @return string
235
+     */
236
+    public function writeToCache($key, $value) {
237
+        if(!$this->configured) {
238
+            $this->readConfiguration();
239
+        }
240
+        if(is_null($this->cache)
241
+            || !$this->configuration->ldapCacheTTL
242
+            || !$this->configuration->ldapConfigurationActive) {
243
+            return null;
244
+        }
245
+        $key   = $this->getCacheKey($key);
246
+        $value = base64_encode(json_encode($value));
247
+        $this->cache->set($key, $value, $this->configuration->ldapCacheTTL);
248
+    }
249
+
250
+    public function clearCache() {
251
+        if(!is_null($this->cache)) {
252
+            $this->cache->clear($this->getCacheKey(null));
253
+        }
254
+    }
255
+
256
+    /**
257
+     * Caches the general LDAP configuration.
258
+     * @param bool $force optional. true, if the re-read should be forced. defaults
259
+     * to false.
260
+     * @return null
261
+     */
262
+    private function readConfiguration($force = false) {
263
+        if((!$this->configured || $force) && !is_null($this->configID)) {
264
+            $this->configuration->readConfiguration();
265
+            $this->configured = $this->validateConfiguration();
266
+        }
267
+    }
268
+
269
+    /**
270
+     * set LDAP configuration with values delivered by an array, not read from configuration
271
+     * @param array $config array that holds the config parameters in an associated array
272
+     * @param array &$setParameters optional; array where the set fields will be given to
273
+     * @return boolean true if config validates, false otherwise. Check with $setParameters for detailed success on single parameters
274
+     */
275
+    public function setConfiguration($config, &$setParameters = null) {
276
+        if(is_null($setParameters)) {
277
+            $setParameters = array();
278
+        }
279
+        $this->doNotValidate = false;
280
+        $this->configuration->setConfiguration($config, $setParameters);
281
+        if(count($setParameters) > 0) {
282
+            $this->configured = $this->validateConfiguration();
283
+        }
284
+
285
+
286
+        return $this->configured;
287
+    }
288
+
289
+    /**
290
+     * saves the current Configuration in the database and empties the
291
+     * cache
292
+     * @return null
293
+     */
294
+    public function saveConfiguration() {
295
+        $this->configuration->saveConfiguration();
296
+        $this->clearCache();
297
+    }
298
+
299
+    /**
300
+     * get the current LDAP configuration
301
+     * @return array
302
+     */
303
+    public function getConfiguration() {
304
+        $this->readConfiguration();
305
+        $config = $this->configuration->getConfiguration();
306
+        $cta = $this->configuration->getConfigTranslationArray();
307
+        $result = array();
308
+        foreach($cta as $dbkey => $configkey) {
309
+            switch($configkey) {
310
+                case 'homeFolderNamingRule':
311
+                    if(strpos($config[$configkey], 'attr:') === 0) {
312
+                        $result[$dbkey] = substr($config[$configkey], 5);
313
+                    } else {
314
+                        $result[$dbkey] = '';
315
+                    }
316
+                    break;
317
+                case 'ldapBase':
318
+                case 'ldapBaseUsers':
319
+                case 'ldapBaseGroups':
320
+                case 'ldapAttributesForUserSearch':
321
+                case 'ldapAttributesForGroupSearch':
322
+                    if(is_array($config[$configkey])) {
323
+                        $result[$dbkey] = implode("\n", $config[$configkey]);
324
+                        break;
325
+                    } //else follows default
326
+                default:
327
+                    $result[$dbkey] = $config[$configkey];
328
+            }
329
+        }
330
+        return $result;
331
+    }
332
+
333
+    private function doSoftValidation() {
334
+        //if User or Group Base are not set, take over Base DN setting
335
+        foreach(array('ldapBaseUsers', 'ldapBaseGroups') as $keyBase) {
336
+            $val = $this->configuration->$keyBase;
337
+            if(empty($val)) {
338
+                $this->configuration->$keyBase = $this->configuration->ldapBase;
339
+            }
340
+        }
341
+
342
+        foreach(array('ldapExpertUUIDUserAttr'  => 'ldapUuidUserAttribute',
343
+                        'ldapExpertUUIDGroupAttr' => 'ldapUuidGroupAttribute')
344
+                as $expertSetting => $effectiveSetting) {
345
+            $uuidOverride = $this->configuration->$expertSetting;
346
+            if(!empty($uuidOverride)) {
347
+                $this->configuration->$effectiveSetting = $uuidOverride;
348
+            } else {
349
+                $uuidAttributes = array('auto', 'entryuuid', 'nsuniqueid',
350
+                                        'objectguid', 'guid', 'ipauniqueid');
351
+                if(!in_array($this->configuration->$effectiveSetting,
352
+                            $uuidAttributes)
353
+                    && (!is_null($this->configID))) {
354
+                    $this->configuration->$effectiveSetting = 'auto';
355
+                    $this->configuration->saveConfiguration();
356
+                    \OCP\Util::writeLog('user_ldap',
357
+                                        'Illegal value for the '.
358
+                                        $effectiveSetting.', '.'reset to '.
359
+                                        'autodetect.', \OCP\Util::INFO);
360
+                }
361
+
362
+            }
363
+        }
364
+
365
+        $backupPort = intval($this->configuration->ldapBackupPort);
366
+        if ($backupPort <= 0) {
367
+            $this->configuration->backupPort = $this->configuration->ldapPort;
368
+        }
369
+
370
+        //make sure empty search attributes are saved as simple, empty array
371
+        $saKeys = array('ldapAttributesForUserSearch',
372
+                        'ldapAttributesForGroupSearch');
373
+        foreach($saKeys as $key) {
374
+            $val = $this->configuration->$key;
375
+            if(is_array($val) && count($val) === 1 && empty($val[0])) {
376
+                $this->configuration->$key = array();
377
+            }
378
+        }
379
+
380
+        if((stripos($this->configuration->ldapHost, 'ldaps://') === 0)
381
+            && $this->configuration->ldapTLS) {
382
+            $this->configuration->ldapTLS = false;
383
+            \OCP\Util::writeLog('user_ldap',
384
+                                'LDAPS (already using secure connection) and '.
385
+                                'TLS do not work together. Switched off TLS.',
386
+                                \OCP\Util::INFO);
387
+        }
388
+    }
389
+
390
+    /**
391
+     * @return bool
392
+     */
393
+    private function doCriticalValidation() {
394
+        $configurationOK = true;
395
+        $errorStr = 'Configuration Error (prefix '.
396
+                    strval($this->configPrefix).'): ';
397
+
398
+        //options that shall not be empty
399
+        $options = array('ldapHost', 'ldapPort', 'ldapUserDisplayName',
400
+                            'ldapGroupDisplayName', 'ldapLoginFilter');
401
+        foreach($options as $key) {
402
+            $val = $this->configuration->$key;
403
+            if(empty($val)) {
404
+                switch($key) {
405
+                    case 'ldapHost':
406
+                        $subj = 'LDAP Host';
407
+                        break;
408
+                    case 'ldapPort':
409
+                        $subj = 'LDAP Port';
410
+                        break;
411
+                    case 'ldapUserDisplayName':
412
+                        $subj = 'LDAP User Display Name';
413
+                        break;
414
+                    case 'ldapGroupDisplayName':
415
+                        $subj = 'LDAP Group Display Name';
416
+                        break;
417
+                    case 'ldapLoginFilter':
418
+                        $subj = 'LDAP Login Filter';
419
+                        break;
420
+                    default:
421
+                        $subj = $key;
422
+                        break;
423
+                }
424
+                $configurationOK = false;
425
+                \OCP\Util::writeLog('user_ldap',
426
+                                    $errorStr.'No '.$subj.' given!',
427
+                                    \OCP\Util::WARN);
428
+            }
429
+        }
430
+
431
+        //combinations
432
+        $agent = $this->configuration->ldapAgentName;
433
+        $pwd = $this->configuration->ldapAgentPassword;
434
+        if (
435
+            ($agent === ''  && $pwd !== '')
436
+            || ($agent !== '' && $pwd === '')
437
+        ) {
438
+            \OCP\Util::writeLog('user_ldap',
439
+                                $errorStr.'either no password is given for the '.
440
+                                'user agent or a password is given, but not an '.
441
+                                'LDAP agent.',
442
+                \OCP\Util::WARN);
443
+            $configurationOK = false;
444
+        }
445
+
446
+        $base = $this->configuration->ldapBase;
447
+        $baseUsers = $this->configuration->ldapBaseUsers;
448
+        $baseGroups = $this->configuration->ldapBaseGroups;
449
+
450
+        if(empty($base) && empty($baseUsers) && empty($baseGroups)) {
451
+            \OCP\Util::writeLog('user_ldap',
452
+                                $errorStr.'Not a single Base DN given.',
453
+                                \OCP\Util::WARN);
454
+            $configurationOK = false;
455
+        }
456
+
457
+        if(mb_strpos($this->configuration->ldapLoginFilter, '%uid', 0, 'UTF-8')
458
+            === false) {
459
+            \OCP\Util::writeLog('user_ldap',
460
+                                $errorStr.'login filter does not contain %uid '.
461
+                                'place holder.',
462
+                                \OCP\Util::WARN);
463
+            $configurationOK = false;
464
+        }
465
+
466
+        return $configurationOK;
467
+    }
468
+
469
+    /**
470
+     * Validates the user specified configuration
471
+     * @return bool true if configuration seems OK, false otherwise
472
+     */
473
+    private function validateConfiguration() {
474
+
475
+        if($this->doNotValidate) {
476
+            //don't do a validation if it is a new configuration with pure
477
+            //default values. Will be allowed on changes via __set or
478
+            //setConfiguration
479
+            return false;
480
+        }
481
+
482
+        // first step: "soft" checks: settings that are not really
483
+        // necessary, but advisable. If left empty, give an info message
484
+        $this->doSoftValidation();
485
+
486
+        //second step: critical checks. If left empty or filled wrong, mark as
487
+        //not configured and give a warning.
488
+        return $this->doCriticalValidation();
489
+    }
490
+
491
+
492
+    /**
493
+     * Connects and Binds to LDAP
494
+     */
495
+    private function establishConnection() {
496
+        if(!$this->configuration->ldapConfigurationActive) {
497
+            return null;
498
+        }
499
+        static $phpLDAPinstalled = true;
500
+        if(!$phpLDAPinstalled) {
501
+            return false;
502
+        }
503
+        if(!$this->ignoreValidation && !$this->configured) {
504
+            \OCP\Util::writeLog('user_ldap',
505
+                                'Configuration is invalid, cannot connect',
506
+                                \OCP\Util::WARN);
507
+            return false;
508
+        }
509
+        if(!$this->ldapConnectionRes) {
510
+            if(!$this->ldap->areLDAPFunctionsAvailable()) {
511
+                $phpLDAPinstalled = false;
512
+                \OCP\Util::writeLog('user_ldap',
513
+                                    'function ldap_connect is not available. Make '.
514
+                                    'sure that the PHP ldap module is installed.',
515
+                                    \OCP\Util::ERROR);
516
+
517
+                return false;
518
+            }
519
+            if($this->configuration->turnOffCertCheck) {
520
+                if(putenv('LDAPTLS_REQCERT=never')) {
521
+                    \OCP\Util::writeLog('user_ldap',
522
+                        'Turned off SSL certificate validation successfully.',
523
+                        \OCP\Util::DEBUG);
524
+                } else {
525
+                    \OCP\Util::writeLog('user_ldap',
526
+                                        'Could not turn off SSL certificate validation.',
527
+                                        \OCP\Util::WARN);
528
+                }
529
+            }
530
+
531
+            $isOverrideMainServer = ($this->configuration->ldapOverrideMainServer
532
+                || $this->getFromCache('overrideMainServer'));
533
+            $isBackupHost = (trim($this->configuration->ldapBackupHost) !== "");
534
+            $bindStatus = false;
535
+            $error = -1;
536
+            try {
537
+                if (!$isOverrideMainServer) {
538
+                    $this->doConnect($this->configuration->ldapHost,
539
+                        $this->configuration->ldapPort);
540
+                    $bindStatus = $this->bind();
541
+                    $error = $this->ldap->isResource($this->ldapConnectionRes) ?
542
+                        $this->ldap->errno($this->ldapConnectionRes) : -1;
543
+                }
544
+                if($bindStatus === true) {
545
+                    return $bindStatus;
546
+                }
547
+            } catch (ServerNotAvailableException $e) {
548
+                if(!$isBackupHost) {
549
+                    throw $e;
550
+                }
551
+            }
552
+
553
+            //if LDAP server is not reachable, try the Backup (Replica!) Server
554
+            if($isBackupHost && ($error !== 0 || $isOverrideMainServer)) {
555
+                $this->doConnect($this->configuration->ldapBackupHost,
556
+                                    $this->configuration->ldapBackupPort);
557
+                $bindStatus = $this->bind();
558
+                $error = $this->ldap->isResource($this->ldapConnectionRes) ?
559
+                    $this->ldap->errno($this->ldapConnectionRes) : -1;
560
+                if($bindStatus && $error === 0 && !$this->getFromCache('overrideMainServer')) {
561
+                    //when bind to backup server succeeded and failed to main server,
562
+                    //skip contacting him until next cache refresh
563
+                    $this->writeToCache('overrideMainServer', true);
564
+                }
565
+            }
566
+
567
+            return $bindStatus;
568
+        }
569
+        return null;
570
+    }
571
+
572
+    /**
573
+     * @param string $host
574
+     * @param string $port
575
+     * @return bool
576
+     * @throws \OC\ServerNotAvailableException
577
+     */
578
+    private function doConnect($host, $port) {
579
+        if ($host === '') {
580
+            return false;
581
+        }
582
+
583
+        $this->ldapConnectionRes = $this->ldap->connect($host, $port);
584
+
585
+        if(!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
586
+            throw new ServerNotAvailableException('Could not set required LDAP Protocol version.');
587
+        }
588
+
589
+        if(!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
590
+            throw new ServerNotAvailableException('Could not disable LDAP referrals.');
591
+        }
592
+
593
+        if($this->configuration->ldapTLS) {
594
+            if(!$this->ldap->startTls($this->ldapConnectionRes)) {
595
+                throw new ServerNotAvailableException('Start TLS failed, when connecting to LDAP host ' . $host . '.');
596
+            }
597
+        }
598
+
599
+        return true;
600
+    }
601
+
602
+    /**
603
+     * Binds to LDAP
604
+     */
605
+    public function bind() {
606
+        if(!$this->configuration->ldapConfigurationActive) {
607
+            return false;
608
+        }
609
+        $cr = $this->getConnectionResource();
610
+        if(!$this->ldap->isResource($cr)) {
611
+            return false;
612
+        }
613
+        $ldapLogin = @$this->ldap->bind($cr,
614
+                                        $this->configuration->ldapAgentName,
615
+                                        $this->configuration->ldapAgentPassword);
616
+        if(!$ldapLogin) {
617
+            $errno = $this->ldap->errno($cr);
618
+
619
+            \OCP\Util::writeLog('user_ldap',
620
+                'Bind failed: ' . $errno . ': ' . $this->ldap->error($cr),
621
+                \OCP\Util::WARN);
622
+
623
+            // Set to failure mode, if LDAP error code is not LDAP_SUCCESS or LDAP_INVALID_CREDENTIALS
624
+            if($errno !== 0x00 && $errno !== 0x31) {
625
+                $this->ldapConnectionRes = null;
626
+            }
627
+
628
+            return false;
629
+        }
630
+        return true;
631
+    }
632 632
 
633 633
 }
Please login to merge, or discard this patch.
apps/user_ldap/lib/User/User.php 2 patches
Indentation   +642 added lines, -642 removed lines patch added patch discarded remove patch
@@ -43,652 +43,652 @@
 block discarded – undo
43 43
  * represents an LDAP user, gets and holds user-specific information from LDAP
44 44
  */
45 45
 class User {
46
-	/**
47
-	 * @var IUserTools
48
-	 */
49
-	protected $access;
50
-	/**
51
-	 * @var Connection
52
-	 */
53
-	protected $connection;
54
-	/**
55
-	 * @var IConfig
56
-	 */
57
-	protected $config;
58
-	/**
59
-	 * @var FilesystemHelper
60
-	 */
61
-	protected $fs;
62
-	/**
63
-	 * @var Image
64
-	 */
65
-	protected $image;
66
-	/**
67
-	 * @var LogWrapper
68
-	 */
69
-	protected $log;
70
-	/**
71
-	 * @var IAvatarManager
72
-	 */
73
-	protected $avatarManager;
74
-	/**
75
-	 * @var IUserManager
76
-	 */
77
-	protected $userManager;
78
-	/**
79
-	 * @var INotificationManager
80
-	 */
81
-	protected $notificationManager;
82
-	/**
83
-	 * @var string
84
-	 */
85
-	protected $dn;
86
-	/**
87
-	 * @var string
88
-	 */
89
-	protected $uid;
90
-	/**
91
-	 * @var string[]
92
-	 */
93
-	protected $refreshedFeatures = array();
94
-	/**
95
-	 * @var string
96
-	 */
97
-	protected $avatarImage;
98
-
99
-	/**
100
-	 * DB config keys for user preferences
101
-	 */
102
-	const USER_PREFKEY_FIRSTLOGIN  = 'firstLoginAccomplished';
103
-	const USER_PREFKEY_LASTREFRESH = 'lastFeatureRefresh';
104
-
105
-	/**
106
-	 * @brief constructor, make sure the subclasses call this one!
107
-	 * @param string $username the internal username
108
-	 * @param string $dn the LDAP DN
109
-	 * @param IUserTools $access an instance that implements IUserTools for
110
-	 * LDAP interaction
111
-	 * @param IConfig $config
112
-	 * @param FilesystemHelper $fs
113
-	 * @param Image $image any empty instance
114
-	 * @param LogWrapper $log
115
-	 * @param IAvatarManager $avatarManager
116
-	 * @param IUserManager $userManager
117
-	 * @param INotificationManager $notificationManager
118
-	 */
119
-	public function __construct($username, $dn, IUserTools $access,
120
-		IConfig $config, FilesystemHelper $fs, Image $image,
121
-		LogWrapper $log, IAvatarManager $avatarManager, IUserManager $userManager,
122
-		INotificationManager $notificationManager) {
46
+    /**
47
+     * @var IUserTools
48
+     */
49
+    protected $access;
50
+    /**
51
+     * @var Connection
52
+     */
53
+    protected $connection;
54
+    /**
55
+     * @var IConfig
56
+     */
57
+    protected $config;
58
+    /**
59
+     * @var FilesystemHelper
60
+     */
61
+    protected $fs;
62
+    /**
63
+     * @var Image
64
+     */
65
+    protected $image;
66
+    /**
67
+     * @var LogWrapper
68
+     */
69
+    protected $log;
70
+    /**
71
+     * @var IAvatarManager
72
+     */
73
+    protected $avatarManager;
74
+    /**
75
+     * @var IUserManager
76
+     */
77
+    protected $userManager;
78
+    /**
79
+     * @var INotificationManager
80
+     */
81
+    protected $notificationManager;
82
+    /**
83
+     * @var string
84
+     */
85
+    protected $dn;
86
+    /**
87
+     * @var string
88
+     */
89
+    protected $uid;
90
+    /**
91
+     * @var string[]
92
+     */
93
+    protected $refreshedFeatures = array();
94
+    /**
95
+     * @var string
96
+     */
97
+    protected $avatarImage;
98
+
99
+    /**
100
+     * DB config keys for user preferences
101
+     */
102
+    const USER_PREFKEY_FIRSTLOGIN  = 'firstLoginAccomplished';
103
+    const USER_PREFKEY_LASTREFRESH = 'lastFeatureRefresh';
104
+
105
+    /**
106
+     * @brief constructor, make sure the subclasses call this one!
107
+     * @param string $username the internal username
108
+     * @param string $dn the LDAP DN
109
+     * @param IUserTools $access an instance that implements IUserTools for
110
+     * LDAP interaction
111
+     * @param IConfig $config
112
+     * @param FilesystemHelper $fs
113
+     * @param Image $image any empty instance
114
+     * @param LogWrapper $log
115
+     * @param IAvatarManager $avatarManager
116
+     * @param IUserManager $userManager
117
+     * @param INotificationManager $notificationManager
118
+     */
119
+    public function __construct($username, $dn, IUserTools $access,
120
+        IConfig $config, FilesystemHelper $fs, Image $image,
121
+        LogWrapper $log, IAvatarManager $avatarManager, IUserManager $userManager,
122
+        INotificationManager $notificationManager) {
123 123
 	
124
-		if ($username === null) {
125
-			$log->log("uid for '$dn' must not be null!", Util::ERROR);
126
-			throw new \InvalidArgumentException('uid must not be null!');
127
-		} else if ($username === '') {
128
-			$log->log("uid for '$dn' must not be an empty string", Util::ERROR);
129
-			throw new \InvalidArgumentException('uid must not be an empty string!');
130
-		}
131
-
132
-		$this->access              = $access;
133
-		$this->connection          = $access->getConnection();
134
-		$this->config              = $config;
135
-		$this->fs                  = $fs;
136
-		$this->dn                  = $dn;
137
-		$this->uid                 = $username;
138
-		$this->image               = $image;
139
-		$this->log                 = $log;
140
-		$this->avatarManager       = $avatarManager;
141
-		$this->userManager         = $userManager;
142
-		$this->notificationManager = $notificationManager;
143
-
144
-		\OCP\Util::connectHook('OC_User', 'post_login', $this, 'handlePasswordExpiry');
145
-	}
146
-
147
-	/**
148
-	 * @brief updates properties like email, quota or avatar provided by LDAP
149
-	 * @return null
150
-	 */
151
-	public function update() {
152
-		if(is_null($this->dn)) {
153
-			return null;
154
-		}
155
-
156
-		$hasLoggedIn = $this->config->getUserValue($this->uid, 'user_ldap',
157
-				self::USER_PREFKEY_FIRSTLOGIN, 0);
158
-
159
-		if($this->needsRefresh()) {
160
-			$this->updateEmail();
161
-			$this->updateQuota();
162
-			if($hasLoggedIn !== 0) {
163
-				//we do not need to try it, when the user has not been logged in
164
-				//before, because the file system will not be ready.
165
-				$this->updateAvatar();
166
-				//in order to get an avatar as soon as possible, mark the user
167
-				//as refreshed only when updating the avatar did happen
168
-				$this->markRefreshTime();
169
-			}
170
-		}
171
-	}
172
-
173
-	/**
174
-	 * processes results from LDAP for attributes as returned by getAttributesToRead()
175
-	 * @param array $ldapEntry the user entry as retrieved from LDAP
176
-	 */
177
-	public function processAttributes($ldapEntry) {
178
-		$this->markRefreshTime();
179
-		//Quota
180
-		$attr = strtolower($this->connection->ldapQuotaAttribute);
181
-		if(isset($ldapEntry[$attr])) {
182
-			$this->updateQuota($ldapEntry[$attr][0]);
183
-		} else {
184
-			if ($this->connection->ldapQuotaDefault !== '') {
185
-				$this->updateQuota();
186
-			}
187
-		}
188
-		unset($attr);
189
-
190
-		//Email
191
-		$attr = strtolower($this->connection->ldapEmailAttribute);
192
-		if(isset($ldapEntry[$attr])) {
193
-			$this->updateEmail($ldapEntry[$attr][0]);
194
-		}
195
-		unset($attr);
196
-
197
-		//displayName
198
-		$displayName = $displayName2 = '';
199
-		$attr = strtolower($this->connection->ldapUserDisplayName);
200
-		if(isset($ldapEntry[$attr])) {
201
-			$displayName = strval($ldapEntry[$attr][0]);
202
-		}
203
-		$attr = strtolower($this->connection->ldapUserDisplayName2);
204
-		if(isset($ldapEntry[$attr])) {
205
-			$displayName2 = strval($ldapEntry[$attr][0]);
206
-		}
207
-		if ($displayName !== '') {
208
-			$this->composeAndStoreDisplayName($displayName);
209
-			$this->access->cacheUserDisplayName(
210
-				$this->getUsername(),
211
-				$displayName,
212
-				$displayName2
213
-			);
214
-		}
215
-		unset($attr);
216
-
217
-		// LDAP Username, needed for s2s sharing
218
-		if(isset($ldapEntry['uid'])) {
219
-			$this->storeLDAPUserName($ldapEntry['uid'][0]);
220
-		} else if(isset($ldapEntry['samaccountname'])) {
221
-			$this->storeLDAPUserName($ldapEntry['samaccountname'][0]);
222
-		}
223
-
224
-		//homePath
225
-		if(strpos($this->connection->homeFolderNamingRule, 'attr:') === 0) {
226
-			$attr = strtolower(substr($this->connection->homeFolderNamingRule, strlen('attr:')));
227
-			if(isset($ldapEntry[$attr])) {
228
-				$this->access->cacheUserHome(
229
-					$this->getUsername(), $this->getHomePath($ldapEntry[$attr][0]));
230
-			}
231
-		}
232
-
233
-		//memberOf groups
234
-		$cacheKey = 'getMemberOf'.$this->getUsername();
235
-		$groups = false;
236
-		if(isset($ldapEntry['memberof'])) {
237
-			$groups = $ldapEntry['memberof'];
238
-		}
239
-		$this->connection->writeToCache($cacheKey, $groups);
240
-
241
-		//Avatar
242
-		$attrs = array('jpegphoto', 'thumbnailphoto');
243
-		foreach ($attrs as $attr)  {
244
-			if(isset($ldapEntry[$attr])) {
245
-				$this->avatarImage = $ldapEntry[$attr][0];
246
-				// the call to the method that saves the avatar in the file
247
-				// system must be postponed after the login. It is to ensure
248
-				// external mounts are mounted properly (e.g. with login
249
-				// credentials from the session).
250
-				\OCP\Util::connectHook('OC_User', 'post_login', $this, 'updateAvatarPostLogin');
251
-				break;
252
-			}
253
-		}
254
-	}
255
-
256
-	/**
257
-	 * @brief returns the LDAP DN of the user
258
-	 * @return string
259
-	 */
260
-	public function getDN() {
261
-		return $this->dn;
262
-	}
263
-
264
-	/**
265
-	 * @brief returns the Nextcloud internal username of the user
266
-	 * @return string
267
-	 */
268
-	public function getUsername() {
269
-		return $this->uid;
270
-	}
271
-
272
-	/**
273
-	 * returns the home directory of the user if specified by LDAP settings
274
-	 * @param string $valueFromLDAP
275
-	 * @return bool|string
276
-	 * @throws \Exception
277
-	 */
278
-	public function getHomePath($valueFromLDAP = null) {
279
-		$path = strval($valueFromLDAP);
280
-		$attr = null;
281
-
282
-		if (is_null($valueFromLDAP)
283
-		   && strpos($this->access->connection->homeFolderNamingRule, 'attr:') === 0
284
-		   && $this->access->connection->homeFolderNamingRule !== 'attr:')
285
-		{
286
-			$attr = substr($this->access->connection->homeFolderNamingRule, strlen('attr:'));
287
-			$homedir = $this->access->readAttribute(
288
-				$this->access->username2dn($this->getUsername()), $attr);
289
-			if ($homedir && isset($homedir[0])) {
290
-				$path = $homedir[0];
291
-			}
292
-		}
293
-
294
-		if ($path !== '') {
295
-			//if attribute's value is an absolute path take this, otherwise append it to data dir
296
-			//check for / at the beginning or pattern c:\ resp. c:/
297
-			if(   '/' !== $path[0]
298
-			   && !(3 < strlen($path) && ctype_alpha($path[0])
299
-			       && $path[1] === ':' && ('\\' === $path[2] || '/' === $path[2]))
300
-			) {
301
-				$path = $this->config->getSystemValue('datadirectory',
302
-						\OC::$SERVERROOT.'/data' ) . '/' . $path;
303
-			}
304
-			//we need it to store it in the DB as well in case a user gets
305
-			//deleted so we can clean up afterwards
306
-			$this->config->setUserValue(
307
-				$this->getUsername(), 'user_ldap', 'homePath', $path
308
-			);
309
-			return $path;
310
-		}
311
-
312
-		if(    !is_null($attr)
313
-			&& $this->config->getAppValue('user_ldap', 'enforce_home_folder_naming_rule', true)
314
-		) {
315
-			// a naming rule attribute is defined, but it doesn't exist for that LDAP user
316
-			throw new \Exception('Home dir attribute can\'t be read from LDAP for uid: ' . $this->getUsername());
317
-		}
318
-
319
-		//false will apply default behaviour as defined and done by OC_User
320
-		$this->config->setUserValue($this->getUsername(), 'user_ldap', 'homePath', '');
321
-		return false;
322
-	}
323
-
324
-	public function getMemberOfGroups() {
325
-		$cacheKey = 'getMemberOf'.$this->getUsername();
326
-		$memberOfGroups = $this->connection->getFromCache($cacheKey);
327
-		if(!is_null($memberOfGroups)) {
328
-			return $memberOfGroups;
329
-		}
330
-		$groupDNs = $this->access->readAttribute($this->getDN(), 'memberOf');
331
-		$this->connection->writeToCache($cacheKey, $groupDNs);
332
-		return $groupDNs;
333
-	}
334
-
335
-	/**
336
-	 * @brief reads the image from LDAP that shall be used as Avatar
337
-	 * @return string data (provided by LDAP) | false
338
-	 */
339
-	public function getAvatarImage() {
340
-		if(!is_null($this->avatarImage)) {
341
-			return $this->avatarImage;
342
-		}
343
-
344
-		$this->avatarImage = false;
345
-		$attributes = array('jpegPhoto', 'thumbnailPhoto');
346
-		foreach($attributes as $attribute) {
347
-			$result = $this->access->readAttribute($this->dn, $attribute);
348
-			if($result !== false && is_array($result) && isset($result[0])) {
349
-				$this->avatarImage = $result[0];
350
-				break;
351
-			}
352
-		}
353
-
354
-		return $this->avatarImage;
355
-	}
356
-
357
-	/**
358
-	 * @brief marks the user as having logged in at least once
359
-	 * @return null
360
-	 */
361
-	public function markLogin() {
362
-		$this->config->setUserValue(
363
-			$this->uid, 'user_ldap', self::USER_PREFKEY_FIRSTLOGIN, 1);
364
-	}
365
-
366
-	/**
367
-	 * @brief marks the time when user features like email have been updated
368
-	 * @return null
369
-	 */
370
-	public function markRefreshTime() {
371
-		$this->config->setUserValue(
372
-			$this->uid, 'user_ldap', self::USER_PREFKEY_LASTREFRESH, time());
373
-	}
374
-
375
-	/**
376
-	 * @brief checks whether user features needs to be updated again by
377
-	 * comparing the difference of time of the last refresh to now with the
378
-	 * desired interval
379
-	 * @return bool
380
-	 */
381
-	private function needsRefresh() {
382
-		$lastChecked = $this->config->getUserValue($this->uid, 'user_ldap',
383
-			self::USER_PREFKEY_LASTREFRESH, 0);
384
-
385
-		//TODO make interval configurable
386
-		if((time() - intval($lastChecked)) < 86400 ) {
387
-			return false;
388
-		}
389
-		return  true;
390
-	}
391
-
392
-	/**
393
-	 * Stores a key-value pair in relation to this user
394
-	 *
395
-	 * @param string $key
396
-	 * @param string $value
397
-	 */
398
-	private function store($key, $value) {
399
-		$this->config->setUserValue($this->uid, 'user_ldap', $key, $value);
400
-	}
401
-
402
-	/**
403
-	 * Composes the display name and stores it in the database. The final
404
-	 * display name is returned.
405
-	 *
406
-	 * @param string $displayName
407
-	 * @param string $displayName2
408
-	 * @returns string the effective display name
409
-	 */
410
-	public function composeAndStoreDisplayName($displayName, $displayName2 = '') {
411
-		$displayName2 = strval($displayName2);
412
-		if($displayName2 !== '') {
413
-			$displayName .= ' (' . $displayName2 . ')';
414
-		}
415
-		$this->store('displayName', $displayName);
416
-		return $displayName;
417
-	}
418
-
419
-	/**
420
-	 * Stores the LDAP Username in the Database
421
-	 * @param string $userName
422
-	 */
423
-	public function storeLDAPUserName($userName) {
424
-		$this->store('uid', $userName);
425
-	}
426
-
427
-	/**
428
-	 * @brief checks whether an update method specified by feature was run
429
-	 * already. If not, it will marked like this, because it is expected that
430
-	 * the method will be run, when false is returned.
431
-	 * @param string $feature email | quota | avatar (can be extended)
432
-	 * @return bool
433
-	 */
434
-	private function wasRefreshed($feature) {
435
-		if(isset($this->refreshedFeatures[$feature])) {
436
-			return true;
437
-		}
438
-		$this->refreshedFeatures[$feature] = 1;
439
-		return false;
440
-	}
441
-
442
-	/**
443
-	 * fetches the email from LDAP and stores it as Nextcloud user value
444
-	 * @param string $valueFromLDAP if known, to save an LDAP read request
445
-	 * @return null
446
-	 */
447
-	public function updateEmail($valueFromLDAP = null) {
448
-		if($this->wasRefreshed('email')) {
449
-			return;
450
-		}
451
-		$email = strval($valueFromLDAP);
452
-		if(is_null($valueFromLDAP)) {
453
-			$emailAttribute = $this->connection->ldapEmailAttribute;
454
-			if ($emailAttribute !== '') {
455
-				$aEmail = $this->access->readAttribute($this->dn, $emailAttribute);
456
-				if(is_array($aEmail) && (count($aEmail) > 0)) {
457
-					$email = strval($aEmail[0]);
458
-				}
459
-			}
460
-		}
461
-		if ($email !== '') {
462
-			$user = $this->userManager->get($this->uid);
463
-			if (!is_null($user)) {
464
-				$currentEmail = strval($user->getEMailAddress());
465
-				if ($currentEmail !== $email) {
466
-					$user->setEMailAddress($email);
467
-				}
468
-			}
469
-		}
470
-	}
471
-
472
-	/**
473
-	 * Overall process goes as follow:
474
-	 * 1. fetch the quota from LDAP and check if it's parseable with the "verifyQuotaValue" function
475
-	 * 2. if the value can't be fetched, is empty or not parseable, use the default LDAP quota
476
-	 * 3. if the default LDAP quota can't be parsed, use the Nextcloud's default quota (use 'default')
477
-	 * 4. check if the target user exists and set the quota for the user.
478
-	 *
479
-	 * In order to improve performance and prevent an unwanted extra LDAP call, the $valueFromLDAP
480
-	 * parameter can be passed with the value of the attribute. This value will be considered as the
481
-	 * quota for the user coming from the LDAP server (step 1 of the process) It can be useful to
482
-	 * fetch all the user's attributes in one call and use the fetched values in this function.
483
-	 * The expected value for that parameter is a string describing the quota for the user. Valid
484
-	 * values are 'none' (unlimited), 'default' (the Nextcloud's default quota), '1234' (quota in
485
-	 * bytes), '1234 MB' (quota in MB - check the \OC_Helper::computerFileSize method for more info)
486
-	 *
487
-	 * fetches the quota from LDAP and stores it as Nextcloud user value
488
-	 * @param string $valueFromLDAP the quota attribute's value can be passed,
489
-	 * to save the readAttribute request
490
-	 * @return null
491
-	 */
492
-	public function updateQuota($valueFromLDAP = null) {
493
-		if($this->wasRefreshed('quota')) {
494
-			return;
495
-		}
496
-
497
-		$quota = false;
498
-		if(is_null($valueFromLDAP)) {
499
-			$quotaAttribute = $this->connection->ldapQuotaAttribute;
500
-			if ($quotaAttribute !== '') {
501
-				$aQuota = $this->access->readAttribute($this->dn, $quotaAttribute);
502
-				if($aQuota && (count($aQuota) > 0)) {
503
-					if ($this->verifyQuotaValue($aQuota[0])) {
504
-						$quota = $aQuota[0];
505
-					} else {
506
-						$this->log->log('not suitable LDAP quota found for user ' . $this->uid . ': [' . $aQuota[0] . ']', \OCP\Util::WARN);
507
-					}
508
-				}
509
-			}
510
-		} else {
511
-			if ($this->verifyQuotaValue($valueFromLDAP)) {
512
-				$quota = $valueFromLDAP;
513
-			} else {
514
-				$this->log->log('not suitable LDAP quota found for user ' . $this->uid . ': [' . $valueFromLDAP . ']', \OCP\Util::WARN);
515
-			}
516
-		}
517
-
518
-		if ($quota === false) {
519
-			// quota not found using the LDAP attribute (or not parseable). Try the default quota
520
-			$defaultQuota = $this->connection->ldapQuotaDefault;
521
-			if ($this->verifyQuotaValue($defaultQuota)) {
522
-				$quota = $defaultQuota;
523
-			}
524
-		}
525
-
526
-		$targetUser = $this->userManager->get($this->uid);
527
-		if ($targetUser) {
528
-			if($quota !== false) {
529
-				$targetUser->setQuota($quota);
530
-			} else {
531
-				$this->log->log('not suitable default quota found for user ' . $this->uid . ': [' . $defaultQuota . ']', \OCP\Util::WARN);
532
-			}
533
-		} else {
534
-			$this->log->log('trying to set a quota for user ' . $this->uid . ' but the user is missing', \OCP\Util::ERROR);
535
-		}
536
-	}
537
-
538
-	private function verifyQuotaValue($quotaValue) {
539
-		return $quotaValue === 'none' || $quotaValue === 'default' || \OC_Helper::computerFileSize($quotaValue) !== false;
540
-	}
541
-
542
-	/**
543
-	 * called by a post_login hook to save the avatar picture
544
-	 *
545
-	 * @param array $params
546
-	 */
547
-	public function updateAvatarPostLogin($params) {
548
-		if(isset($params['uid']) && $params['uid'] === $this->getUsername()) {
549
-			$this->updateAvatar();
550
-		}
551
-	}
552
-
553
-	/**
554
-	 * @brief attempts to get an image from LDAP and sets it as Nextcloud avatar
555
-	 * @return null
556
-	 */
557
-	public function updateAvatar() {
558
-		if($this->wasRefreshed('avatar')) {
559
-			return;
560
-		}
561
-		$avatarImage = $this->getAvatarImage();
562
-		if($avatarImage === false) {
563
-			//not set, nothing left to do;
564
-			return;
565
-		}
566
-		$this->image->loadFromBase64(base64_encode($avatarImage));
567
-		$this->setOwnCloudAvatar();
568
-	}
569
-
570
-	/**
571
-	 * @brief sets an image as Nextcloud avatar
572
-	 * @return null
573
-	 */
574
-	private function setOwnCloudAvatar() {
575
-		if(!$this->image->valid()) {
576
-			$this->log->log('jpegPhoto data invalid for '.$this->dn, \OCP\Util::ERROR);
577
-			return;
578
-		}
579
-		//make sure it is a square and not bigger than 128x128
580
-		$size = min(array($this->image->width(), $this->image->height(), 128));
581
-		if(!$this->image->centerCrop($size)) {
582
-			$this->log->log('croping image for avatar failed for '.$this->dn, \OCP\Util::ERROR);
583
-			return;
584
-		}
585
-
586
-		if(!$this->fs->isLoaded()) {
587
-			$this->fs->setup($this->uid);
588
-		}
589
-
590
-		try {
591
-			$avatar = $this->avatarManager->getAvatar($this->uid);
592
-			$avatar->set($this->image);
593
-		} catch (\Exception $e) {
594
-			\OC::$server->getLogger()->notice(
595
-				'Could not set avatar for ' . $this->dn	. ', because: ' . $e->getMessage(),
596
-				['app' => 'user_ldap']);
597
-		}
598
-	}
599
-
600
-	/**
601
-	 * called by a post_login hook to handle password expiry
602
-	 *
603
-	 * @param array $params
604
-	 */
605
-	public function handlePasswordExpiry($params) {
606
-		$ppolicyDN = $this->connection->ldapDefaultPPolicyDN;
607
-		if (empty($ppolicyDN) || (intval($this->connection->turnOnPasswordChange) !== 1)) {
608
-			return;//password expiry handling disabled
609
-		}
610
-		$uid = $params['uid'];
611
-		if(isset($uid) && $uid === $this->getUsername()) {
612
-			//retrieve relevant user attributes
613
-			$result = $this->access->search('objectclass=*', $this->dn, ['pwdpolicysubentry', 'pwdgraceusetime', 'pwdreset', 'pwdchangedtime']);
124
+        if ($username === null) {
125
+            $log->log("uid for '$dn' must not be null!", Util::ERROR);
126
+            throw new \InvalidArgumentException('uid must not be null!');
127
+        } else if ($username === '') {
128
+            $log->log("uid for '$dn' must not be an empty string", Util::ERROR);
129
+            throw new \InvalidArgumentException('uid must not be an empty string!');
130
+        }
131
+
132
+        $this->access              = $access;
133
+        $this->connection          = $access->getConnection();
134
+        $this->config              = $config;
135
+        $this->fs                  = $fs;
136
+        $this->dn                  = $dn;
137
+        $this->uid                 = $username;
138
+        $this->image               = $image;
139
+        $this->log                 = $log;
140
+        $this->avatarManager       = $avatarManager;
141
+        $this->userManager         = $userManager;
142
+        $this->notificationManager = $notificationManager;
143
+
144
+        \OCP\Util::connectHook('OC_User', 'post_login', $this, 'handlePasswordExpiry');
145
+    }
146
+
147
+    /**
148
+     * @brief updates properties like email, quota or avatar provided by LDAP
149
+     * @return null
150
+     */
151
+    public function update() {
152
+        if(is_null($this->dn)) {
153
+            return null;
154
+        }
155
+
156
+        $hasLoggedIn = $this->config->getUserValue($this->uid, 'user_ldap',
157
+                self::USER_PREFKEY_FIRSTLOGIN, 0);
158
+
159
+        if($this->needsRefresh()) {
160
+            $this->updateEmail();
161
+            $this->updateQuota();
162
+            if($hasLoggedIn !== 0) {
163
+                //we do not need to try it, when the user has not been logged in
164
+                //before, because the file system will not be ready.
165
+                $this->updateAvatar();
166
+                //in order to get an avatar as soon as possible, mark the user
167
+                //as refreshed only when updating the avatar did happen
168
+                $this->markRefreshTime();
169
+            }
170
+        }
171
+    }
172
+
173
+    /**
174
+     * processes results from LDAP for attributes as returned by getAttributesToRead()
175
+     * @param array $ldapEntry the user entry as retrieved from LDAP
176
+     */
177
+    public function processAttributes($ldapEntry) {
178
+        $this->markRefreshTime();
179
+        //Quota
180
+        $attr = strtolower($this->connection->ldapQuotaAttribute);
181
+        if(isset($ldapEntry[$attr])) {
182
+            $this->updateQuota($ldapEntry[$attr][0]);
183
+        } else {
184
+            if ($this->connection->ldapQuotaDefault !== '') {
185
+                $this->updateQuota();
186
+            }
187
+        }
188
+        unset($attr);
189
+
190
+        //Email
191
+        $attr = strtolower($this->connection->ldapEmailAttribute);
192
+        if(isset($ldapEntry[$attr])) {
193
+            $this->updateEmail($ldapEntry[$attr][0]);
194
+        }
195
+        unset($attr);
196
+
197
+        //displayName
198
+        $displayName = $displayName2 = '';
199
+        $attr = strtolower($this->connection->ldapUserDisplayName);
200
+        if(isset($ldapEntry[$attr])) {
201
+            $displayName = strval($ldapEntry[$attr][0]);
202
+        }
203
+        $attr = strtolower($this->connection->ldapUserDisplayName2);
204
+        if(isset($ldapEntry[$attr])) {
205
+            $displayName2 = strval($ldapEntry[$attr][0]);
206
+        }
207
+        if ($displayName !== '') {
208
+            $this->composeAndStoreDisplayName($displayName);
209
+            $this->access->cacheUserDisplayName(
210
+                $this->getUsername(),
211
+                $displayName,
212
+                $displayName2
213
+            );
214
+        }
215
+        unset($attr);
216
+
217
+        // LDAP Username, needed for s2s sharing
218
+        if(isset($ldapEntry['uid'])) {
219
+            $this->storeLDAPUserName($ldapEntry['uid'][0]);
220
+        } else if(isset($ldapEntry['samaccountname'])) {
221
+            $this->storeLDAPUserName($ldapEntry['samaccountname'][0]);
222
+        }
223
+
224
+        //homePath
225
+        if(strpos($this->connection->homeFolderNamingRule, 'attr:') === 0) {
226
+            $attr = strtolower(substr($this->connection->homeFolderNamingRule, strlen('attr:')));
227
+            if(isset($ldapEntry[$attr])) {
228
+                $this->access->cacheUserHome(
229
+                    $this->getUsername(), $this->getHomePath($ldapEntry[$attr][0]));
230
+            }
231
+        }
232
+
233
+        //memberOf groups
234
+        $cacheKey = 'getMemberOf'.$this->getUsername();
235
+        $groups = false;
236
+        if(isset($ldapEntry['memberof'])) {
237
+            $groups = $ldapEntry['memberof'];
238
+        }
239
+        $this->connection->writeToCache($cacheKey, $groups);
240
+
241
+        //Avatar
242
+        $attrs = array('jpegphoto', 'thumbnailphoto');
243
+        foreach ($attrs as $attr)  {
244
+            if(isset($ldapEntry[$attr])) {
245
+                $this->avatarImage = $ldapEntry[$attr][0];
246
+                // the call to the method that saves the avatar in the file
247
+                // system must be postponed after the login. It is to ensure
248
+                // external mounts are mounted properly (e.g. with login
249
+                // credentials from the session).
250
+                \OCP\Util::connectHook('OC_User', 'post_login', $this, 'updateAvatarPostLogin');
251
+                break;
252
+            }
253
+        }
254
+    }
255
+
256
+    /**
257
+     * @brief returns the LDAP DN of the user
258
+     * @return string
259
+     */
260
+    public function getDN() {
261
+        return $this->dn;
262
+    }
263
+
264
+    /**
265
+     * @brief returns the Nextcloud internal username of the user
266
+     * @return string
267
+     */
268
+    public function getUsername() {
269
+        return $this->uid;
270
+    }
271
+
272
+    /**
273
+     * returns the home directory of the user if specified by LDAP settings
274
+     * @param string $valueFromLDAP
275
+     * @return bool|string
276
+     * @throws \Exception
277
+     */
278
+    public function getHomePath($valueFromLDAP = null) {
279
+        $path = strval($valueFromLDAP);
280
+        $attr = null;
281
+
282
+        if (is_null($valueFromLDAP)
283
+           && strpos($this->access->connection->homeFolderNamingRule, 'attr:') === 0
284
+           && $this->access->connection->homeFolderNamingRule !== 'attr:')
285
+        {
286
+            $attr = substr($this->access->connection->homeFolderNamingRule, strlen('attr:'));
287
+            $homedir = $this->access->readAttribute(
288
+                $this->access->username2dn($this->getUsername()), $attr);
289
+            if ($homedir && isset($homedir[0])) {
290
+                $path = $homedir[0];
291
+            }
292
+        }
293
+
294
+        if ($path !== '') {
295
+            //if attribute's value is an absolute path take this, otherwise append it to data dir
296
+            //check for / at the beginning or pattern c:\ resp. c:/
297
+            if(   '/' !== $path[0]
298
+               && !(3 < strlen($path) && ctype_alpha($path[0])
299
+                   && $path[1] === ':' && ('\\' === $path[2] || '/' === $path[2]))
300
+            ) {
301
+                $path = $this->config->getSystemValue('datadirectory',
302
+                        \OC::$SERVERROOT.'/data' ) . '/' . $path;
303
+            }
304
+            //we need it to store it in the DB as well in case a user gets
305
+            //deleted so we can clean up afterwards
306
+            $this->config->setUserValue(
307
+                $this->getUsername(), 'user_ldap', 'homePath', $path
308
+            );
309
+            return $path;
310
+        }
311
+
312
+        if(    !is_null($attr)
313
+            && $this->config->getAppValue('user_ldap', 'enforce_home_folder_naming_rule', true)
314
+        ) {
315
+            // a naming rule attribute is defined, but it doesn't exist for that LDAP user
316
+            throw new \Exception('Home dir attribute can\'t be read from LDAP for uid: ' . $this->getUsername());
317
+        }
318
+
319
+        //false will apply default behaviour as defined and done by OC_User
320
+        $this->config->setUserValue($this->getUsername(), 'user_ldap', 'homePath', '');
321
+        return false;
322
+    }
323
+
324
+    public function getMemberOfGroups() {
325
+        $cacheKey = 'getMemberOf'.$this->getUsername();
326
+        $memberOfGroups = $this->connection->getFromCache($cacheKey);
327
+        if(!is_null($memberOfGroups)) {
328
+            return $memberOfGroups;
329
+        }
330
+        $groupDNs = $this->access->readAttribute($this->getDN(), 'memberOf');
331
+        $this->connection->writeToCache($cacheKey, $groupDNs);
332
+        return $groupDNs;
333
+    }
334
+
335
+    /**
336
+     * @brief reads the image from LDAP that shall be used as Avatar
337
+     * @return string data (provided by LDAP) | false
338
+     */
339
+    public function getAvatarImage() {
340
+        if(!is_null($this->avatarImage)) {
341
+            return $this->avatarImage;
342
+        }
343
+
344
+        $this->avatarImage = false;
345
+        $attributes = array('jpegPhoto', 'thumbnailPhoto');
346
+        foreach($attributes as $attribute) {
347
+            $result = $this->access->readAttribute($this->dn, $attribute);
348
+            if($result !== false && is_array($result) && isset($result[0])) {
349
+                $this->avatarImage = $result[0];
350
+                break;
351
+            }
352
+        }
353
+
354
+        return $this->avatarImage;
355
+    }
356
+
357
+    /**
358
+     * @brief marks the user as having logged in at least once
359
+     * @return null
360
+     */
361
+    public function markLogin() {
362
+        $this->config->setUserValue(
363
+            $this->uid, 'user_ldap', self::USER_PREFKEY_FIRSTLOGIN, 1);
364
+    }
365
+
366
+    /**
367
+     * @brief marks the time when user features like email have been updated
368
+     * @return null
369
+     */
370
+    public function markRefreshTime() {
371
+        $this->config->setUserValue(
372
+            $this->uid, 'user_ldap', self::USER_PREFKEY_LASTREFRESH, time());
373
+    }
374
+
375
+    /**
376
+     * @brief checks whether user features needs to be updated again by
377
+     * comparing the difference of time of the last refresh to now with the
378
+     * desired interval
379
+     * @return bool
380
+     */
381
+    private function needsRefresh() {
382
+        $lastChecked = $this->config->getUserValue($this->uid, 'user_ldap',
383
+            self::USER_PREFKEY_LASTREFRESH, 0);
384
+
385
+        //TODO make interval configurable
386
+        if((time() - intval($lastChecked)) < 86400 ) {
387
+            return false;
388
+        }
389
+        return  true;
390
+    }
391
+
392
+    /**
393
+     * Stores a key-value pair in relation to this user
394
+     *
395
+     * @param string $key
396
+     * @param string $value
397
+     */
398
+    private function store($key, $value) {
399
+        $this->config->setUserValue($this->uid, 'user_ldap', $key, $value);
400
+    }
401
+
402
+    /**
403
+     * Composes the display name and stores it in the database. The final
404
+     * display name is returned.
405
+     *
406
+     * @param string $displayName
407
+     * @param string $displayName2
408
+     * @returns string the effective display name
409
+     */
410
+    public function composeAndStoreDisplayName($displayName, $displayName2 = '') {
411
+        $displayName2 = strval($displayName2);
412
+        if($displayName2 !== '') {
413
+            $displayName .= ' (' . $displayName2 . ')';
414
+        }
415
+        $this->store('displayName', $displayName);
416
+        return $displayName;
417
+    }
418
+
419
+    /**
420
+     * Stores the LDAP Username in the Database
421
+     * @param string $userName
422
+     */
423
+    public function storeLDAPUserName($userName) {
424
+        $this->store('uid', $userName);
425
+    }
426
+
427
+    /**
428
+     * @brief checks whether an update method specified by feature was run
429
+     * already. If not, it will marked like this, because it is expected that
430
+     * the method will be run, when false is returned.
431
+     * @param string $feature email | quota | avatar (can be extended)
432
+     * @return bool
433
+     */
434
+    private function wasRefreshed($feature) {
435
+        if(isset($this->refreshedFeatures[$feature])) {
436
+            return true;
437
+        }
438
+        $this->refreshedFeatures[$feature] = 1;
439
+        return false;
440
+    }
441
+
442
+    /**
443
+     * fetches the email from LDAP and stores it as Nextcloud user value
444
+     * @param string $valueFromLDAP if known, to save an LDAP read request
445
+     * @return null
446
+     */
447
+    public function updateEmail($valueFromLDAP = null) {
448
+        if($this->wasRefreshed('email')) {
449
+            return;
450
+        }
451
+        $email = strval($valueFromLDAP);
452
+        if(is_null($valueFromLDAP)) {
453
+            $emailAttribute = $this->connection->ldapEmailAttribute;
454
+            if ($emailAttribute !== '') {
455
+                $aEmail = $this->access->readAttribute($this->dn, $emailAttribute);
456
+                if(is_array($aEmail) && (count($aEmail) > 0)) {
457
+                    $email = strval($aEmail[0]);
458
+                }
459
+            }
460
+        }
461
+        if ($email !== '') {
462
+            $user = $this->userManager->get($this->uid);
463
+            if (!is_null($user)) {
464
+                $currentEmail = strval($user->getEMailAddress());
465
+                if ($currentEmail !== $email) {
466
+                    $user->setEMailAddress($email);
467
+                }
468
+            }
469
+        }
470
+    }
471
+
472
+    /**
473
+     * Overall process goes as follow:
474
+     * 1. fetch the quota from LDAP and check if it's parseable with the "verifyQuotaValue" function
475
+     * 2. if the value can't be fetched, is empty or not parseable, use the default LDAP quota
476
+     * 3. if the default LDAP quota can't be parsed, use the Nextcloud's default quota (use 'default')
477
+     * 4. check if the target user exists and set the quota for the user.
478
+     *
479
+     * In order to improve performance and prevent an unwanted extra LDAP call, the $valueFromLDAP
480
+     * parameter can be passed with the value of the attribute. This value will be considered as the
481
+     * quota for the user coming from the LDAP server (step 1 of the process) It can be useful to
482
+     * fetch all the user's attributes in one call and use the fetched values in this function.
483
+     * The expected value for that parameter is a string describing the quota for the user. Valid
484
+     * values are 'none' (unlimited), 'default' (the Nextcloud's default quota), '1234' (quota in
485
+     * bytes), '1234 MB' (quota in MB - check the \OC_Helper::computerFileSize method for more info)
486
+     *
487
+     * fetches the quota from LDAP and stores it as Nextcloud user value
488
+     * @param string $valueFromLDAP the quota attribute's value can be passed,
489
+     * to save the readAttribute request
490
+     * @return null
491
+     */
492
+    public function updateQuota($valueFromLDAP = null) {
493
+        if($this->wasRefreshed('quota')) {
494
+            return;
495
+        }
496
+
497
+        $quota = false;
498
+        if(is_null($valueFromLDAP)) {
499
+            $quotaAttribute = $this->connection->ldapQuotaAttribute;
500
+            if ($quotaAttribute !== '') {
501
+                $aQuota = $this->access->readAttribute($this->dn, $quotaAttribute);
502
+                if($aQuota && (count($aQuota) > 0)) {
503
+                    if ($this->verifyQuotaValue($aQuota[0])) {
504
+                        $quota = $aQuota[0];
505
+                    } else {
506
+                        $this->log->log('not suitable LDAP quota found for user ' . $this->uid . ': [' . $aQuota[0] . ']', \OCP\Util::WARN);
507
+                    }
508
+                }
509
+            }
510
+        } else {
511
+            if ($this->verifyQuotaValue($valueFromLDAP)) {
512
+                $quota = $valueFromLDAP;
513
+            } else {
514
+                $this->log->log('not suitable LDAP quota found for user ' . $this->uid . ': [' . $valueFromLDAP . ']', \OCP\Util::WARN);
515
+            }
516
+        }
517
+
518
+        if ($quota === false) {
519
+            // quota not found using the LDAP attribute (or not parseable). Try the default quota
520
+            $defaultQuota = $this->connection->ldapQuotaDefault;
521
+            if ($this->verifyQuotaValue($defaultQuota)) {
522
+                $quota = $defaultQuota;
523
+            }
524
+        }
525
+
526
+        $targetUser = $this->userManager->get($this->uid);
527
+        if ($targetUser) {
528
+            if($quota !== false) {
529
+                $targetUser->setQuota($quota);
530
+            } else {
531
+                $this->log->log('not suitable default quota found for user ' . $this->uid . ': [' . $defaultQuota . ']', \OCP\Util::WARN);
532
+            }
533
+        } else {
534
+            $this->log->log('trying to set a quota for user ' . $this->uid . ' but the user is missing', \OCP\Util::ERROR);
535
+        }
536
+    }
537
+
538
+    private function verifyQuotaValue($quotaValue) {
539
+        return $quotaValue === 'none' || $quotaValue === 'default' || \OC_Helper::computerFileSize($quotaValue) !== false;
540
+    }
541
+
542
+    /**
543
+     * called by a post_login hook to save the avatar picture
544
+     *
545
+     * @param array $params
546
+     */
547
+    public function updateAvatarPostLogin($params) {
548
+        if(isset($params['uid']) && $params['uid'] === $this->getUsername()) {
549
+            $this->updateAvatar();
550
+        }
551
+    }
552
+
553
+    /**
554
+     * @brief attempts to get an image from LDAP and sets it as Nextcloud avatar
555
+     * @return null
556
+     */
557
+    public function updateAvatar() {
558
+        if($this->wasRefreshed('avatar')) {
559
+            return;
560
+        }
561
+        $avatarImage = $this->getAvatarImage();
562
+        if($avatarImage === false) {
563
+            //not set, nothing left to do;
564
+            return;
565
+        }
566
+        $this->image->loadFromBase64(base64_encode($avatarImage));
567
+        $this->setOwnCloudAvatar();
568
+    }
569
+
570
+    /**
571
+     * @brief sets an image as Nextcloud avatar
572
+     * @return null
573
+     */
574
+    private function setOwnCloudAvatar() {
575
+        if(!$this->image->valid()) {
576
+            $this->log->log('jpegPhoto data invalid for '.$this->dn, \OCP\Util::ERROR);
577
+            return;
578
+        }
579
+        //make sure it is a square and not bigger than 128x128
580
+        $size = min(array($this->image->width(), $this->image->height(), 128));
581
+        if(!$this->image->centerCrop($size)) {
582
+            $this->log->log('croping image for avatar failed for '.$this->dn, \OCP\Util::ERROR);
583
+            return;
584
+        }
585
+
586
+        if(!$this->fs->isLoaded()) {
587
+            $this->fs->setup($this->uid);
588
+        }
589
+
590
+        try {
591
+            $avatar = $this->avatarManager->getAvatar($this->uid);
592
+            $avatar->set($this->image);
593
+        } catch (\Exception $e) {
594
+            \OC::$server->getLogger()->notice(
595
+                'Could not set avatar for ' . $this->dn	. ', because: ' . $e->getMessage(),
596
+                ['app' => 'user_ldap']);
597
+        }
598
+    }
599
+
600
+    /**
601
+     * called by a post_login hook to handle password expiry
602
+     *
603
+     * @param array $params
604
+     */
605
+    public function handlePasswordExpiry($params) {
606
+        $ppolicyDN = $this->connection->ldapDefaultPPolicyDN;
607
+        if (empty($ppolicyDN) || (intval($this->connection->turnOnPasswordChange) !== 1)) {
608
+            return;//password expiry handling disabled
609
+        }
610
+        $uid = $params['uid'];
611
+        if(isset($uid) && $uid === $this->getUsername()) {
612
+            //retrieve relevant user attributes
613
+            $result = $this->access->search('objectclass=*', $this->dn, ['pwdpolicysubentry', 'pwdgraceusetime', 'pwdreset', 'pwdchangedtime']);
614 614
 			
615
-			if(array_key_exists('pwdpolicysubentry', $result[0])) {
616
-				$pwdPolicySubentry = $result[0]['pwdpolicysubentry'];
617
-				if($pwdPolicySubentry && (count($pwdPolicySubentry) > 0)){
618
-					$ppolicyDN = $pwdPolicySubentry[0];//custom ppolicy DN
619
-				}
620
-			}
615
+            if(array_key_exists('pwdpolicysubentry', $result[0])) {
616
+                $pwdPolicySubentry = $result[0]['pwdpolicysubentry'];
617
+                if($pwdPolicySubentry && (count($pwdPolicySubentry) > 0)){
618
+                    $ppolicyDN = $pwdPolicySubentry[0];//custom ppolicy DN
619
+                }
620
+            }
621 621
 			
622
-			$pwdGraceUseTime = array_key_exists('pwdgraceusetime', $result[0]) ? $result[0]['pwdgraceusetime'] : null;
623
-			$pwdReset = array_key_exists('pwdreset', $result[0]) ? $result[0]['pwdreset'] : null;
624
-			$pwdChangedTime = array_key_exists('pwdchangedtime', $result[0]) ? $result[0]['pwdchangedtime'] : null;
622
+            $pwdGraceUseTime = array_key_exists('pwdgraceusetime', $result[0]) ? $result[0]['pwdgraceusetime'] : null;
623
+            $pwdReset = array_key_exists('pwdreset', $result[0]) ? $result[0]['pwdreset'] : null;
624
+            $pwdChangedTime = array_key_exists('pwdchangedtime', $result[0]) ? $result[0]['pwdchangedtime'] : null;
625 625
 			
626
-			//retrieve relevant password policy attributes
627
-			$cacheKey = 'ppolicyAttributes' . $ppolicyDN;
628
-			$result = $this->connection->getFromCache($cacheKey);
629
-			if(is_null($result)) {
630
-				$result = $this->access->search('objectclass=*', $ppolicyDN, ['pwdgraceauthnlimit', 'pwdmaxage', 'pwdexpirewarning']);
631
-				$this->connection->writeToCache($cacheKey, $result);
632
-			}
626
+            //retrieve relevant password policy attributes
627
+            $cacheKey = 'ppolicyAttributes' . $ppolicyDN;
628
+            $result = $this->connection->getFromCache($cacheKey);
629
+            if(is_null($result)) {
630
+                $result = $this->access->search('objectclass=*', $ppolicyDN, ['pwdgraceauthnlimit', 'pwdmaxage', 'pwdexpirewarning']);
631
+                $this->connection->writeToCache($cacheKey, $result);
632
+            }
633 633
 			
634
-			$pwdGraceAuthNLimit = array_key_exists('pwdgraceauthnlimit', $result[0]) ? $result[0]['pwdgraceauthnlimit'] : null;
635
-			$pwdMaxAge = array_key_exists('pwdmaxage', $result[0]) ? $result[0]['pwdmaxage'] : null;
636
-			$pwdExpireWarning = array_key_exists('pwdexpirewarning', $result[0]) ? $result[0]['pwdexpirewarning'] : null;
634
+            $pwdGraceAuthNLimit = array_key_exists('pwdgraceauthnlimit', $result[0]) ? $result[0]['pwdgraceauthnlimit'] : null;
635
+            $pwdMaxAge = array_key_exists('pwdmaxage', $result[0]) ? $result[0]['pwdmaxage'] : null;
636
+            $pwdExpireWarning = array_key_exists('pwdexpirewarning', $result[0]) ? $result[0]['pwdexpirewarning'] : null;
637 637
 			
638
-			//handle grace login
639
-			$pwdGraceUseTimeCount = count($pwdGraceUseTime);
640
-			if($pwdGraceUseTime && $pwdGraceUseTimeCount > 0) { //was this a grace login?
641
-				if($pwdGraceAuthNLimit 
642
-					&& (count($pwdGraceAuthNLimit) > 0)
643
-					&&($pwdGraceUseTimeCount < intval($pwdGraceAuthNLimit[0]))) { //at least one more grace login available?
644
-					$this->config->setUserValue($uid, 'user_ldap', 'needsPasswordReset', 'true');
645
-					header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute(
646
-					'user_ldap.renewPassword.showRenewPasswordForm', array('user' => $uid)));
647
-				} else { //no more grace login available
648
-					header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute(
649
-					'user_ldap.renewPassword.showLoginFormInvalidPassword', array('user' => $uid)));
650
-				}
651
-				exit();
652
-			}
653
-			//handle pwdReset attribute
654
-			if($pwdReset && (count($pwdReset) > 0) && $pwdReset[0] === 'TRUE') { //user must change his password
655
-				$this->config->setUserValue($uid, 'user_ldap', 'needsPasswordReset', 'true');
656
-				header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute(
657
-				'user_ldap.renewPassword.showRenewPasswordForm', array('user' => $uid)));
658
-				exit();
659
-			}
660
-			//handle password expiry warning
661
-			if($pwdChangedTime && (count($pwdChangedTime) > 0)) {
662
-				if($pwdMaxAge && (count($pwdMaxAge) > 0)
663
-					&& $pwdExpireWarning && (count($pwdExpireWarning) > 0)) {
664
-					$pwdMaxAgeInt = intval($pwdMaxAge[0]);
665
-					$pwdExpireWarningInt = intval($pwdExpireWarning[0]);
666
-					if($pwdMaxAgeInt > 0 && $pwdExpireWarningInt > 0){
667
-						$pwdChangedTimeDt = \DateTime::createFromFormat('YmdHisZ', $pwdChangedTime[0]);
668
-						$pwdChangedTimeDt->add(new \DateInterval('PT'.$pwdMaxAgeInt.'S'));
669
-						$currentDateTime = new \DateTime();
670
-						$secondsToExpiry = $pwdChangedTimeDt->getTimestamp() - $currentDateTime->getTimestamp();
671
-						if($secondsToExpiry <= $pwdExpireWarningInt) {
672
-							//remove last password expiry warning if any
673
-							$notification = $this->notificationManager->createNotification();
674
-							$notification->setApp('user_ldap')
675
-								->setUser($uid)
676
-								->setObject('pwd_exp_warn', $uid)
677
-							;
678
-							$this->notificationManager->markProcessed($notification);
679
-							//create new password expiry warning
680
-							$notification = $this->notificationManager->createNotification();
681
-							$notification->setApp('user_ldap')
682
-								->setUser($uid)
683
-								->setDateTime($currentDateTime)
684
-								->setObject('pwd_exp_warn', $uid) 
685
-								->setSubject('pwd_exp_warn_days', [(int) ceil($secondsToExpiry / 60 / 60 / 24)])
686
-							;
687
-							$this->notificationManager->notify($notification);
688
-						}
689
-					}
690
-				}
691
-			}
692
-		}
693
-	}
638
+            //handle grace login
639
+            $pwdGraceUseTimeCount = count($pwdGraceUseTime);
640
+            if($pwdGraceUseTime && $pwdGraceUseTimeCount > 0) { //was this a grace login?
641
+                if($pwdGraceAuthNLimit 
642
+                    && (count($pwdGraceAuthNLimit) > 0)
643
+                    &&($pwdGraceUseTimeCount < intval($pwdGraceAuthNLimit[0]))) { //at least one more grace login available?
644
+                    $this->config->setUserValue($uid, 'user_ldap', 'needsPasswordReset', 'true');
645
+                    header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute(
646
+                    'user_ldap.renewPassword.showRenewPasswordForm', array('user' => $uid)));
647
+                } else { //no more grace login available
648
+                    header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute(
649
+                    'user_ldap.renewPassword.showLoginFormInvalidPassword', array('user' => $uid)));
650
+                }
651
+                exit();
652
+            }
653
+            //handle pwdReset attribute
654
+            if($pwdReset && (count($pwdReset) > 0) && $pwdReset[0] === 'TRUE') { //user must change his password
655
+                $this->config->setUserValue($uid, 'user_ldap', 'needsPasswordReset', 'true');
656
+                header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute(
657
+                'user_ldap.renewPassword.showRenewPasswordForm', array('user' => $uid)));
658
+                exit();
659
+            }
660
+            //handle password expiry warning
661
+            if($pwdChangedTime && (count($pwdChangedTime) > 0)) {
662
+                if($pwdMaxAge && (count($pwdMaxAge) > 0)
663
+                    && $pwdExpireWarning && (count($pwdExpireWarning) > 0)) {
664
+                    $pwdMaxAgeInt = intval($pwdMaxAge[0]);
665
+                    $pwdExpireWarningInt = intval($pwdExpireWarning[0]);
666
+                    if($pwdMaxAgeInt > 0 && $pwdExpireWarningInt > 0){
667
+                        $pwdChangedTimeDt = \DateTime::createFromFormat('YmdHisZ', $pwdChangedTime[0]);
668
+                        $pwdChangedTimeDt->add(new \DateInterval('PT'.$pwdMaxAgeInt.'S'));
669
+                        $currentDateTime = new \DateTime();
670
+                        $secondsToExpiry = $pwdChangedTimeDt->getTimestamp() - $currentDateTime->getTimestamp();
671
+                        if($secondsToExpiry <= $pwdExpireWarningInt) {
672
+                            //remove last password expiry warning if any
673
+                            $notification = $this->notificationManager->createNotification();
674
+                            $notification->setApp('user_ldap')
675
+                                ->setUser($uid)
676
+                                ->setObject('pwd_exp_warn', $uid)
677
+                            ;
678
+                            $this->notificationManager->markProcessed($notification);
679
+                            //create new password expiry warning
680
+                            $notification = $this->notificationManager->createNotification();
681
+                            $notification->setApp('user_ldap')
682
+                                ->setUser($uid)
683
+                                ->setDateTime($currentDateTime)
684
+                                ->setObject('pwd_exp_warn', $uid) 
685
+                                ->setSubject('pwd_exp_warn_days', [(int) ceil($secondsToExpiry / 60 / 60 / 24)])
686
+                            ;
687
+                            $this->notificationManager->notify($notification);
688
+                        }
689
+                    }
690
+                }
691
+            }
692
+        }
693
+    }
694 694
 }
Please login to merge, or discard this patch.
Spacing   +58 added lines, -58 removed lines patch added patch discarded remove patch
@@ -149,17 +149,17 @@  discard block
 block discarded – undo
149 149
 	 * @return null
150 150
 	 */
151 151
 	public function update() {
152
-		if(is_null($this->dn)) {
152
+		if (is_null($this->dn)) {
153 153
 			return null;
154 154
 		}
155 155
 
156 156
 		$hasLoggedIn = $this->config->getUserValue($this->uid, 'user_ldap',
157 157
 				self::USER_PREFKEY_FIRSTLOGIN, 0);
158 158
 
159
-		if($this->needsRefresh()) {
159
+		if ($this->needsRefresh()) {
160 160
 			$this->updateEmail();
161 161
 			$this->updateQuota();
162
-			if($hasLoggedIn !== 0) {
162
+			if ($hasLoggedIn !== 0) {
163 163
 				//we do not need to try it, when the user has not been logged in
164 164
 				//before, because the file system will not be ready.
165 165
 				$this->updateAvatar();
@@ -178,7 +178,7 @@  discard block
 block discarded – undo
178 178
 		$this->markRefreshTime();
179 179
 		//Quota
180 180
 		$attr = strtolower($this->connection->ldapQuotaAttribute);
181
-		if(isset($ldapEntry[$attr])) {
181
+		if (isset($ldapEntry[$attr])) {
182 182
 			$this->updateQuota($ldapEntry[$attr][0]);
183 183
 		} else {
184 184
 			if ($this->connection->ldapQuotaDefault !== '') {
@@ -189,7 +189,7 @@  discard block
 block discarded – undo
189 189
 
190 190
 		//Email
191 191
 		$attr = strtolower($this->connection->ldapEmailAttribute);
192
-		if(isset($ldapEntry[$attr])) {
192
+		if (isset($ldapEntry[$attr])) {
193 193
 			$this->updateEmail($ldapEntry[$attr][0]);
194 194
 		}
195 195
 		unset($attr);
@@ -197,11 +197,11 @@  discard block
 block discarded – undo
197 197
 		//displayName
198 198
 		$displayName = $displayName2 = '';
199 199
 		$attr = strtolower($this->connection->ldapUserDisplayName);
200
-		if(isset($ldapEntry[$attr])) {
200
+		if (isset($ldapEntry[$attr])) {
201 201
 			$displayName = strval($ldapEntry[$attr][0]);
202 202
 		}
203 203
 		$attr = strtolower($this->connection->ldapUserDisplayName2);
204
-		if(isset($ldapEntry[$attr])) {
204
+		if (isset($ldapEntry[$attr])) {
205 205
 			$displayName2 = strval($ldapEntry[$attr][0]);
206 206
 		}
207 207
 		if ($displayName !== '') {
@@ -215,16 +215,16 @@  discard block
 block discarded – undo
215 215
 		unset($attr);
216 216
 
217 217
 		// LDAP Username, needed for s2s sharing
218
-		if(isset($ldapEntry['uid'])) {
218
+		if (isset($ldapEntry['uid'])) {
219 219
 			$this->storeLDAPUserName($ldapEntry['uid'][0]);
220
-		} else if(isset($ldapEntry['samaccountname'])) {
220
+		} else if (isset($ldapEntry['samaccountname'])) {
221 221
 			$this->storeLDAPUserName($ldapEntry['samaccountname'][0]);
222 222
 		}
223 223
 
224 224
 		//homePath
225
-		if(strpos($this->connection->homeFolderNamingRule, 'attr:') === 0) {
225
+		if (strpos($this->connection->homeFolderNamingRule, 'attr:') === 0) {
226 226
 			$attr = strtolower(substr($this->connection->homeFolderNamingRule, strlen('attr:')));
227
-			if(isset($ldapEntry[$attr])) {
227
+			if (isset($ldapEntry[$attr])) {
228 228
 				$this->access->cacheUserHome(
229 229
 					$this->getUsername(), $this->getHomePath($ldapEntry[$attr][0]));
230 230
 			}
@@ -233,15 +233,15 @@  discard block
 block discarded – undo
233 233
 		//memberOf groups
234 234
 		$cacheKey = 'getMemberOf'.$this->getUsername();
235 235
 		$groups = false;
236
-		if(isset($ldapEntry['memberof'])) {
236
+		if (isset($ldapEntry['memberof'])) {
237 237
 			$groups = $ldapEntry['memberof'];
238 238
 		}
239 239
 		$this->connection->writeToCache($cacheKey, $groups);
240 240
 
241 241
 		//Avatar
242 242
 		$attrs = array('jpegphoto', 'thumbnailphoto');
243
-		foreach ($attrs as $attr)  {
244
-			if(isset($ldapEntry[$attr])) {
243
+		foreach ($attrs as $attr) {
244
+			if (isset($ldapEntry[$attr])) {
245 245
 				$this->avatarImage = $ldapEntry[$attr][0];
246 246
 				// the call to the method that saves the avatar in the file
247 247
 				// system must be postponed after the login. It is to ensure
@@ -294,12 +294,12 @@  discard block
 block discarded – undo
294 294
 		if ($path !== '') {
295 295
 			//if attribute's value is an absolute path take this, otherwise append it to data dir
296 296
 			//check for / at the beginning or pattern c:\ resp. c:/
297
-			if(   '/' !== $path[0]
297
+			if ('/' !== $path[0]
298 298
 			   && !(3 < strlen($path) && ctype_alpha($path[0])
299 299
 			       && $path[1] === ':' && ('\\' === $path[2] || '/' === $path[2]))
300 300
 			) {
301 301
 				$path = $this->config->getSystemValue('datadirectory',
302
-						\OC::$SERVERROOT.'/data' ) . '/' . $path;
302
+						\OC::$SERVERROOT.'/data').'/'.$path;
303 303
 			}
304 304
 			//we need it to store it in the DB as well in case a user gets
305 305
 			//deleted so we can clean up afterwards
@@ -309,11 +309,11 @@  discard block
 block discarded – undo
309 309
 			return $path;
310 310
 		}
311 311
 
312
-		if(    !is_null($attr)
312
+		if (!is_null($attr)
313 313
 			&& $this->config->getAppValue('user_ldap', 'enforce_home_folder_naming_rule', true)
314 314
 		) {
315 315
 			// a naming rule attribute is defined, but it doesn't exist for that LDAP user
316
-			throw new \Exception('Home dir attribute can\'t be read from LDAP for uid: ' . $this->getUsername());
316
+			throw new \Exception('Home dir attribute can\'t be read from LDAP for uid: '.$this->getUsername());
317 317
 		}
318 318
 
319 319
 		//false will apply default behaviour as defined and done by OC_User
@@ -324,7 +324,7 @@  discard block
 block discarded – undo
324 324
 	public function getMemberOfGroups() {
325 325
 		$cacheKey = 'getMemberOf'.$this->getUsername();
326 326
 		$memberOfGroups = $this->connection->getFromCache($cacheKey);
327
-		if(!is_null($memberOfGroups)) {
327
+		if (!is_null($memberOfGroups)) {
328 328
 			return $memberOfGroups;
329 329
 		}
330 330
 		$groupDNs = $this->access->readAttribute($this->getDN(), 'memberOf');
@@ -337,15 +337,15 @@  discard block
 block discarded – undo
337 337
 	 * @return string data (provided by LDAP) | false
338 338
 	 */
339 339
 	public function getAvatarImage() {
340
-		if(!is_null($this->avatarImage)) {
340
+		if (!is_null($this->avatarImage)) {
341 341
 			return $this->avatarImage;
342 342
 		}
343 343
 
344 344
 		$this->avatarImage = false;
345 345
 		$attributes = array('jpegPhoto', 'thumbnailPhoto');
346
-		foreach($attributes as $attribute) {
346
+		foreach ($attributes as $attribute) {
347 347
 			$result = $this->access->readAttribute($this->dn, $attribute);
348
-			if($result !== false && is_array($result) && isset($result[0])) {
348
+			if ($result !== false && is_array($result) && isset($result[0])) {
349 349
 				$this->avatarImage = $result[0];
350 350
 				break;
351 351
 			}
@@ -383,7 +383,7 @@  discard block
 block discarded – undo
383 383
 			self::USER_PREFKEY_LASTREFRESH, 0);
384 384
 
385 385
 		//TODO make interval configurable
386
-		if((time() - intval($lastChecked)) < 86400 ) {
386
+		if ((time() - intval($lastChecked)) < 86400) {
387 387
 			return false;
388 388
 		}
389 389
 		return  true;
@@ -409,8 +409,8 @@  discard block
 block discarded – undo
409 409
 	 */
410 410
 	public function composeAndStoreDisplayName($displayName, $displayName2 = '') {
411 411
 		$displayName2 = strval($displayName2);
412
-		if($displayName2 !== '') {
413
-			$displayName .= ' (' . $displayName2 . ')';
412
+		if ($displayName2 !== '') {
413
+			$displayName .= ' ('.$displayName2.')';
414 414
 		}
415 415
 		$this->store('displayName', $displayName);
416 416
 		return $displayName;
@@ -432,7 +432,7 @@  discard block
 block discarded – undo
432 432
 	 * @return bool
433 433
 	 */
434 434
 	private function wasRefreshed($feature) {
435
-		if(isset($this->refreshedFeatures[$feature])) {
435
+		if (isset($this->refreshedFeatures[$feature])) {
436 436
 			return true;
437 437
 		}
438 438
 		$this->refreshedFeatures[$feature] = 1;
@@ -445,15 +445,15 @@  discard block
 block discarded – undo
445 445
 	 * @return null
446 446
 	 */
447 447
 	public function updateEmail($valueFromLDAP = null) {
448
-		if($this->wasRefreshed('email')) {
448
+		if ($this->wasRefreshed('email')) {
449 449
 			return;
450 450
 		}
451 451
 		$email = strval($valueFromLDAP);
452
-		if(is_null($valueFromLDAP)) {
452
+		if (is_null($valueFromLDAP)) {
453 453
 			$emailAttribute = $this->connection->ldapEmailAttribute;
454 454
 			if ($emailAttribute !== '') {
455 455
 				$aEmail = $this->access->readAttribute($this->dn, $emailAttribute);
456
-				if(is_array($aEmail) && (count($aEmail) > 0)) {
456
+				if (is_array($aEmail) && (count($aEmail) > 0)) {
457 457
 					$email = strval($aEmail[0]);
458 458
 				}
459 459
 			}
@@ -490,20 +490,20 @@  discard block
 block discarded – undo
490 490
 	 * @return null
491 491
 	 */
492 492
 	public function updateQuota($valueFromLDAP = null) {
493
-		if($this->wasRefreshed('quota')) {
493
+		if ($this->wasRefreshed('quota')) {
494 494
 			return;
495 495
 		}
496 496
 
497 497
 		$quota = false;
498
-		if(is_null($valueFromLDAP)) {
498
+		if (is_null($valueFromLDAP)) {
499 499
 			$quotaAttribute = $this->connection->ldapQuotaAttribute;
500 500
 			if ($quotaAttribute !== '') {
501 501
 				$aQuota = $this->access->readAttribute($this->dn, $quotaAttribute);
502
-				if($aQuota && (count($aQuota) > 0)) {
502
+				if ($aQuota && (count($aQuota) > 0)) {
503 503
 					if ($this->verifyQuotaValue($aQuota[0])) {
504 504
 						$quota = $aQuota[0];
505 505
 					} else {
506
-						$this->log->log('not suitable LDAP quota found for user ' . $this->uid . ': [' . $aQuota[0] . ']', \OCP\Util::WARN);
506
+						$this->log->log('not suitable LDAP quota found for user '.$this->uid.': ['.$aQuota[0].']', \OCP\Util::WARN);
507 507
 					}
508 508
 				}
509 509
 			}
@@ -511,7 +511,7 @@  discard block
 block discarded – undo
511 511
 			if ($this->verifyQuotaValue($valueFromLDAP)) {
512 512
 				$quota = $valueFromLDAP;
513 513
 			} else {
514
-				$this->log->log('not suitable LDAP quota found for user ' . $this->uid . ': [' . $valueFromLDAP . ']', \OCP\Util::WARN);
514
+				$this->log->log('not suitable LDAP quota found for user '.$this->uid.': ['.$valueFromLDAP.']', \OCP\Util::WARN);
515 515
 			}
516 516
 		}
517 517
 
@@ -525,13 +525,13 @@  discard block
 block discarded – undo
525 525
 
526 526
 		$targetUser = $this->userManager->get($this->uid);
527 527
 		if ($targetUser) {
528
-			if($quota !== false) {
528
+			if ($quota !== false) {
529 529
 				$targetUser->setQuota($quota);
530 530
 			} else {
531
-				$this->log->log('not suitable default quota found for user ' . $this->uid . ': [' . $defaultQuota . ']', \OCP\Util::WARN);
531
+				$this->log->log('not suitable default quota found for user '.$this->uid.': ['.$defaultQuota.']', \OCP\Util::WARN);
532 532
 			}
533 533
 		} else {
534
-			$this->log->log('trying to set a quota for user ' . $this->uid . ' but the user is missing', \OCP\Util::ERROR);
534
+			$this->log->log('trying to set a quota for user '.$this->uid.' but the user is missing', \OCP\Util::ERROR);
535 535
 		}
536 536
 	}
537 537
 
@@ -545,7 +545,7 @@  discard block
 block discarded – undo
545 545
 	 * @param array $params
546 546
 	 */
547 547
 	public function updateAvatarPostLogin($params) {
548
-		if(isset($params['uid']) && $params['uid'] === $this->getUsername()) {
548
+		if (isset($params['uid']) && $params['uid'] === $this->getUsername()) {
549 549
 			$this->updateAvatar();
550 550
 		}
551 551
 	}
@@ -555,11 +555,11 @@  discard block
 block discarded – undo
555 555
 	 * @return null
556 556
 	 */
557 557
 	public function updateAvatar() {
558
-		if($this->wasRefreshed('avatar')) {
558
+		if ($this->wasRefreshed('avatar')) {
559 559
 			return;
560 560
 		}
561 561
 		$avatarImage = $this->getAvatarImage();
562
-		if($avatarImage === false) {
562
+		if ($avatarImage === false) {
563 563
 			//not set, nothing left to do;
564 564
 			return;
565 565
 		}
@@ -572,18 +572,18 @@  discard block
 block discarded – undo
572 572
 	 * @return null
573 573
 	 */
574 574
 	private function setOwnCloudAvatar() {
575
-		if(!$this->image->valid()) {
575
+		if (!$this->image->valid()) {
576 576
 			$this->log->log('jpegPhoto data invalid for '.$this->dn, \OCP\Util::ERROR);
577 577
 			return;
578 578
 		}
579 579
 		//make sure it is a square and not bigger than 128x128
580 580
 		$size = min(array($this->image->width(), $this->image->height(), 128));
581
-		if(!$this->image->centerCrop($size)) {
581
+		if (!$this->image->centerCrop($size)) {
582 582
 			$this->log->log('croping image for avatar failed for '.$this->dn, \OCP\Util::ERROR);
583 583
 			return;
584 584
 		}
585 585
 
586
-		if(!$this->fs->isLoaded()) {
586
+		if (!$this->fs->isLoaded()) {
587 587
 			$this->fs->setup($this->uid);
588 588
 		}
589 589
 
@@ -592,7 +592,7 @@  discard block
 block discarded – undo
592 592
 			$avatar->set($this->image);
593 593
 		} catch (\Exception $e) {
594 594
 			\OC::$server->getLogger()->notice(
595
-				'Could not set avatar for ' . $this->dn	. ', because: ' . $e->getMessage(),
595
+				'Could not set avatar for '.$this->dn.', because: '.$e->getMessage(),
596 596
 				['app' => 'user_ldap']);
597 597
 		}
598 598
 	}
@@ -605,17 +605,17 @@  discard block
 block discarded – undo
605 605
 	public function handlePasswordExpiry($params) {
606 606
 		$ppolicyDN = $this->connection->ldapDefaultPPolicyDN;
607 607
 		if (empty($ppolicyDN) || (intval($this->connection->turnOnPasswordChange) !== 1)) {
608
-			return;//password expiry handling disabled
608
+			return; //password expiry handling disabled
609 609
 		}
610 610
 		$uid = $params['uid'];
611
-		if(isset($uid) && $uid === $this->getUsername()) {
611
+		if (isset($uid) && $uid === $this->getUsername()) {
612 612
 			//retrieve relevant user attributes
613 613
 			$result = $this->access->search('objectclass=*', $this->dn, ['pwdpolicysubentry', 'pwdgraceusetime', 'pwdreset', 'pwdchangedtime']);
614 614
 			
615
-			if(array_key_exists('pwdpolicysubentry', $result[0])) {
615
+			if (array_key_exists('pwdpolicysubentry', $result[0])) {
616 616
 				$pwdPolicySubentry = $result[0]['pwdpolicysubentry'];
617
-				if($pwdPolicySubentry && (count($pwdPolicySubentry) > 0)){
618
-					$ppolicyDN = $pwdPolicySubentry[0];//custom ppolicy DN
617
+				if ($pwdPolicySubentry && (count($pwdPolicySubentry) > 0)) {
618
+					$ppolicyDN = $pwdPolicySubentry[0]; //custom ppolicy DN
619 619
 				}
620 620
 			}
621 621
 			
@@ -624,9 +624,9 @@  discard block
 block discarded – undo
624 624
 			$pwdChangedTime = array_key_exists('pwdchangedtime', $result[0]) ? $result[0]['pwdchangedtime'] : null;
625 625
 			
626 626
 			//retrieve relevant password policy attributes
627
-			$cacheKey = 'ppolicyAttributes' . $ppolicyDN;
627
+			$cacheKey = 'ppolicyAttributes'.$ppolicyDN;
628 628
 			$result = $this->connection->getFromCache($cacheKey);
629
-			if(is_null($result)) {
629
+			if (is_null($result)) {
630 630
 				$result = $this->access->search('objectclass=*', $ppolicyDN, ['pwdgraceauthnlimit', 'pwdmaxage', 'pwdexpirewarning']);
631 631
 				$this->connection->writeToCache($cacheKey, $result);
632 632
 			}
@@ -637,8 +637,8 @@  discard block
 block discarded – undo
637 637
 			
638 638
 			//handle grace login
639 639
 			$pwdGraceUseTimeCount = count($pwdGraceUseTime);
640
-			if($pwdGraceUseTime && $pwdGraceUseTimeCount > 0) { //was this a grace login?
641
-				if($pwdGraceAuthNLimit 
640
+			if ($pwdGraceUseTime && $pwdGraceUseTimeCount > 0) { //was this a grace login?
641
+				if ($pwdGraceAuthNLimit 
642 642
 					&& (count($pwdGraceAuthNLimit) > 0)
643 643
 					&&($pwdGraceUseTimeCount < intval($pwdGraceAuthNLimit[0]))) { //at least one more grace login available?
644 644
 					$this->config->setUserValue($uid, 'user_ldap', 'needsPasswordReset', 'true');
@@ -651,24 +651,24 @@  discard block
 block discarded – undo
651 651
 				exit();
652 652
 			}
653 653
 			//handle pwdReset attribute
654
-			if($pwdReset && (count($pwdReset) > 0) && $pwdReset[0] === 'TRUE') { //user must change his password
654
+			if ($pwdReset && (count($pwdReset) > 0) && $pwdReset[0] === 'TRUE') { //user must change his password
655 655
 				$this->config->setUserValue($uid, 'user_ldap', 'needsPasswordReset', 'true');
656 656
 				header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute(
657 657
 				'user_ldap.renewPassword.showRenewPasswordForm', array('user' => $uid)));
658 658
 				exit();
659 659
 			}
660 660
 			//handle password expiry warning
661
-			if($pwdChangedTime && (count($pwdChangedTime) > 0)) {
662
-				if($pwdMaxAge && (count($pwdMaxAge) > 0)
661
+			if ($pwdChangedTime && (count($pwdChangedTime) > 0)) {
662
+				if ($pwdMaxAge && (count($pwdMaxAge) > 0)
663 663
 					&& $pwdExpireWarning && (count($pwdExpireWarning) > 0)) {
664 664
 					$pwdMaxAgeInt = intval($pwdMaxAge[0]);
665 665
 					$pwdExpireWarningInt = intval($pwdExpireWarning[0]);
666
-					if($pwdMaxAgeInt > 0 && $pwdExpireWarningInt > 0){
666
+					if ($pwdMaxAgeInt > 0 && $pwdExpireWarningInt > 0) {
667 667
 						$pwdChangedTimeDt = \DateTime::createFromFormat('YmdHisZ', $pwdChangedTime[0]);
668 668
 						$pwdChangedTimeDt->add(new \DateInterval('PT'.$pwdMaxAgeInt.'S'));
669 669
 						$currentDateTime = new \DateTime();
670 670
 						$secondsToExpiry = $pwdChangedTimeDt->getTimestamp() - $currentDateTime->getTimestamp();
671
-						if($secondsToExpiry <= $pwdExpireWarningInt) {
671
+						if ($secondsToExpiry <= $pwdExpireWarningInt) {
672 672
 							//remove last password expiry warning if any
673 673
 							$notification = $this->notificationManager->createNotification();
674 674
 							$notification->setApp('user_ldap')
Please login to merge, or discard this patch.