Passed
Push — master ( e50efc...4d0403 )
by Blizzz
17:07 queued 13s
created
apps/user_ldap/lib/Connection.php 1 patch
Indentation   +655 added lines, -655 removed lines patch added patch discarded remove patch
@@ -75,659 +75,659 @@
 block discarded – undo
75 75
  * @property string ldapMatchingRuleInChainState
76 76
  */
77 77
 class Connection extends LDAPUtility {
78
-	/**
79
-	 * @var resource|\LDAP\Connection|null
80
-	 */
81
-	private $ldapConnectionRes = null;
82
-
83
-	/**
84
-	 * @var string
85
-	 */
86
-	private $configPrefix;
87
-
88
-	/**
89
-	 * @var ?string
90
-	 */
91
-	private $configID;
92
-
93
-	/**
94
-	 * @var bool
95
-	 */
96
-	private $configured = false;
97
-
98
-	/**
99
-	 * @var bool whether connection should be kept on __destruct
100
-	 */
101
-	private $dontDestruct = false;
102
-
103
-	/**
104
-	 * @var bool runtime flag that indicates whether supported primary groups are available
105
-	 */
106
-	public $hasPrimaryGroups = true;
107
-
108
-	/**
109
-	 * @var bool runtime flag that indicates whether supported POSIX gidNumber are available
110
-	 */
111
-	public $hasGidNumber = true;
112
-
113
-	/**
114
-	 * @var \OCP\ICache|null
115
-	 */
116
-	protected $cache = null;
117
-
118
-	/** @var Configuration settings handler **/
119
-	protected $configuration;
120
-
121
-	/**
122
-	 * @var bool
123
-	 */
124
-	protected $doNotValidate = false;
125
-
126
-	/**
127
-	 * @var bool
128
-	 */
129
-	protected $ignoreValidation = false;
130
-
131
-	/**
132
-	 * @var array{sum?: string, result?: bool}
133
-	 */
134
-	protected $bindResult = [];
135
-
136
-	/** @var LoggerInterface */
137
-	protected $logger;
138
-
139
-	/**
140
-	 * Constructor
141
-	 * @param string $configPrefix a string with the prefix for the configkey column (appconfig table)
142
-	 * @param string|null $configID a string with the value for the appid column (appconfig table) or null for on-the-fly connections
143
-	 */
144
-	public function __construct(ILDAPWrapper $ldap, string $configPrefix = '', ?string $configID = 'user_ldap') {
145
-		parent::__construct($ldap);
146
-		$this->configPrefix = $configPrefix;
147
-		$this->configID = $configID;
148
-		$this->configuration = new Configuration($configPrefix, !is_null($configID));
149
-		$memcache = \OC::$server->getMemCacheFactory();
150
-		if ($memcache->isAvailable()) {
151
-			$this->cache = $memcache->createDistributed();
152
-		}
153
-		$helper = new Helper(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection());
154
-		$this->doNotValidate = !in_array($this->configPrefix,
155
-			$helper->getServerConfigurationPrefixes());
156
-		$this->logger = \OC::$server->get(LoggerInterface::class);
157
-	}
158
-
159
-	public function __destruct() {
160
-		if (!$this->dontDestruct && $this->ldap->isResource($this->ldapConnectionRes)) {
161
-			@$this->ldap->unbind($this->ldapConnectionRes);
162
-			$this->bindResult = [];
163
-		}
164
-	}
165
-
166
-	/**
167
-	 * defines behaviour when the instance is cloned
168
-	 */
169
-	public function __clone() {
170
-		$this->configuration = new Configuration($this->configPrefix,
171
-			!is_null($this->configID));
172
-		if (count($this->bindResult) !== 0 && $this->bindResult['result'] === true) {
173
-			$this->bindResult = [];
174
-		}
175
-		$this->ldapConnectionRes = null;
176
-		$this->dontDestruct = true;
177
-	}
178
-
179
-	public function __get(string $name) {
180
-		if (!$this->configured) {
181
-			$this->readConfiguration();
182
-		}
183
-
184
-		return $this->configuration->$name;
185
-	}
186
-
187
-	/**
188
-	 * @param string $name
189
-	 * @param mixed $value
190
-	 */
191
-	public function __set($name, $value) {
192
-		$this->doNotValidate = false;
193
-		$before = $this->configuration->$name;
194
-		$this->configuration->$name = $value;
195
-		$after = $this->configuration->$name;
196
-		if ($before !== $after) {
197
-			if ($this->configID !== '' && $this->configID !== null) {
198
-				$this->configuration->saveConfiguration();
199
-			}
200
-			$this->validateConfiguration();
201
-		}
202
-	}
203
-
204
-	/**
205
-	 * @param string $rule
206
-	 * @return array
207
-	 * @throws \RuntimeException
208
-	 */
209
-	public function resolveRule($rule) {
210
-		return $this->configuration->resolveRule($rule);
211
-	}
212
-
213
-	/**
214
-	 * sets whether the result of the configuration validation shall
215
-	 * be ignored when establishing the connection. Used by the Wizard
216
-	 * in early configuration state.
217
-	 * @param bool $state
218
-	 */
219
-	public function setIgnoreValidation($state) {
220
-		$this->ignoreValidation = (bool)$state;
221
-	}
222
-
223
-	/**
224
-	 * initializes the LDAP backend
225
-	 * @param bool $force read the config settings no matter what
226
-	 */
227
-	public function init($force = false) {
228
-		$this->readConfiguration($force);
229
-		$this->establishConnection();
230
-	}
231
-
232
-	/**
233
-	 * @return resource|\LDAP\Connection The LDAP resource
234
-	 */
235
-	public function getConnectionResource() {
236
-		if (!$this->ldapConnectionRes) {
237
-			$this->init();
238
-		} elseif (!$this->ldap->isResource($this->ldapConnectionRes)) {
239
-			$this->ldapConnectionRes = null;
240
-			$this->establishConnection();
241
-		}
242
-		if (is_null($this->ldapConnectionRes)) {
243
-			$this->logger->error(
244
-				'No LDAP Connection to server ' . $this->configuration->ldapHost,
245
-				['app' => 'user_ldap']
246
-			);
247
-			throw new ServerNotAvailableException('Connection to LDAP server could not be established');
248
-		}
249
-		return $this->ldapConnectionRes;
250
-	}
251
-
252
-	/**
253
-	 * resets the connection resource
254
-	 */
255
-	public function resetConnectionResource() {
256
-		if (!is_null($this->ldapConnectionRes)) {
257
-			@$this->ldap->unbind($this->ldapConnectionRes);
258
-			$this->ldapConnectionRes = null;
259
-			$this->bindResult = [];
260
-		}
261
-	}
262
-
263
-	/**
264
-	 * @param string|null $key
265
-	 * @return string
266
-	 */
267
-	private function getCacheKey($key) {
268
-		$prefix = 'LDAP-'.$this->configID.'-'.$this->configPrefix.'-';
269
-		if (is_null($key)) {
270
-			return $prefix;
271
-		}
272
-		return $prefix.hash('sha256', $key);
273
-	}
274
-
275
-	/**
276
-	 * @param string $key
277
-	 * @return mixed|null
278
-	 */
279
-	public function getFromCache($key) {
280
-		if (!$this->configured) {
281
-			$this->readConfiguration();
282
-		}
283
-		if (is_null($this->cache) || !$this->configuration->ldapCacheTTL) {
284
-			return null;
285
-		}
286
-		$key = $this->getCacheKey($key);
287
-
288
-		return json_decode(base64_decode($this->cache->get($key) ?? ''), true);
289
-	}
290
-
291
-	/**
292
-	 * @param string $key
293
-	 * @param mixed $value
294
-	 */
295
-	public function writeToCache($key, $value): void {
296
-		if (!$this->configured) {
297
-			$this->readConfiguration();
298
-		}
299
-		if (is_null($this->cache)
300
-			|| !$this->configuration->ldapCacheTTL
301
-			|| !$this->configuration->ldapConfigurationActive) {
302
-			return;
303
-		}
304
-		$key = $this->getCacheKey($key);
305
-		$value = base64_encode(json_encode($value));
306
-		$this->cache->set($key, $value, $this->configuration->ldapCacheTTL);
307
-	}
308
-
309
-	public function clearCache() {
310
-		if (!is_null($this->cache)) {
311
-			$this->cache->clear($this->getCacheKey(null));
312
-		}
313
-	}
314
-
315
-	/**
316
-	 * Caches the general LDAP configuration.
317
-	 * @param bool $force optional. true, if the re-read should be forced. defaults
318
-	 * to false.
319
-	 * @return null
320
-	 */
321
-	private function readConfiguration($force = false) {
322
-		if ((!$this->configured || $force) && !is_null($this->configID)) {
323
-			$this->configuration->readConfiguration();
324
-			$this->configured = $this->validateConfiguration();
325
-		}
326
-	}
327
-
328
-	/**
329
-	 * set LDAP configuration with values delivered by an array, not read from configuration
330
-	 * @param array $config array that holds the config parameters in an associated array
331
-	 * @param array &$setParameters optional; array where the set fields will be given to
332
-	 * @return bool true if config validates, false otherwise. Check with $setParameters for detailed success on single parameters
333
-	 */
334
-	public function setConfiguration($config, &$setParameters = null): bool {
335
-		if (is_null($setParameters)) {
336
-			$setParameters = [];
337
-		}
338
-		$this->doNotValidate = false;
339
-		$this->configuration->setConfiguration($config, $setParameters);
340
-		if (count($setParameters) > 0) {
341
-			$this->configured = $this->validateConfiguration();
342
-		}
343
-
344
-
345
-		return $this->configured;
346
-	}
347
-
348
-	/**
349
-	 * saves the current Configuration in the database and empties the
350
-	 * cache
351
-	 * @return null
352
-	 */
353
-	public function saveConfiguration() {
354
-		$this->configuration->saveConfiguration();
355
-		$this->clearCache();
356
-	}
357
-
358
-	/**
359
-	 * get the current LDAP configuration
360
-	 * @return array
361
-	 */
362
-	public function getConfiguration() {
363
-		$this->readConfiguration();
364
-		$config = $this->configuration->getConfiguration();
365
-		$cta = $this->configuration->getConfigTranslationArray();
366
-		$result = [];
367
-		foreach ($cta as $dbkey => $configkey) {
368
-			switch ($configkey) {
369
-				case 'homeFolderNamingRule':
370
-					if (strpos($config[$configkey], 'attr:') === 0) {
371
-						$result[$dbkey] = substr($config[$configkey], 5);
372
-					} else {
373
-						$result[$dbkey] = '';
374
-					}
375
-					break;
376
-				case 'ldapBase':
377
-				case 'ldapBaseUsers':
378
-				case 'ldapBaseGroups':
379
-				case 'ldapAttributesForUserSearch':
380
-				case 'ldapAttributesForGroupSearch':
381
-					if (is_array($config[$configkey])) {
382
-						$result[$dbkey] = implode("\n", $config[$configkey]);
383
-						break;
384
-					} //else follows default
385
-					// no break
386
-				default:
387
-					$result[$dbkey] = $config[$configkey];
388
-			}
389
-		}
390
-		return $result;
391
-	}
392
-
393
-	private function doSoftValidation() {
394
-		//if User or Group Base are not set, take over Base DN setting
395
-		foreach (['ldapBaseUsers', 'ldapBaseGroups'] as $keyBase) {
396
-			$val = $this->configuration->$keyBase;
397
-			if (empty($val)) {
398
-				$this->configuration->$keyBase = $this->configuration->ldapBase;
399
-			}
400
-		}
401
-
402
-		foreach (['ldapExpertUUIDUserAttr' => 'ldapUuidUserAttribute',
403
-			'ldapExpertUUIDGroupAttr' => 'ldapUuidGroupAttribute']
404
-				as $expertSetting => $effectiveSetting) {
405
-			$uuidOverride = $this->configuration->$expertSetting;
406
-			if (!empty($uuidOverride)) {
407
-				$this->configuration->$effectiveSetting = $uuidOverride;
408
-			} else {
409
-				$uuidAttributes = Access::UUID_ATTRIBUTES;
410
-				array_unshift($uuidAttributes, 'auto');
411
-				if (!in_array($this->configuration->$effectiveSetting, $uuidAttributes)
412
-					&& !is_null($this->configID)) {
413
-					$this->configuration->$effectiveSetting = 'auto';
414
-					$this->configuration->saveConfiguration();
415
-					$this->logger->info(
416
-						'Illegal value for the '.$effectiveSetting.', reset to autodetect.',
417
-						['app' => 'user_ldap']
418
-					);
419
-				}
420
-			}
421
-		}
422
-
423
-		$backupPort = (int)$this->configuration->ldapBackupPort;
424
-		if ($backupPort <= 0) {
425
-			$this->configuration->backupPort = $this->configuration->ldapPort;
426
-		}
427
-
428
-		//make sure empty search attributes are saved as simple, empty array
429
-		$saKeys = ['ldapAttributesForUserSearch',
430
-			'ldapAttributesForGroupSearch'];
431
-		foreach ($saKeys as $key) {
432
-			$val = $this->configuration->$key;
433
-			if (is_array($val) && count($val) === 1 && empty($val[0])) {
434
-				$this->configuration->$key = [];
435
-			}
436
-		}
437
-
438
-		if ((stripos((string)$this->configuration->ldapHost, 'ldaps://') === 0)
439
-			&& $this->configuration->ldapTLS) {
440
-			$this->configuration->ldapTLS = false;
441
-			$this->logger->info(
442
-				'LDAPS (already using secure connection) and TLS do not work together. Switched off TLS.',
443
-				['app' => 'user_ldap']
444
-			);
445
-		}
446
-	}
447
-
448
-	/**
449
-	 * @return bool
450
-	 */
451
-	private function doCriticalValidation() {
452
-		$configurationOK = true;
453
-		$errorStr = 'Configuration Error (prefix '.
454
-			(string)$this->configPrefix .'): ';
455
-
456
-		//options that shall not be empty
457
-		$options = ['ldapHost', 'ldapUserDisplayName',
458
-			'ldapGroupDisplayName', 'ldapLoginFilter'];
459
-
460
-		//ldapPort should not be empty either unless ldapHost is pointing to a socket
461
-		if (!$this->configuration->usesLdapi()) {
462
-			$options[] = 'ldapPort';
463
-		}
464
-
465
-		foreach ($options as $key) {
466
-			$val = $this->configuration->$key;
467
-			if (empty($val)) {
468
-				switch ($key) {
469
-					case 'ldapHost':
470
-						$subj = 'LDAP Host';
471
-						break;
472
-					case 'ldapPort':
473
-						$subj = 'LDAP Port';
474
-						break;
475
-					case 'ldapUserDisplayName':
476
-						$subj = 'LDAP User Display Name';
477
-						break;
478
-					case 'ldapGroupDisplayName':
479
-						$subj = 'LDAP Group Display Name';
480
-						break;
481
-					case 'ldapLoginFilter':
482
-						$subj = 'LDAP Login Filter';
483
-						break;
484
-					default:
485
-						$subj = $key;
486
-						break;
487
-				}
488
-				$configurationOK = false;
489
-				$this->logger->warning(
490
-					$errorStr.'No '.$subj.' given!',
491
-					['app' => 'user_ldap']
492
-				);
493
-			}
494
-		}
495
-
496
-		//combinations
497
-		$agent = $this->configuration->ldapAgentName;
498
-		$pwd = $this->configuration->ldapAgentPassword;
499
-		if (
500
-			($agent === '' && $pwd !== '')
501
-			|| ($agent !== '' && $pwd === '')
502
-		) {
503
-			$this->logger->warning(
504
-				$errorStr.'either no password is given for the user ' .
505
-					'agent or a password is given, but not an LDAP agent.',
506
-				['app' => 'user_ldap']
507
-			);
508
-			$configurationOK = false;
509
-		}
510
-
511
-		$base = $this->configuration->ldapBase;
512
-		$baseUsers = $this->configuration->ldapBaseUsers;
513
-		$baseGroups = $this->configuration->ldapBaseGroups;
514
-
515
-		if (empty($base) && empty($baseUsers) && empty($baseGroups)) {
516
-			$this->logger->warning(
517
-				$errorStr.'Not a single Base DN given.',
518
-				['app' => 'user_ldap']
519
-			);
520
-			$configurationOK = false;
521
-		}
522
-
523
-		if (mb_strpos((string)$this->configuration->ldapLoginFilter, '%uid', 0, 'UTF-8')
524
-		   === false) {
525
-			$this->logger->warning(
526
-				$errorStr.'login filter does not contain %uid place holder.',
527
-				['app' => 'user_ldap']
528
-			);
529
-			$configurationOK = false;
530
-		}
531
-
532
-		return $configurationOK;
533
-	}
534
-
535
-	/**
536
-	 * Validates the user specified configuration
537
-	 * @return bool true if configuration seems OK, false otherwise
538
-	 */
539
-	private function validateConfiguration() {
540
-		if ($this->doNotValidate) {
541
-			//don't do a validation if it is a new configuration with pure
542
-			//default values. Will be allowed on changes via __set or
543
-			//setConfiguration
544
-			return false;
545
-		}
546
-
547
-		// first step: "soft" checks: settings that are not really
548
-		// necessary, but advisable. If left empty, give an info message
549
-		$this->doSoftValidation();
550
-
551
-		//second step: critical checks. If left empty or filled wrong, mark as
552
-		//not configured and give a warning.
553
-		return $this->doCriticalValidation();
554
-	}
555
-
556
-
557
-	/**
558
-	 * Connects and Binds to LDAP
559
-	 *
560
-	 * @throws ServerNotAvailableException
561
-	 */
562
-	private function establishConnection() {
563
-		if (!$this->configuration->ldapConfigurationActive) {
564
-			return null;
565
-		}
566
-		static $phpLDAPinstalled = true;
567
-		if (!$phpLDAPinstalled) {
568
-			return false;
569
-		}
570
-		if (!$this->ignoreValidation && !$this->configured) {
571
-			$this->logger->warning(
572
-				'Configuration is invalid, cannot connect',
573
-				['app' => 'user_ldap']
574
-			);
575
-			return false;
576
-		}
577
-		if (!$this->ldapConnectionRes) {
578
-			if (!$this->ldap->areLDAPFunctionsAvailable()) {
579
-				$phpLDAPinstalled = false;
580
-				$this->logger->error(
581
-					'function ldap_connect is not available. Make sure that the PHP ldap module is installed.',
582
-					['app' => 'user_ldap']
583
-				);
584
-
585
-				return false;
586
-			}
587
-			if ($this->configuration->turnOffCertCheck) {
588
-				if (putenv('LDAPTLS_REQCERT=never')) {
589
-					$this->logger->debug(
590
-						'Turned off SSL certificate validation successfully.',
591
-						['app' => 'user_ldap']
592
-					);
593
-				} else {
594
-					$this->logger->warning(
595
-						'Could not turn off SSL certificate validation.',
596
-						['app' => 'user_ldap']
597
-					);
598
-				}
599
-			}
600
-
601
-			$hasBackupHost = (trim($this->configuration->ldapBackupHost ?? '') !== '');
602
-			$hasBackgroundHost = (trim($this->configuration->ldapBackgroundHost ?? '') !== '');
603
-			$useBackgroundHost = (\OC::$CLI && $hasBackgroundHost);
604
-			$overrideCacheKey = ($useBackgroundHost ? 'overrideBackgroundServer' : 'overrideMainServer');
605
-			$forceBackupHost = ($this->configuration->ldapOverrideMainServer || $this->getFromCache($overrideCacheKey));
606
-			$bindStatus = false;
607
-			if (!$forceBackupHost) {
608
-				try {
609
-					$host = $this->configuration->ldapHost ?? '';
610
-					$port = $this->configuration->ldapPort ?? '';
611
-					if ($useBackgroundHost) {
612
-						$host = $this->configuration->ldapBackgroundHost ?? '';
613
-						$port = $this->configuration->ldapBackgroundPort ?? '';
614
-					}
615
-					$this->doConnect($host, $port);
616
-					return $this->bind();
617
-				} catch (ServerNotAvailableException $e) {
618
-					if (!$hasBackupHost) {
619
-						throw $e;
620
-					}
621
-				}
622
-				$this->logger->warning(
623
-					'Main LDAP not reachable, connecting to backup',
624
-					[
625
-						'app' => 'user_ldap'
626
-					]
627
-				);
628
-			}
629
-
630
-			// if LDAP server is not reachable, try the Backup (Replica!) Server
631
-			$this->doConnect($this->configuration->ldapBackupHost ?? '', $this->configuration->ldapBackupPort ?? '');
632
-			$this->bindResult = [];
633
-			$bindStatus = $this->bind();
634
-			$error = $this->ldap->isResource($this->ldapConnectionRes) ?
635
-				$this->ldap->errno($this->ldapConnectionRes) : -1;
636
-			if ($bindStatus && $error === 0 && !$forceBackupHost) {
637
-				//when bind to backup server succeeded and failed to main server,
638
-				//skip contacting him until next cache refresh
639
-				$this->writeToCache($overrideCacheKey, true);
640
-			}
641
-
642
-			return $bindStatus;
643
-		}
644
-		return null;
645
-	}
646
-
647
-	/**
648
-	 * @param string $host
649
-	 * @param string $port
650
-	 * @return bool
651
-	 * @throws \OC\ServerNotAvailableException
652
-	 */
653
-	private function doConnect($host, $port) {
654
-		if ($host === '') {
655
-			return false;
656
-		}
657
-
658
-		$this->ldapConnectionRes = $this->ldap->connect($host, $port);
659
-
660
-		if (!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
661
-			throw new ServerNotAvailableException('Could not set required LDAP Protocol version.');
662
-		}
663
-
664
-		if (!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
665
-			throw new ServerNotAvailableException('Could not disable LDAP referrals.');
666
-		}
667
-
668
-		if (!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_NETWORK_TIMEOUT, $this->configuration->ldapConnectionTimeout)) {
669
-			throw new ServerNotAvailableException('Could not set network timeout');
670
-		}
671
-
672
-		if ($this->configuration->ldapTLS) {
673
-			if (!$this->ldap->startTls($this->ldapConnectionRes)) {
674
-				throw new ServerNotAvailableException('Start TLS failed, when connecting to LDAP host ' . $host . '.');
675
-			}
676
-		}
677
-
678
-		return true;
679
-	}
680
-
681
-	/**
682
-	 * Binds to LDAP
683
-	 */
684
-	public function bind() {
685
-		if (!$this->configuration->ldapConfigurationActive) {
686
-			return false;
687
-		}
688
-		$cr = $this->ldapConnectionRes;
689
-		if (!$this->ldap->isResource($cr)) {
690
-			$cr = $this->getConnectionResource();
691
-		}
692
-
693
-		if (
694
-			count($this->bindResult) !== 0
695
-			&& $this->bindResult['sum'] === md5($this->configuration->ldapAgentName . $this->configPrefix . $this->configuration->ldapAgentPassword)
696
-		) {
697
-			// don't attempt to bind again with the same data as before
698
-			// bind might have been invoked via getConnectionResource(),
699
-			// but we need results specifically for e.g. user login
700
-			return $this->bindResult['result'];
701
-		}
702
-
703
-		$ldapLogin = @$this->ldap->bind($cr,
704
-			$this->configuration->ldapAgentName,
705
-			$this->configuration->ldapAgentPassword);
706
-
707
-		$this->bindResult = [
708
-			'sum' => md5($this->configuration->ldapAgentName . $this->configPrefix . $this->configuration->ldapAgentPassword),
709
-			'result' => $ldapLogin,
710
-		];
711
-
712
-		if (!$ldapLogin) {
713
-			$errno = $this->ldap->errno($cr);
714
-
715
-			$this->logger->warning(
716
-				'Bind failed: ' . $errno . ': ' . $this->ldap->error($cr),
717
-				['app' => 'user_ldap']
718
-			);
719
-
720
-			// Set to failure mode, if LDAP error code is not one of
721
-			// - LDAP_SUCCESS (0)
722
-			// - LDAP_INVALID_CREDENTIALS (49)
723
-			// - LDAP_INSUFFICIENT_ACCESS (50, spotted Apple Open Directory)
724
-			// - LDAP_UNWILLING_TO_PERFORM (53, spotted eDirectory)
725
-			if (!in_array($errno, [0, 49, 50, 53], true)) {
726
-				$this->ldapConnectionRes = null;
727
-			}
728
-
729
-			return false;
730
-		}
731
-		return true;
732
-	}
78
+    /**
79
+     * @var resource|\LDAP\Connection|null
80
+     */
81
+    private $ldapConnectionRes = null;
82
+
83
+    /**
84
+     * @var string
85
+     */
86
+    private $configPrefix;
87
+
88
+    /**
89
+     * @var ?string
90
+     */
91
+    private $configID;
92
+
93
+    /**
94
+     * @var bool
95
+     */
96
+    private $configured = false;
97
+
98
+    /**
99
+     * @var bool whether connection should be kept on __destruct
100
+     */
101
+    private $dontDestruct = false;
102
+
103
+    /**
104
+     * @var bool runtime flag that indicates whether supported primary groups are available
105
+     */
106
+    public $hasPrimaryGroups = true;
107
+
108
+    /**
109
+     * @var bool runtime flag that indicates whether supported POSIX gidNumber are available
110
+     */
111
+    public $hasGidNumber = true;
112
+
113
+    /**
114
+     * @var \OCP\ICache|null
115
+     */
116
+    protected $cache = null;
117
+
118
+    /** @var Configuration settings handler **/
119
+    protected $configuration;
120
+
121
+    /**
122
+     * @var bool
123
+     */
124
+    protected $doNotValidate = false;
125
+
126
+    /**
127
+     * @var bool
128
+     */
129
+    protected $ignoreValidation = false;
130
+
131
+    /**
132
+     * @var array{sum?: string, result?: bool}
133
+     */
134
+    protected $bindResult = [];
135
+
136
+    /** @var LoggerInterface */
137
+    protected $logger;
138
+
139
+    /**
140
+     * Constructor
141
+     * @param string $configPrefix a string with the prefix for the configkey column (appconfig table)
142
+     * @param string|null $configID a string with the value for the appid column (appconfig table) or null for on-the-fly connections
143
+     */
144
+    public function __construct(ILDAPWrapper $ldap, string $configPrefix = '', ?string $configID = 'user_ldap') {
145
+        parent::__construct($ldap);
146
+        $this->configPrefix = $configPrefix;
147
+        $this->configID = $configID;
148
+        $this->configuration = new Configuration($configPrefix, !is_null($configID));
149
+        $memcache = \OC::$server->getMemCacheFactory();
150
+        if ($memcache->isAvailable()) {
151
+            $this->cache = $memcache->createDistributed();
152
+        }
153
+        $helper = new Helper(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection());
154
+        $this->doNotValidate = !in_array($this->configPrefix,
155
+            $helper->getServerConfigurationPrefixes());
156
+        $this->logger = \OC::$server->get(LoggerInterface::class);
157
+    }
158
+
159
+    public function __destruct() {
160
+        if (!$this->dontDestruct && $this->ldap->isResource($this->ldapConnectionRes)) {
161
+            @$this->ldap->unbind($this->ldapConnectionRes);
162
+            $this->bindResult = [];
163
+        }
164
+    }
165
+
166
+    /**
167
+     * defines behaviour when the instance is cloned
168
+     */
169
+    public function __clone() {
170
+        $this->configuration = new Configuration($this->configPrefix,
171
+            !is_null($this->configID));
172
+        if (count($this->bindResult) !== 0 && $this->bindResult['result'] === true) {
173
+            $this->bindResult = [];
174
+        }
175
+        $this->ldapConnectionRes = null;
176
+        $this->dontDestruct = true;
177
+    }
178
+
179
+    public function __get(string $name) {
180
+        if (!$this->configured) {
181
+            $this->readConfiguration();
182
+        }
183
+
184
+        return $this->configuration->$name;
185
+    }
186
+
187
+    /**
188
+     * @param string $name
189
+     * @param mixed $value
190
+     */
191
+    public function __set($name, $value) {
192
+        $this->doNotValidate = false;
193
+        $before = $this->configuration->$name;
194
+        $this->configuration->$name = $value;
195
+        $after = $this->configuration->$name;
196
+        if ($before !== $after) {
197
+            if ($this->configID !== '' && $this->configID !== null) {
198
+                $this->configuration->saveConfiguration();
199
+            }
200
+            $this->validateConfiguration();
201
+        }
202
+    }
203
+
204
+    /**
205
+     * @param string $rule
206
+     * @return array
207
+     * @throws \RuntimeException
208
+     */
209
+    public function resolveRule($rule) {
210
+        return $this->configuration->resolveRule($rule);
211
+    }
212
+
213
+    /**
214
+     * sets whether the result of the configuration validation shall
215
+     * be ignored when establishing the connection. Used by the Wizard
216
+     * in early configuration state.
217
+     * @param bool $state
218
+     */
219
+    public function setIgnoreValidation($state) {
220
+        $this->ignoreValidation = (bool)$state;
221
+    }
222
+
223
+    /**
224
+     * initializes the LDAP backend
225
+     * @param bool $force read the config settings no matter what
226
+     */
227
+    public function init($force = false) {
228
+        $this->readConfiguration($force);
229
+        $this->establishConnection();
230
+    }
231
+
232
+    /**
233
+     * @return resource|\LDAP\Connection The LDAP resource
234
+     */
235
+    public function getConnectionResource() {
236
+        if (!$this->ldapConnectionRes) {
237
+            $this->init();
238
+        } elseif (!$this->ldap->isResource($this->ldapConnectionRes)) {
239
+            $this->ldapConnectionRes = null;
240
+            $this->establishConnection();
241
+        }
242
+        if (is_null($this->ldapConnectionRes)) {
243
+            $this->logger->error(
244
+                'No LDAP Connection to server ' . $this->configuration->ldapHost,
245
+                ['app' => 'user_ldap']
246
+            );
247
+            throw new ServerNotAvailableException('Connection to LDAP server could not be established');
248
+        }
249
+        return $this->ldapConnectionRes;
250
+    }
251
+
252
+    /**
253
+     * resets the connection resource
254
+     */
255
+    public function resetConnectionResource() {
256
+        if (!is_null($this->ldapConnectionRes)) {
257
+            @$this->ldap->unbind($this->ldapConnectionRes);
258
+            $this->ldapConnectionRes = null;
259
+            $this->bindResult = [];
260
+        }
261
+    }
262
+
263
+    /**
264
+     * @param string|null $key
265
+     * @return string
266
+     */
267
+    private function getCacheKey($key) {
268
+        $prefix = 'LDAP-'.$this->configID.'-'.$this->configPrefix.'-';
269
+        if (is_null($key)) {
270
+            return $prefix;
271
+        }
272
+        return $prefix.hash('sha256', $key);
273
+    }
274
+
275
+    /**
276
+     * @param string $key
277
+     * @return mixed|null
278
+     */
279
+    public function getFromCache($key) {
280
+        if (!$this->configured) {
281
+            $this->readConfiguration();
282
+        }
283
+        if (is_null($this->cache) || !$this->configuration->ldapCacheTTL) {
284
+            return null;
285
+        }
286
+        $key = $this->getCacheKey($key);
287
+
288
+        return json_decode(base64_decode($this->cache->get($key) ?? ''), true);
289
+    }
290
+
291
+    /**
292
+     * @param string $key
293
+     * @param mixed $value
294
+     */
295
+    public function writeToCache($key, $value): void {
296
+        if (!$this->configured) {
297
+            $this->readConfiguration();
298
+        }
299
+        if (is_null($this->cache)
300
+            || !$this->configuration->ldapCacheTTL
301
+            || !$this->configuration->ldapConfigurationActive) {
302
+            return;
303
+        }
304
+        $key = $this->getCacheKey($key);
305
+        $value = base64_encode(json_encode($value));
306
+        $this->cache->set($key, $value, $this->configuration->ldapCacheTTL);
307
+    }
308
+
309
+    public function clearCache() {
310
+        if (!is_null($this->cache)) {
311
+            $this->cache->clear($this->getCacheKey(null));
312
+        }
313
+    }
314
+
315
+    /**
316
+     * Caches the general LDAP configuration.
317
+     * @param bool $force optional. true, if the re-read should be forced. defaults
318
+     * to false.
319
+     * @return null
320
+     */
321
+    private function readConfiguration($force = false) {
322
+        if ((!$this->configured || $force) && !is_null($this->configID)) {
323
+            $this->configuration->readConfiguration();
324
+            $this->configured = $this->validateConfiguration();
325
+        }
326
+    }
327
+
328
+    /**
329
+     * set LDAP configuration with values delivered by an array, not read from configuration
330
+     * @param array $config array that holds the config parameters in an associated array
331
+     * @param array &$setParameters optional; array where the set fields will be given to
332
+     * @return bool true if config validates, false otherwise. Check with $setParameters for detailed success on single parameters
333
+     */
334
+    public function setConfiguration($config, &$setParameters = null): bool {
335
+        if (is_null($setParameters)) {
336
+            $setParameters = [];
337
+        }
338
+        $this->doNotValidate = false;
339
+        $this->configuration->setConfiguration($config, $setParameters);
340
+        if (count($setParameters) > 0) {
341
+            $this->configured = $this->validateConfiguration();
342
+        }
343
+
344
+
345
+        return $this->configured;
346
+    }
347
+
348
+    /**
349
+     * saves the current Configuration in the database and empties the
350
+     * cache
351
+     * @return null
352
+     */
353
+    public function saveConfiguration() {
354
+        $this->configuration->saveConfiguration();
355
+        $this->clearCache();
356
+    }
357
+
358
+    /**
359
+     * get the current LDAP configuration
360
+     * @return array
361
+     */
362
+    public function getConfiguration() {
363
+        $this->readConfiguration();
364
+        $config = $this->configuration->getConfiguration();
365
+        $cta = $this->configuration->getConfigTranslationArray();
366
+        $result = [];
367
+        foreach ($cta as $dbkey => $configkey) {
368
+            switch ($configkey) {
369
+                case 'homeFolderNamingRule':
370
+                    if (strpos($config[$configkey], 'attr:') === 0) {
371
+                        $result[$dbkey] = substr($config[$configkey], 5);
372
+                    } else {
373
+                        $result[$dbkey] = '';
374
+                    }
375
+                    break;
376
+                case 'ldapBase':
377
+                case 'ldapBaseUsers':
378
+                case 'ldapBaseGroups':
379
+                case 'ldapAttributesForUserSearch':
380
+                case 'ldapAttributesForGroupSearch':
381
+                    if (is_array($config[$configkey])) {
382
+                        $result[$dbkey] = implode("\n", $config[$configkey]);
383
+                        break;
384
+                    } //else follows default
385
+                    // no break
386
+                default:
387
+                    $result[$dbkey] = $config[$configkey];
388
+            }
389
+        }
390
+        return $result;
391
+    }
392
+
393
+    private function doSoftValidation() {
394
+        //if User or Group Base are not set, take over Base DN setting
395
+        foreach (['ldapBaseUsers', 'ldapBaseGroups'] as $keyBase) {
396
+            $val = $this->configuration->$keyBase;
397
+            if (empty($val)) {
398
+                $this->configuration->$keyBase = $this->configuration->ldapBase;
399
+            }
400
+        }
401
+
402
+        foreach (['ldapExpertUUIDUserAttr' => 'ldapUuidUserAttribute',
403
+            'ldapExpertUUIDGroupAttr' => 'ldapUuidGroupAttribute']
404
+                as $expertSetting => $effectiveSetting) {
405
+            $uuidOverride = $this->configuration->$expertSetting;
406
+            if (!empty($uuidOverride)) {
407
+                $this->configuration->$effectiveSetting = $uuidOverride;
408
+            } else {
409
+                $uuidAttributes = Access::UUID_ATTRIBUTES;
410
+                array_unshift($uuidAttributes, 'auto');
411
+                if (!in_array($this->configuration->$effectiveSetting, $uuidAttributes)
412
+                    && !is_null($this->configID)) {
413
+                    $this->configuration->$effectiveSetting = 'auto';
414
+                    $this->configuration->saveConfiguration();
415
+                    $this->logger->info(
416
+                        'Illegal value for the '.$effectiveSetting.', reset to autodetect.',
417
+                        ['app' => 'user_ldap']
418
+                    );
419
+                }
420
+            }
421
+        }
422
+
423
+        $backupPort = (int)$this->configuration->ldapBackupPort;
424
+        if ($backupPort <= 0) {
425
+            $this->configuration->backupPort = $this->configuration->ldapPort;
426
+        }
427
+
428
+        //make sure empty search attributes are saved as simple, empty array
429
+        $saKeys = ['ldapAttributesForUserSearch',
430
+            'ldapAttributesForGroupSearch'];
431
+        foreach ($saKeys as $key) {
432
+            $val = $this->configuration->$key;
433
+            if (is_array($val) && count($val) === 1 && empty($val[0])) {
434
+                $this->configuration->$key = [];
435
+            }
436
+        }
437
+
438
+        if ((stripos((string)$this->configuration->ldapHost, 'ldaps://') === 0)
439
+            && $this->configuration->ldapTLS) {
440
+            $this->configuration->ldapTLS = false;
441
+            $this->logger->info(
442
+                'LDAPS (already using secure connection) and TLS do not work together. Switched off TLS.',
443
+                ['app' => 'user_ldap']
444
+            );
445
+        }
446
+    }
447
+
448
+    /**
449
+     * @return bool
450
+     */
451
+    private function doCriticalValidation() {
452
+        $configurationOK = true;
453
+        $errorStr = 'Configuration Error (prefix '.
454
+            (string)$this->configPrefix .'): ';
455
+
456
+        //options that shall not be empty
457
+        $options = ['ldapHost', 'ldapUserDisplayName',
458
+            'ldapGroupDisplayName', 'ldapLoginFilter'];
459
+
460
+        //ldapPort should not be empty either unless ldapHost is pointing to a socket
461
+        if (!$this->configuration->usesLdapi()) {
462
+            $options[] = 'ldapPort';
463
+        }
464
+
465
+        foreach ($options as $key) {
466
+            $val = $this->configuration->$key;
467
+            if (empty($val)) {
468
+                switch ($key) {
469
+                    case 'ldapHost':
470
+                        $subj = 'LDAP Host';
471
+                        break;
472
+                    case 'ldapPort':
473
+                        $subj = 'LDAP Port';
474
+                        break;
475
+                    case 'ldapUserDisplayName':
476
+                        $subj = 'LDAP User Display Name';
477
+                        break;
478
+                    case 'ldapGroupDisplayName':
479
+                        $subj = 'LDAP Group Display Name';
480
+                        break;
481
+                    case 'ldapLoginFilter':
482
+                        $subj = 'LDAP Login Filter';
483
+                        break;
484
+                    default:
485
+                        $subj = $key;
486
+                        break;
487
+                }
488
+                $configurationOK = false;
489
+                $this->logger->warning(
490
+                    $errorStr.'No '.$subj.' given!',
491
+                    ['app' => 'user_ldap']
492
+                );
493
+            }
494
+        }
495
+
496
+        //combinations
497
+        $agent = $this->configuration->ldapAgentName;
498
+        $pwd = $this->configuration->ldapAgentPassword;
499
+        if (
500
+            ($agent === '' && $pwd !== '')
501
+            || ($agent !== '' && $pwd === '')
502
+        ) {
503
+            $this->logger->warning(
504
+                $errorStr.'either no password is given for the user ' .
505
+                    'agent or a password is given, but not an LDAP agent.',
506
+                ['app' => 'user_ldap']
507
+            );
508
+            $configurationOK = false;
509
+        }
510
+
511
+        $base = $this->configuration->ldapBase;
512
+        $baseUsers = $this->configuration->ldapBaseUsers;
513
+        $baseGroups = $this->configuration->ldapBaseGroups;
514
+
515
+        if (empty($base) && empty($baseUsers) && empty($baseGroups)) {
516
+            $this->logger->warning(
517
+                $errorStr.'Not a single Base DN given.',
518
+                ['app' => 'user_ldap']
519
+            );
520
+            $configurationOK = false;
521
+        }
522
+
523
+        if (mb_strpos((string)$this->configuration->ldapLoginFilter, '%uid', 0, 'UTF-8')
524
+            === false) {
525
+            $this->logger->warning(
526
+                $errorStr.'login filter does not contain %uid place holder.',
527
+                ['app' => 'user_ldap']
528
+            );
529
+            $configurationOK = false;
530
+        }
531
+
532
+        return $configurationOK;
533
+    }
534
+
535
+    /**
536
+     * Validates the user specified configuration
537
+     * @return bool true if configuration seems OK, false otherwise
538
+     */
539
+    private function validateConfiguration() {
540
+        if ($this->doNotValidate) {
541
+            //don't do a validation if it is a new configuration with pure
542
+            //default values. Will be allowed on changes via __set or
543
+            //setConfiguration
544
+            return false;
545
+        }
546
+
547
+        // first step: "soft" checks: settings that are not really
548
+        // necessary, but advisable. If left empty, give an info message
549
+        $this->doSoftValidation();
550
+
551
+        //second step: critical checks. If left empty or filled wrong, mark as
552
+        //not configured and give a warning.
553
+        return $this->doCriticalValidation();
554
+    }
555
+
556
+
557
+    /**
558
+     * Connects and Binds to LDAP
559
+     *
560
+     * @throws ServerNotAvailableException
561
+     */
562
+    private function establishConnection() {
563
+        if (!$this->configuration->ldapConfigurationActive) {
564
+            return null;
565
+        }
566
+        static $phpLDAPinstalled = true;
567
+        if (!$phpLDAPinstalled) {
568
+            return false;
569
+        }
570
+        if (!$this->ignoreValidation && !$this->configured) {
571
+            $this->logger->warning(
572
+                'Configuration is invalid, cannot connect',
573
+                ['app' => 'user_ldap']
574
+            );
575
+            return false;
576
+        }
577
+        if (!$this->ldapConnectionRes) {
578
+            if (!$this->ldap->areLDAPFunctionsAvailable()) {
579
+                $phpLDAPinstalled = false;
580
+                $this->logger->error(
581
+                    'function ldap_connect is not available. Make sure that the PHP ldap module is installed.',
582
+                    ['app' => 'user_ldap']
583
+                );
584
+
585
+                return false;
586
+            }
587
+            if ($this->configuration->turnOffCertCheck) {
588
+                if (putenv('LDAPTLS_REQCERT=never')) {
589
+                    $this->logger->debug(
590
+                        'Turned off SSL certificate validation successfully.',
591
+                        ['app' => 'user_ldap']
592
+                    );
593
+                } else {
594
+                    $this->logger->warning(
595
+                        'Could not turn off SSL certificate validation.',
596
+                        ['app' => 'user_ldap']
597
+                    );
598
+                }
599
+            }
600
+
601
+            $hasBackupHost = (trim($this->configuration->ldapBackupHost ?? '') !== '');
602
+            $hasBackgroundHost = (trim($this->configuration->ldapBackgroundHost ?? '') !== '');
603
+            $useBackgroundHost = (\OC::$CLI && $hasBackgroundHost);
604
+            $overrideCacheKey = ($useBackgroundHost ? 'overrideBackgroundServer' : 'overrideMainServer');
605
+            $forceBackupHost = ($this->configuration->ldapOverrideMainServer || $this->getFromCache($overrideCacheKey));
606
+            $bindStatus = false;
607
+            if (!$forceBackupHost) {
608
+                try {
609
+                    $host = $this->configuration->ldapHost ?? '';
610
+                    $port = $this->configuration->ldapPort ?? '';
611
+                    if ($useBackgroundHost) {
612
+                        $host = $this->configuration->ldapBackgroundHost ?? '';
613
+                        $port = $this->configuration->ldapBackgroundPort ?? '';
614
+                    }
615
+                    $this->doConnect($host, $port);
616
+                    return $this->bind();
617
+                } catch (ServerNotAvailableException $e) {
618
+                    if (!$hasBackupHost) {
619
+                        throw $e;
620
+                    }
621
+                }
622
+                $this->logger->warning(
623
+                    'Main LDAP not reachable, connecting to backup',
624
+                    [
625
+                        'app' => 'user_ldap'
626
+                    ]
627
+                );
628
+            }
629
+
630
+            // if LDAP server is not reachable, try the Backup (Replica!) Server
631
+            $this->doConnect($this->configuration->ldapBackupHost ?? '', $this->configuration->ldapBackupPort ?? '');
632
+            $this->bindResult = [];
633
+            $bindStatus = $this->bind();
634
+            $error = $this->ldap->isResource($this->ldapConnectionRes) ?
635
+                $this->ldap->errno($this->ldapConnectionRes) : -1;
636
+            if ($bindStatus && $error === 0 && !$forceBackupHost) {
637
+                //when bind to backup server succeeded and failed to main server,
638
+                //skip contacting him until next cache refresh
639
+                $this->writeToCache($overrideCacheKey, true);
640
+            }
641
+
642
+            return $bindStatus;
643
+        }
644
+        return null;
645
+    }
646
+
647
+    /**
648
+     * @param string $host
649
+     * @param string $port
650
+     * @return bool
651
+     * @throws \OC\ServerNotAvailableException
652
+     */
653
+    private function doConnect($host, $port) {
654
+        if ($host === '') {
655
+            return false;
656
+        }
657
+
658
+        $this->ldapConnectionRes = $this->ldap->connect($host, $port);
659
+
660
+        if (!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
661
+            throw new ServerNotAvailableException('Could not set required LDAP Protocol version.');
662
+        }
663
+
664
+        if (!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
665
+            throw new ServerNotAvailableException('Could not disable LDAP referrals.');
666
+        }
667
+
668
+        if (!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_NETWORK_TIMEOUT, $this->configuration->ldapConnectionTimeout)) {
669
+            throw new ServerNotAvailableException('Could not set network timeout');
670
+        }
671
+
672
+        if ($this->configuration->ldapTLS) {
673
+            if (!$this->ldap->startTls($this->ldapConnectionRes)) {
674
+                throw new ServerNotAvailableException('Start TLS failed, when connecting to LDAP host ' . $host . '.');
675
+            }
676
+        }
677
+
678
+        return true;
679
+    }
680
+
681
+    /**
682
+     * Binds to LDAP
683
+     */
684
+    public function bind() {
685
+        if (!$this->configuration->ldapConfigurationActive) {
686
+            return false;
687
+        }
688
+        $cr = $this->ldapConnectionRes;
689
+        if (!$this->ldap->isResource($cr)) {
690
+            $cr = $this->getConnectionResource();
691
+        }
692
+
693
+        if (
694
+            count($this->bindResult) !== 0
695
+            && $this->bindResult['sum'] === md5($this->configuration->ldapAgentName . $this->configPrefix . $this->configuration->ldapAgentPassword)
696
+        ) {
697
+            // don't attempt to bind again with the same data as before
698
+            // bind might have been invoked via getConnectionResource(),
699
+            // but we need results specifically for e.g. user login
700
+            return $this->bindResult['result'];
701
+        }
702
+
703
+        $ldapLogin = @$this->ldap->bind($cr,
704
+            $this->configuration->ldapAgentName,
705
+            $this->configuration->ldapAgentPassword);
706
+
707
+        $this->bindResult = [
708
+            'sum' => md5($this->configuration->ldapAgentName . $this->configPrefix . $this->configuration->ldapAgentPassword),
709
+            'result' => $ldapLogin,
710
+        ];
711
+
712
+        if (!$ldapLogin) {
713
+            $errno = $this->ldap->errno($cr);
714
+
715
+            $this->logger->warning(
716
+                'Bind failed: ' . $errno . ': ' . $this->ldap->error($cr),
717
+                ['app' => 'user_ldap']
718
+            );
719
+
720
+            // Set to failure mode, if LDAP error code is not one of
721
+            // - LDAP_SUCCESS (0)
722
+            // - LDAP_INVALID_CREDENTIALS (49)
723
+            // - LDAP_INSUFFICIENT_ACCESS (50, spotted Apple Open Directory)
724
+            // - LDAP_UNWILLING_TO_PERFORM (53, spotted eDirectory)
725
+            if (!in_array($errno, [0, 49, 50, 53], true)) {
726
+                $this->ldapConnectionRes = null;
727
+            }
728
+
729
+            return false;
730
+        }
731
+        return true;
732
+    }
733 733
 }
Please login to merge, or discard this patch.
apps/user_ldap/lib/Configuration.php 1 patch
Indentation   +507 added lines, -507 removed lines patch added patch discarded remove patch
@@ -39,540 +39,540 @@
 block discarded – undo
39 39
  * @property string ldapUserAvatarRule
40 40
  */
41 41
 class Configuration {
42
-	public const AVATAR_PREFIX_DEFAULT = 'default';
43
-	public const AVATAR_PREFIX_NONE = 'none';
44
-	public const AVATAR_PREFIX_DATA_ATTRIBUTE = 'data:';
42
+    public const AVATAR_PREFIX_DEFAULT = 'default';
43
+    public const AVATAR_PREFIX_NONE = 'none';
44
+    public const AVATAR_PREFIX_DATA_ATTRIBUTE = 'data:';
45 45
 
46
-	public const LDAP_SERVER_FEATURE_UNKNOWN = 'unknown';
47
-	public const LDAP_SERVER_FEATURE_AVAILABLE = 'available';
48
-	public const LDAP_SERVER_FEATURE_UNAVAILABLE = 'unavailable';
46
+    public const LDAP_SERVER_FEATURE_UNKNOWN = 'unknown';
47
+    public const LDAP_SERVER_FEATURE_AVAILABLE = 'available';
48
+    public const LDAP_SERVER_FEATURE_UNAVAILABLE = 'unavailable';
49 49
 
50
-	/**
51
-	 * @var string
52
-	 */
53
-	protected $configPrefix;
54
-	/**
55
-	 * @var bool
56
-	 */
57
-	protected $configRead = false;
58
-	/**
59
-	 * @var string[]
60
-	 */
61
-	protected array $unsavedChanges = [];
50
+    /**
51
+     * @var string
52
+     */
53
+    protected $configPrefix;
54
+    /**
55
+     * @var bool
56
+     */
57
+    protected $configRead = false;
58
+    /**
59
+     * @var string[]
60
+     */
61
+    protected array $unsavedChanges = [];
62 62
 
63
-	/**
64
-	 * @var array<string, mixed> settings
65
-	 */
66
-	protected $config = [
67
-		'ldapHost' => null,
68
-		'ldapPort' => null,
69
-		'ldapBackupHost' => null,
70
-		'ldapBackupPort' => null,
71
-		'ldapBackgroundHost' => null,
72
-		'ldapBackgroundPort' => null,
73
-		'ldapBase' => null,
74
-		'ldapBaseUsers' => null,
75
-		'ldapBaseGroups' => null,
76
-		'ldapAgentName' => null,
77
-		'ldapAgentPassword' => null,
78
-		'ldapTLS' => null,
79
-		'turnOffCertCheck' => null,
80
-		'ldapIgnoreNamingRules' => null,
81
-		'ldapUserDisplayName' => null,
82
-		'ldapUserDisplayName2' => null,
83
-		'ldapUserAvatarRule' => null,
84
-		'ldapGidNumber' => null,
85
-		'ldapUserFilterObjectclass' => null,
86
-		'ldapUserFilterGroups' => null,
87
-		'ldapUserFilter' => null,
88
-		'ldapUserFilterMode' => null,
89
-		'ldapGroupFilter' => null,
90
-		'ldapGroupFilterMode' => null,
91
-		'ldapGroupFilterObjectclass' => null,
92
-		'ldapGroupFilterGroups' => null,
93
-		'ldapGroupDisplayName' => null,
94
-		'ldapGroupMemberAssocAttr' => null,
95
-		'ldapLoginFilter' => null,
96
-		'ldapLoginFilterMode' => null,
97
-		'ldapLoginFilterEmail' => null,
98
-		'ldapLoginFilterUsername' => null,
99
-		'ldapLoginFilterAttributes' => null,
100
-		'ldapQuotaAttribute' => null,
101
-		'ldapQuotaDefault' => null,
102
-		'ldapEmailAttribute' => null,
103
-		'ldapCacheTTL' => null,
104
-		'ldapUuidUserAttribute' => 'auto',
105
-		'ldapUuidGroupAttribute' => 'auto',
106
-		'ldapOverrideMainServer' => false,
107
-		'ldapConfigurationActive' => false,
108
-		'ldapAttributesForUserSearch' => null,
109
-		'ldapAttributesForGroupSearch' => null,
110
-		'ldapExperiencedAdmin' => false,
111
-		'homeFolderNamingRule' => null,
112
-		'hasMemberOfFilterSupport' => false,
113
-		'useMemberOfToDetectMembership' => true,
114
-		'ldapExpertUsernameAttr' => null,
115
-		'ldapExpertUUIDUserAttr' => null,
116
-		'ldapExpertUUIDGroupAttr' => null,
117
-		'lastJpegPhotoLookup' => null,
118
-		'ldapNestedGroups' => false,
119
-		'ldapPagingSize' => null,
120
-		'turnOnPasswordChange' => false,
121
-		'ldapDynamicGroupMemberURL' => null,
122
-		'ldapDefaultPPolicyDN' => null,
123
-		'ldapExtStorageHomeAttribute' => null,
124
-		'ldapMatchingRuleInChainState' => self::LDAP_SERVER_FEATURE_UNKNOWN,
125
-		'ldapConnectionTimeout' => 15,
126
-	];
63
+    /**
64
+     * @var array<string, mixed> settings
65
+     */
66
+    protected $config = [
67
+        'ldapHost' => null,
68
+        'ldapPort' => null,
69
+        'ldapBackupHost' => null,
70
+        'ldapBackupPort' => null,
71
+        'ldapBackgroundHost' => null,
72
+        'ldapBackgroundPort' => null,
73
+        'ldapBase' => null,
74
+        'ldapBaseUsers' => null,
75
+        'ldapBaseGroups' => null,
76
+        'ldapAgentName' => null,
77
+        'ldapAgentPassword' => null,
78
+        'ldapTLS' => null,
79
+        'turnOffCertCheck' => null,
80
+        'ldapIgnoreNamingRules' => null,
81
+        'ldapUserDisplayName' => null,
82
+        'ldapUserDisplayName2' => null,
83
+        'ldapUserAvatarRule' => null,
84
+        'ldapGidNumber' => null,
85
+        'ldapUserFilterObjectclass' => null,
86
+        'ldapUserFilterGroups' => null,
87
+        'ldapUserFilter' => null,
88
+        'ldapUserFilterMode' => null,
89
+        'ldapGroupFilter' => null,
90
+        'ldapGroupFilterMode' => null,
91
+        'ldapGroupFilterObjectclass' => null,
92
+        'ldapGroupFilterGroups' => null,
93
+        'ldapGroupDisplayName' => null,
94
+        'ldapGroupMemberAssocAttr' => null,
95
+        'ldapLoginFilter' => null,
96
+        'ldapLoginFilterMode' => null,
97
+        'ldapLoginFilterEmail' => null,
98
+        'ldapLoginFilterUsername' => null,
99
+        'ldapLoginFilterAttributes' => null,
100
+        'ldapQuotaAttribute' => null,
101
+        'ldapQuotaDefault' => null,
102
+        'ldapEmailAttribute' => null,
103
+        'ldapCacheTTL' => null,
104
+        'ldapUuidUserAttribute' => 'auto',
105
+        'ldapUuidGroupAttribute' => 'auto',
106
+        'ldapOverrideMainServer' => false,
107
+        'ldapConfigurationActive' => false,
108
+        'ldapAttributesForUserSearch' => null,
109
+        'ldapAttributesForGroupSearch' => null,
110
+        'ldapExperiencedAdmin' => false,
111
+        'homeFolderNamingRule' => null,
112
+        'hasMemberOfFilterSupport' => false,
113
+        'useMemberOfToDetectMembership' => true,
114
+        'ldapExpertUsernameAttr' => null,
115
+        'ldapExpertUUIDUserAttr' => null,
116
+        'ldapExpertUUIDGroupAttr' => null,
117
+        'lastJpegPhotoLookup' => null,
118
+        'ldapNestedGroups' => false,
119
+        'ldapPagingSize' => null,
120
+        'turnOnPasswordChange' => false,
121
+        'ldapDynamicGroupMemberURL' => null,
122
+        'ldapDefaultPPolicyDN' => null,
123
+        'ldapExtStorageHomeAttribute' => null,
124
+        'ldapMatchingRuleInChainState' => self::LDAP_SERVER_FEATURE_UNKNOWN,
125
+        'ldapConnectionTimeout' => 15,
126
+    ];
127 127
 
128
-	public function __construct(string $configPrefix, bool $autoRead = true) {
129
-		$this->configPrefix = $configPrefix;
130
-		if ($autoRead) {
131
-			$this->readConfiguration();
132
-		}
133
-	}
128
+    public function __construct(string $configPrefix, bool $autoRead = true) {
129
+        $this->configPrefix = $configPrefix;
130
+        if ($autoRead) {
131
+            $this->readConfiguration();
132
+        }
133
+    }
134 134
 
135
-	/**
136
-	 * @param string $name
137
-	 * @return mixed|null
138
-	 */
139
-	public function __get($name) {
140
-		if (isset($this->config[$name])) {
141
-			return $this->config[$name];
142
-		}
143
-		return null;
144
-	}
135
+    /**
136
+     * @param string $name
137
+     * @return mixed|null
138
+     */
139
+    public function __get($name) {
140
+        if (isset($this->config[$name])) {
141
+            return $this->config[$name];
142
+        }
143
+        return null;
144
+    }
145 145
 
146
-	/**
147
-	 * @param string $name
148
-	 * @param mixed $value
149
-	 */
150
-	public function __set($name, $value) {
151
-		$this->setConfiguration([$name => $value]);
152
-	}
146
+    /**
147
+     * @param string $name
148
+     * @param mixed $value
149
+     */
150
+    public function __set($name, $value) {
151
+        $this->setConfiguration([$name => $value]);
152
+    }
153 153
 
154
-	public function getConfiguration(): array {
155
-		return $this->config;
156
-	}
154
+    public function getConfiguration(): array {
155
+        return $this->config;
156
+    }
157 157
 
158
-	/**
159
-	 * set LDAP configuration with values delivered by an array, not read
160
-	 * from configuration. It does not save the configuration! To do so, you
161
-	 * must call saveConfiguration afterwards.
162
-	 * @param array $config array that holds the config parameters in an associated
163
-	 * array
164
-	 * @param array &$applied optional; array where the set fields will be given to
165
-	 */
166
-	public function setConfiguration(array $config, array &$applied = null): void {
167
-		$cta = $this->getConfigTranslationArray();
168
-		foreach ($config as $inputKey => $val) {
169
-			if (strpos($inputKey, '_') !== false && array_key_exists($inputKey, $cta)) {
170
-				$key = $cta[$inputKey];
171
-			} elseif (array_key_exists($inputKey, $this->config)) {
172
-				$key = $inputKey;
173
-			} else {
174
-				continue;
175
-			}
158
+    /**
159
+     * set LDAP configuration with values delivered by an array, not read
160
+     * from configuration. It does not save the configuration! To do so, you
161
+     * must call saveConfiguration afterwards.
162
+     * @param array $config array that holds the config parameters in an associated
163
+     * array
164
+     * @param array &$applied optional; array where the set fields will be given to
165
+     */
166
+    public function setConfiguration(array $config, array &$applied = null): void {
167
+        $cta = $this->getConfigTranslationArray();
168
+        foreach ($config as $inputKey => $val) {
169
+            if (strpos($inputKey, '_') !== false && array_key_exists($inputKey, $cta)) {
170
+                $key = $cta[$inputKey];
171
+            } elseif (array_key_exists($inputKey, $this->config)) {
172
+                $key = $inputKey;
173
+            } else {
174
+                continue;
175
+            }
176 176
 
177
-			$setMethod = 'setValue';
178
-			switch ($key) {
179
-				case 'ldapAgentPassword':
180
-					$setMethod = 'setRawValue';
181
-					break;
182
-				case 'homeFolderNamingRule':
183
-					$trimmedVal = trim($val);
184
-					if ($trimmedVal !== '' && strpos($val, 'attr:') === false) {
185
-						$val = 'attr:'.$trimmedVal;
186
-					}
187
-					break;
188
-				case 'ldapBase':
189
-				case 'ldapBaseUsers':
190
-				case 'ldapBaseGroups':
191
-				case 'ldapAttributesForUserSearch':
192
-				case 'ldapAttributesForGroupSearch':
193
-				case 'ldapUserFilterObjectclass':
194
-				case 'ldapUserFilterGroups':
195
-				case 'ldapGroupFilterObjectclass':
196
-				case 'ldapGroupFilterGroups':
197
-				case 'ldapLoginFilterAttributes':
198
-					$setMethod = 'setMultiLine';
199
-					break;
200
-			}
201
-			$this->$setMethod($key, $val);
202
-			if (is_array($applied)) {
203
-				$applied[] = $inputKey;
204
-				// storing key as index avoids duplication, and as value for simplicity
205
-			}
206
-			$this->unsavedChanges[$key] = $key;
207
-		}
208
-	}
177
+            $setMethod = 'setValue';
178
+            switch ($key) {
179
+                case 'ldapAgentPassword':
180
+                    $setMethod = 'setRawValue';
181
+                    break;
182
+                case 'homeFolderNamingRule':
183
+                    $trimmedVal = trim($val);
184
+                    if ($trimmedVal !== '' && strpos($val, 'attr:') === false) {
185
+                        $val = 'attr:'.$trimmedVal;
186
+                    }
187
+                    break;
188
+                case 'ldapBase':
189
+                case 'ldapBaseUsers':
190
+                case 'ldapBaseGroups':
191
+                case 'ldapAttributesForUserSearch':
192
+                case 'ldapAttributesForGroupSearch':
193
+                case 'ldapUserFilterObjectclass':
194
+                case 'ldapUserFilterGroups':
195
+                case 'ldapGroupFilterObjectclass':
196
+                case 'ldapGroupFilterGroups':
197
+                case 'ldapLoginFilterAttributes':
198
+                    $setMethod = 'setMultiLine';
199
+                    break;
200
+            }
201
+            $this->$setMethod($key, $val);
202
+            if (is_array($applied)) {
203
+                $applied[] = $inputKey;
204
+                // storing key as index avoids duplication, and as value for simplicity
205
+            }
206
+            $this->unsavedChanges[$key] = $key;
207
+        }
208
+    }
209 209
 
210
-	public function readConfiguration(): void {
211
-		if (!$this->configRead) {
212
-			$cta = array_flip($this->getConfigTranslationArray());
213
-			foreach ($this->config as $key => $val) {
214
-				if (!isset($cta[$key])) {
215
-					//some are determined
216
-					continue;
217
-				}
218
-				$dbKey = $cta[$key];
219
-				switch ($key) {
220
-					case 'ldapBase':
221
-					case 'ldapBaseUsers':
222
-					case 'ldapBaseGroups':
223
-					case 'ldapAttributesForUserSearch':
224
-					case 'ldapAttributesForGroupSearch':
225
-					case 'ldapUserFilterObjectclass':
226
-					case 'ldapUserFilterGroups':
227
-					case 'ldapGroupFilterObjectclass':
228
-					case 'ldapGroupFilterGroups':
229
-					case 'ldapLoginFilterAttributes':
230
-						$readMethod = 'getMultiLine';
231
-						break;
232
-					case 'ldapIgnoreNamingRules':
233
-						$readMethod = 'getSystemValue';
234
-						$dbKey = $key;
235
-						break;
236
-					case 'ldapAgentPassword':
237
-						$readMethod = 'getPwd';
238
-						break;
239
-					case 'ldapUserDisplayName2':
240
-					case 'ldapGroupDisplayName':
241
-						$readMethod = 'getLcValue';
242
-						break;
243
-					case 'ldapUserDisplayName':
244
-					default:
245
-						// user display name does not lower case because
246
-						// we rely on an upper case N as indicator whether to
247
-						// auto-detect it or not. FIXME
248
-						$readMethod = 'getValue';
249
-						break;
250
-				}
251
-				$this->config[$key] = $this->$readMethod($dbKey);
252
-			}
253
-			$this->configRead = true;
254
-		}
255
-	}
210
+    public function readConfiguration(): void {
211
+        if (!$this->configRead) {
212
+            $cta = array_flip($this->getConfigTranslationArray());
213
+            foreach ($this->config as $key => $val) {
214
+                if (!isset($cta[$key])) {
215
+                    //some are determined
216
+                    continue;
217
+                }
218
+                $dbKey = $cta[$key];
219
+                switch ($key) {
220
+                    case 'ldapBase':
221
+                    case 'ldapBaseUsers':
222
+                    case 'ldapBaseGroups':
223
+                    case 'ldapAttributesForUserSearch':
224
+                    case 'ldapAttributesForGroupSearch':
225
+                    case 'ldapUserFilterObjectclass':
226
+                    case 'ldapUserFilterGroups':
227
+                    case 'ldapGroupFilterObjectclass':
228
+                    case 'ldapGroupFilterGroups':
229
+                    case 'ldapLoginFilterAttributes':
230
+                        $readMethod = 'getMultiLine';
231
+                        break;
232
+                    case 'ldapIgnoreNamingRules':
233
+                        $readMethod = 'getSystemValue';
234
+                        $dbKey = $key;
235
+                        break;
236
+                    case 'ldapAgentPassword':
237
+                        $readMethod = 'getPwd';
238
+                        break;
239
+                    case 'ldapUserDisplayName2':
240
+                    case 'ldapGroupDisplayName':
241
+                        $readMethod = 'getLcValue';
242
+                        break;
243
+                    case 'ldapUserDisplayName':
244
+                    default:
245
+                        // user display name does not lower case because
246
+                        // we rely on an upper case N as indicator whether to
247
+                        // auto-detect it or not. FIXME
248
+                        $readMethod = 'getValue';
249
+                        break;
250
+                }
251
+                $this->config[$key] = $this->$readMethod($dbKey);
252
+            }
253
+            $this->configRead = true;
254
+        }
255
+    }
256 256
 
257
-	/**
258
-	 * saves the current config changes in the database
259
-	 */
260
-	public function saveConfiguration(): void {
261
-		$cta = array_flip($this->getConfigTranslationArray());
262
-		$changed = false;
263
-		foreach ($this->unsavedChanges as $key) {
264
-			$value = $this->config[$key];
265
-			switch ($key) {
266
-				case 'ldapAgentPassword':
267
-					$value = base64_encode($value);
268
-					break;
269
-				case 'ldapBase':
270
-				case 'ldapBaseUsers':
271
-				case 'ldapBaseGroups':
272
-				case 'ldapAttributesForUserSearch':
273
-				case 'ldapAttributesForGroupSearch':
274
-				case 'ldapUserFilterObjectclass':
275
-				case 'ldapUserFilterGroups':
276
-				case 'ldapGroupFilterObjectclass':
277
-				case 'ldapGroupFilterGroups':
278
-				case 'ldapLoginFilterAttributes':
279
-					if (is_array($value)) {
280
-						$value = implode("\n", $value);
281
-					}
282
-					break;
283
-					//following options are not stored but detected, skip them
284
-				case 'ldapIgnoreNamingRules':
285
-				case 'ldapUuidUserAttribute':
286
-				case 'ldapUuidGroupAttribute':
287
-					continue 2;
288
-			}
289
-			if (is_null($value)) {
290
-				$value = '';
291
-			}
292
-			$changed = true;
293
-			$this->saveValue($cta[$key], $value);
294
-		}
295
-		if ($changed) {
296
-			$this->saveValue('_lastChange', (string)time());
297
-		}
298
-		$this->unsavedChanges = [];
299
-	}
257
+    /**
258
+     * saves the current config changes in the database
259
+     */
260
+    public function saveConfiguration(): void {
261
+        $cta = array_flip($this->getConfigTranslationArray());
262
+        $changed = false;
263
+        foreach ($this->unsavedChanges as $key) {
264
+            $value = $this->config[$key];
265
+            switch ($key) {
266
+                case 'ldapAgentPassword':
267
+                    $value = base64_encode($value);
268
+                    break;
269
+                case 'ldapBase':
270
+                case 'ldapBaseUsers':
271
+                case 'ldapBaseGroups':
272
+                case 'ldapAttributesForUserSearch':
273
+                case 'ldapAttributesForGroupSearch':
274
+                case 'ldapUserFilterObjectclass':
275
+                case 'ldapUserFilterGroups':
276
+                case 'ldapGroupFilterObjectclass':
277
+                case 'ldapGroupFilterGroups':
278
+                case 'ldapLoginFilterAttributes':
279
+                    if (is_array($value)) {
280
+                        $value = implode("\n", $value);
281
+                    }
282
+                    break;
283
+                    //following options are not stored but detected, skip them
284
+                case 'ldapIgnoreNamingRules':
285
+                case 'ldapUuidUserAttribute':
286
+                case 'ldapUuidGroupAttribute':
287
+                    continue 2;
288
+            }
289
+            if (is_null($value)) {
290
+                $value = '';
291
+            }
292
+            $changed = true;
293
+            $this->saveValue($cta[$key], $value);
294
+        }
295
+        if ($changed) {
296
+            $this->saveValue('_lastChange', (string)time());
297
+        }
298
+        $this->unsavedChanges = [];
299
+    }
300 300
 
301
-	/**
302
-	 * @param string $varName
303
-	 * @return array|string
304
-	 */
305
-	protected function getMultiLine($varName) {
306
-		$value = $this->getValue($varName);
307
-		if (empty($value)) {
308
-			$value = '';
309
-		} else {
310
-			$value = preg_split('/\r\n|\r|\n/', $value);
311
-		}
301
+    /**
302
+     * @param string $varName
303
+     * @return array|string
304
+     */
305
+    protected function getMultiLine($varName) {
306
+        $value = $this->getValue($varName);
307
+        if (empty($value)) {
308
+            $value = '';
309
+        } else {
310
+            $value = preg_split('/\r\n|\r|\n/', $value);
311
+        }
312 312
 
313
-		return $value;
314
-	}
313
+        return $value;
314
+    }
315 315
 
316
-	/**
317
-	 * Sets multi-line values as arrays
318
-	 *
319
-	 * @param string $varName name of config-key
320
-	 * @param array|string $value to set
321
-	 */
322
-	protected function setMultiLine(string $varName, $value): void {
323
-		if (empty($value)) {
324
-			$value = '';
325
-		} elseif (!is_array($value)) {
326
-			$value = preg_split('/\r\n|\r|\n|;/', $value);
327
-			if ($value === false) {
328
-				$value = '';
329
-			}
330
-		}
316
+    /**
317
+     * Sets multi-line values as arrays
318
+     *
319
+     * @param string $varName name of config-key
320
+     * @param array|string $value to set
321
+     */
322
+    protected function setMultiLine(string $varName, $value): void {
323
+        if (empty($value)) {
324
+            $value = '';
325
+        } elseif (!is_array($value)) {
326
+            $value = preg_split('/\r\n|\r|\n|;/', $value);
327
+            if ($value === false) {
328
+                $value = '';
329
+            }
330
+        }
331 331
 
332
-		if (!is_array($value)) {
333
-			$finalValue = trim($value);
334
-		} else {
335
-			$finalValue = [];
336
-			foreach ($value as $key => $val) {
337
-				if (is_string($val)) {
338
-					$val = trim($val);
339
-					if ($val !== '') {
340
-						//accidental line breaks are not wanted and can cause
341
-						// odd behaviour. Thus, away with them.
342
-						$finalValue[] = $val;
343
-					}
344
-				} else {
345
-					$finalValue[] = $val;
346
-				}
347
-			}
348
-		}
332
+        if (!is_array($value)) {
333
+            $finalValue = trim($value);
334
+        } else {
335
+            $finalValue = [];
336
+            foreach ($value as $key => $val) {
337
+                if (is_string($val)) {
338
+                    $val = trim($val);
339
+                    if ($val !== '') {
340
+                        //accidental line breaks are not wanted and can cause
341
+                        // odd behaviour. Thus, away with them.
342
+                        $finalValue[] = $val;
343
+                    }
344
+                } else {
345
+                    $finalValue[] = $val;
346
+                }
347
+            }
348
+        }
349 349
 
350
-		$this->setRawValue($varName, $finalValue);
351
-	}
350
+        $this->setRawValue($varName, $finalValue);
351
+    }
352 352
 
353
-	protected function getPwd(string $varName): string {
354
-		return base64_decode($this->getValue($varName));
355
-	}
353
+    protected function getPwd(string $varName): string {
354
+        return base64_decode($this->getValue($varName));
355
+    }
356 356
 
357
-	protected function getLcValue(string $varName): string {
358
-		return mb_strtolower($this->getValue($varName), 'UTF-8');
359
-	}
357
+    protected function getLcValue(string $varName): string {
358
+        return mb_strtolower($this->getValue($varName), 'UTF-8');
359
+    }
360 360
 
361
-	protected function getSystemValue(string $varName): string {
362
-		//FIXME: if another system value is added, softcode the default value
363
-		return \OC::$server->getConfig()->getSystemValue($varName, false);
364
-	}
361
+    protected function getSystemValue(string $varName): string {
362
+        //FIXME: if another system value is added, softcode the default value
363
+        return \OC::$server->getConfig()->getSystemValue($varName, false);
364
+    }
365 365
 
366
-	protected function getValue(string $varName): string {
367
-		static $defaults;
368
-		if (is_null($defaults)) {
369
-			$defaults = $this->getDefaults();
370
-		}
371
-		return \OC::$server->getConfig()->getAppValue('user_ldap',
372
-			$this->configPrefix.$varName,
373
-			$defaults[$varName]);
374
-	}
366
+    protected function getValue(string $varName): string {
367
+        static $defaults;
368
+        if (is_null($defaults)) {
369
+            $defaults = $this->getDefaults();
370
+        }
371
+        return \OC::$server->getConfig()->getAppValue('user_ldap',
372
+            $this->configPrefix.$varName,
373
+            $defaults[$varName]);
374
+    }
375 375
 
376
-	/**
377
-	 * Sets a scalar value.
378
-	 *
379
-	 * @param string $varName name of config key
380
-	 * @param mixed $value to set
381
-	 */
382
-	protected function setValue(string $varName, $value): void {
383
-		if (is_string($value)) {
384
-			$value = trim($value);
385
-		}
386
-		$this->config[$varName] = $value;
387
-	}
376
+    /**
377
+     * Sets a scalar value.
378
+     *
379
+     * @param string $varName name of config key
380
+     * @param mixed $value to set
381
+     */
382
+    protected function setValue(string $varName, $value): void {
383
+        if (is_string($value)) {
384
+            $value = trim($value);
385
+        }
386
+        $this->config[$varName] = $value;
387
+    }
388 388
 
389
-	/**
390
-	 * Sets a scalar value without trimming.
391
-	 *
392
-	 * @param string $varName name of config key
393
-	 * @param mixed $value to set
394
-	 */
395
-	protected function setRawValue(string $varName, $value): void {
396
-		$this->config[$varName] = $value;
397
-	}
389
+    /**
390
+     * Sets a scalar value without trimming.
391
+     *
392
+     * @param string $varName name of config key
393
+     * @param mixed $value to set
394
+     */
395
+    protected function setRawValue(string $varName, $value): void {
396
+        $this->config[$varName] = $value;
397
+    }
398 398
 
399
-	protected function saveValue(string $varName, string $value): bool {
400
-		\OC::$server->getConfig()->setAppValue(
401
-			'user_ldap',
402
-			$this->configPrefix.$varName,
403
-			$value
404
-		);
405
-		return true;
406
-	}
399
+    protected function saveValue(string $varName, string $value): bool {
400
+        \OC::$server->getConfig()->setAppValue(
401
+            'user_ldap',
402
+            $this->configPrefix.$varName,
403
+            $value
404
+        );
405
+        return true;
406
+    }
407 407
 
408
-	/**
409
-	 * @return array an associative array with the default values. Keys are correspond
410
-	 * to config-value entries in the database table
411
-	 */
412
-	public function getDefaults(): array {
413
-		return [
414
-			'ldap_host' => '',
415
-			'ldap_port' => '',
416
-			'ldap_backup_host' => '',
417
-			'ldap_backup_port' => '',
418
-			'ldap_background_host' => '',
419
-			'ldap_background_port' => '',
420
-			'ldap_override_main_server' => '',
421
-			'ldap_dn' => '',
422
-			'ldap_agent_password' => '',
423
-			'ldap_base' => '',
424
-			'ldap_base_users' => '',
425
-			'ldap_base_groups' => '',
426
-			'ldap_userlist_filter' => '',
427
-			'ldap_user_filter_mode' => 0,
428
-			'ldap_userfilter_objectclass' => '',
429
-			'ldap_userfilter_groups' => '',
430
-			'ldap_login_filter' => '',
431
-			'ldap_login_filter_mode' => 0,
432
-			'ldap_loginfilter_email' => 0,
433
-			'ldap_loginfilter_username' => 1,
434
-			'ldap_loginfilter_attributes' => '',
435
-			'ldap_group_filter' => '',
436
-			'ldap_group_filter_mode' => 0,
437
-			'ldap_groupfilter_objectclass' => '',
438
-			'ldap_groupfilter_groups' => '',
439
-			'ldap_gid_number' => 'gidNumber',
440
-			'ldap_display_name' => 'displayName',
441
-			'ldap_user_display_name_2' => '',
442
-			'ldap_group_display_name' => 'cn',
443
-			'ldap_tls' => 0,
444
-			'ldap_quota_def' => '',
445
-			'ldap_quota_attr' => '',
446
-			'ldap_email_attr' => '',
447
-			'ldap_group_member_assoc_attribute' => '',
448
-			'ldap_cache_ttl' => 600,
449
-			'ldap_uuid_user_attribute' => 'auto',
450
-			'ldap_uuid_group_attribute' => 'auto',
451
-			'home_folder_naming_rule' => '',
452
-			'ldap_turn_off_cert_check' => 0,
453
-			'ldap_configuration_active' => 0,
454
-			'ldap_attributes_for_user_search' => '',
455
-			'ldap_attributes_for_group_search' => '',
456
-			'ldap_expert_username_attr' => '',
457
-			'ldap_expert_uuid_user_attr' => '',
458
-			'ldap_expert_uuid_group_attr' => '',
459
-			'has_memberof_filter_support' => 0,
460
-			'use_memberof_to_detect_membership' => 1,
461
-			'last_jpegPhoto_lookup' => 0,
462
-			'ldap_nested_groups' => 0,
463
-			'ldap_paging_size' => 500,
464
-			'ldap_turn_on_pwd_change' => 0,
465
-			'ldap_experienced_admin' => 0,
466
-			'ldap_dynamic_group_member_url' => '',
467
-			'ldap_default_ppolicy_dn' => '',
468
-			'ldap_user_avatar_rule' => 'default',
469
-			'ldap_ext_storage_home_attribute' => '',
470
-			'ldap_matching_rule_in_chain_state' => self::LDAP_SERVER_FEATURE_UNKNOWN,
471
-			'ldap_connection_timeout' => 15,
472
-		];
473
-	}
408
+    /**
409
+     * @return array an associative array with the default values. Keys are correspond
410
+     * to config-value entries in the database table
411
+     */
412
+    public function getDefaults(): array {
413
+        return [
414
+            'ldap_host' => '',
415
+            'ldap_port' => '',
416
+            'ldap_backup_host' => '',
417
+            'ldap_backup_port' => '',
418
+            'ldap_background_host' => '',
419
+            'ldap_background_port' => '',
420
+            'ldap_override_main_server' => '',
421
+            'ldap_dn' => '',
422
+            'ldap_agent_password' => '',
423
+            'ldap_base' => '',
424
+            'ldap_base_users' => '',
425
+            'ldap_base_groups' => '',
426
+            'ldap_userlist_filter' => '',
427
+            'ldap_user_filter_mode' => 0,
428
+            'ldap_userfilter_objectclass' => '',
429
+            'ldap_userfilter_groups' => '',
430
+            'ldap_login_filter' => '',
431
+            'ldap_login_filter_mode' => 0,
432
+            'ldap_loginfilter_email' => 0,
433
+            'ldap_loginfilter_username' => 1,
434
+            'ldap_loginfilter_attributes' => '',
435
+            'ldap_group_filter' => '',
436
+            'ldap_group_filter_mode' => 0,
437
+            'ldap_groupfilter_objectclass' => '',
438
+            'ldap_groupfilter_groups' => '',
439
+            'ldap_gid_number' => 'gidNumber',
440
+            'ldap_display_name' => 'displayName',
441
+            'ldap_user_display_name_2' => '',
442
+            'ldap_group_display_name' => 'cn',
443
+            'ldap_tls' => 0,
444
+            'ldap_quota_def' => '',
445
+            'ldap_quota_attr' => '',
446
+            'ldap_email_attr' => '',
447
+            'ldap_group_member_assoc_attribute' => '',
448
+            'ldap_cache_ttl' => 600,
449
+            'ldap_uuid_user_attribute' => 'auto',
450
+            'ldap_uuid_group_attribute' => 'auto',
451
+            'home_folder_naming_rule' => '',
452
+            'ldap_turn_off_cert_check' => 0,
453
+            'ldap_configuration_active' => 0,
454
+            'ldap_attributes_for_user_search' => '',
455
+            'ldap_attributes_for_group_search' => '',
456
+            'ldap_expert_username_attr' => '',
457
+            'ldap_expert_uuid_user_attr' => '',
458
+            'ldap_expert_uuid_group_attr' => '',
459
+            'has_memberof_filter_support' => 0,
460
+            'use_memberof_to_detect_membership' => 1,
461
+            'last_jpegPhoto_lookup' => 0,
462
+            'ldap_nested_groups' => 0,
463
+            'ldap_paging_size' => 500,
464
+            'ldap_turn_on_pwd_change' => 0,
465
+            'ldap_experienced_admin' => 0,
466
+            'ldap_dynamic_group_member_url' => '',
467
+            'ldap_default_ppolicy_dn' => '',
468
+            'ldap_user_avatar_rule' => 'default',
469
+            'ldap_ext_storage_home_attribute' => '',
470
+            'ldap_matching_rule_in_chain_state' => self::LDAP_SERVER_FEATURE_UNKNOWN,
471
+            'ldap_connection_timeout' => 15,
472
+        ];
473
+    }
474 474
 
475
-	/**
476
-	 * @return array that maps internal variable names to database fields
477
-	 */
478
-	public function getConfigTranslationArray(): array {
479
-		//TODO: merge them into one representation
480
-		static $array = [
481
-			'ldap_host' => 'ldapHost',
482
-			'ldap_port' => 'ldapPort',
483
-			'ldap_backup_host' => 'ldapBackupHost',
484
-			'ldap_backup_port' => 'ldapBackupPort',
485
-			'ldap_background_host' => 'ldapBackgroundHost',
486
-			'ldap_background_port' => 'ldapBackgroundPort',
487
-			'ldap_override_main_server' => 'ldapOverrideMainServer',
488
-			'ldap_dn' => 'ldapAgentName',
489
-			'ldap_agent_password' => 'ldapAgentPassword',
490
-			'ldap_base' => 'ldapBase',
491
-			'ldap_base_users' => 'ldapBaseUsers',
492
-			'ldap_base_groups' => 'ldapBaseGroups',
493
-			'ldap_userfilter_objectclass' => 'ldapUserFilterObjectclass',
494
-			'ldap_userfilter_groups' => 'ldapUserFilterGroups',
495
-			'ldap_userlist_filter' => 'ldapUserFilter',
496
-			'ldap_user_filter_mode' => 'ldapUserFilterMode',
497
-			'ldap_user_avatar_rule' => 'ldapUserAvatarRule',
498
-			'ldap_login_filter' => 'ldapLoginFilter',
499
-			'ldap_login_filter_mode' => 'ldapLoginFilterMode',
500
-			'ldap_loginfilter_email' => 'ldapLoginFilterEmail',
501
-			'ldap_loginfilter_username' => 'ldapLoginFilterUsername',
502
-			'ldap_loginfilter_attributes' => 'ldapLoginFilterAttributes',
503
-			'ldap_group_filter' => 'ldapGroupFilter',
504
-			'ldap_group_filter_mode' => 'ldapGroupFilterMode',
505
-			'ldap_groupfilter_objectclass' => 'ldapGroupFilterObjectclass',
506
-			'ldap_groupfilter_groups' => 'ldapGroupFilterGroups',
507
-			'ldap_gid_number' => 'ldapGidNumber',
508
-			'ldap_display_name' => 'ldapUserDisplayName',
509
-			'ldap_user_display_name_2' => 'ldapUserDisplayName2',
510
-			'ldap_group_display_name' => 'ldapGroupDisplayName',
511
-			'ldap_tls' => 'ldapTLS',
512
-			'ldap_quota_def' => 'ldapQuotaDefault',
513
-			'ldap_quota_attr' => 'ldapQuotaAttribute',
514
-			'ldap_email_attr' => 'ldapEmailAttribute',
515
-			'ldap_group_member_assoc_attribute' => 'ldapGroupMemberAssocAttr',
516
-			'ldap_cache_ttl' => 'ldapCacheTTL',
517
-			'home_folder_naming_rule' => 'homeFolderNamingRule',
518
-			'ldap_turn_off_cert_check' => 'turnOffCertCheck',
519
-			'ldap_configuration_active' => 'ldapConfigurationActive',
520
-			'ldap_attributes_for_user_search' => 'ldapAttributesForUserSearch',
521
-			'ldap_attributes_for_group_search' => 'ldapAttributesForGroupSearch',
522
-			'ldap_expert_username_attr' => 'ldapExpertUsernameAttr',
523
-			'ldap_expert_uuid_user_attr' => 'ldapExpertUUIDUserAttr',
524
-			'ldap_expert_uuid_group_attr' => 'ldapExpertUUIDGroupAttr',
525
-			'has_memberof_filter_support' => 'hasMemberOfFilterSupport',
526
-			'use_memberof_to_detect_membership' => 'useMemberOfToDetectMembership',
527
-			'last_jpegPhoto_lookup' => 'lastJpegPhotoLookup',
528
-			'ldap_nested_groups' => 'ldapNestedGroups',
529
-			'ldap_paging_size' => 'ldapPagingSize',
530
-			'ldap_turn_on_pwd_change' => 'turnOnPasswordChange',
531
-			'ldap_experienced_admin' => 'ldapExperiencedAdmin',
532
-			'ldap_dynamic_group_member_url' => 'ldapDynamicGroupMemberURL',
533
-			'ldap_default_ppolicy_dn' => 'ldapDefaultPPolicyDN',
534
-			'ldap_ext_storage_home_attribute' => 'ldapExtStorageHomeAttribute',
535
-			'ldap_matching_rule_in_chain_state' => 'ldapMatchingRuleInChainState',
536
-			'ldapIgnoreNamingRules' => 'ldapIgnoreNamingRules',	// sysconfig
537
-			'ldap_connection_timeout' => 'ldapConnectionTimeout',
538
-		];
539
-		return $array;
540
-	}
475
+    /**
476
+     * @return array that maps internal variable names to database fields
477
+     */
478
+    public function getConfigTranslationArray(): array {
479
+        //TODO: merge them into one representation
480
+        static $array = [
481
+            'ldap_host' => 'ldapHost',
482
+            'ldap_port' => 'ldapPort',
483
+            'ldap_backup_host' => 'ldapBackupHost',
484
+            'ldap_backup_port' => 'ldapBackupPort',
485
+            'ldap_background_host' => 'ldapBackgroundHost',
486
+            'ldap_background_port' => 'ldapBackgroundPort',
487
+            'ldap_override_main_server' => 'ldapOverrideMainServer',
488
+            'ldap_dn' => 'ldapAgentName',
489
+            'ldap_agent_password' => 'ldapAgentPassword',
490
+            'ldap_base' => 'ldapBase',
491
+            'ldap_base_users' => 'ldapBaseUsers',
492
+            'ldap_base_groups' => 'ldapBaseGroups',
493
+            'ldap_userfilter_objectclass' => 'ldapUserFilterObjectclass',
494
+            'ldap_userfilter_groups' => 'ldapUserFilterGroups',
495
+            'ldap_userlist_filter' => 'ldapUserFilter',
496
+            'ldap_user_filter_mode' => 'ldapUserFilterMode',
497
+            'ldap_user_avatar_rule' => 'ldapUserAvatarRule',
498
+            'ldap_login_filter' => 'ldapLoginFilter',
499
+            'ldap_login_filter_mode' => 'ldapLoginFilterMode',
500
+            'ldap_loginfilter_email' => 'ldapLoginFilterEmail',
501
+            'ldap_loginfilter_username' => 'ldapLoginFilterUsername',
502
+            'ldap_loginfilter_attributes' => 'ldapLoginFilterAttributes',
503
+            'ldap_group_filter' => 'ldapGroupFilter',
504
+            'ldap_group_filter_mode' => 'ldapGroupFilterMode',
505
+            'ldap_groupfilter_objectclass' => 'ldapGroupFilterObjectclass',
506
+            'ldap_groupfilter_groups' => 'ldapGroupFilterGroups',
507
+            'ldap_gid_number' => 'ldapGidNumber',
508
+            'ldap_display_name' => 'ldapUserDisplayName',
509
+            'ldap_user_display_name_2' => 'ldapUserDisplayName2',
510
+            'ldap_group_display_name' => 'ldapGroupDisplayName',
511
+            'ldap_tls' => 'ldapTLS',
512
+            'ldap_quota_def' => 'ldapQuotaDefault',
513
+            'ldap_quota_attr' => 'ldapQuotaAttribute',
514
+            'ldap_email_attr' => 'ldapEmailAttribute',
515
+            'ldap_group_member_assoc_attribute' => 'ldapGroupMemberAssocAttr',
516
+            'ldap_cache_ttl' => 'ldapCacheTTL',
517
+            'home_folder_naming_rule' => 'homeFolderNamingRule',
518
+            'ldap_turn_off_cert_check' => 'turnOffCertCheck',
519
+            'ldap_configuration_active' => 'ldapConfigurationActive',
520
+            'ldap_attributes_for_user_search' => 'ldapAttributesForUserSearch',
521
+            'ldap_attributes_for_group_search' => 'ldapAttributesForGroupSearch',
522
+            'ldap_expert_username_attr' => 'ldapExpertUsernameAttr',
523
+            'ldap_expert_uuid_user_attr' => 'ldapExpertUUIDUserAttr',
524
+            'ldap_expert_uuid_group_attr' => 'ldapExpertUUIDGroupAttr',
525
+            'has_memberof_filter_support' => 'hasMemberOfFilterSupport',
526
+            'use_memberof_to_detect_membership' => 'useMemberOfToDetectMembership',
527
+            'last_jpegPhoto_lookup' => 'lastJpegPhotoLookup',
528
+            'ldap_nested_groups' => 'ldapNestedGroups',
529
+            'ldap_paging_size' => 'ldapPagingSize',
530
+            'ldap_turn_on_pwd_change' => 'turnOnPasswordChange',
531
+            'ldap_experienced_admin' => 'ldapExperiencedAdmin',
532
+            'ldap_dynamic_group_member_url' => 'ldapDynamicGroupMemberURL',
533
+            'ldap_default_ppolicy_dn' => 'ldapDefaultPPolicyDN',
534
+            'ldap_ext_storage_home_attribute' => 'ldapExtStorageHomeAttribute',
535
+            'ldap_matching_rule_in_chain_state' => 'ldapMatchingRuleInChainState',
536
+            'ldapIgnoreNamingRules' => 'ldapIgnoreNamingRules',	// sysconfig
537
+            'ldap_connection_timeout' => 'ldapConnectionTimeout',
538
+        ];
539
+        return $array;
540
+    }
541 541
 
542
-	/**
543
-	 * @throws \RuntimeException
544
-	 */
545
-	public function resolveRule(string $rule): array {
546
-		if ($rule === 'avatar') {
547
-			return $this->getAvatarAttributes();
548
-		}
549
-		throw new \RuntimeException('Invalid rule');
550
-	}
542
+    /**
543
+     * @throws \RuntimeException
544
+     */
545
+    public function resolveRule(string $rule): array {
546
+        if ($rule === 'avatar') {
547
+            return $this->getAvatarAttributes();
548
+        }
549
+        throw new \RuntimeException('Invalid rule');
550
+    }
551 551
 
552
-	public function getAvatarAttributes(): array {
553
-		$value = $this->ldapUserAvatarRule ?: self::AVATAR_PREFIX_DEFAULT;
554
-		$defaultAttributes = ['jpegphoto', 'thumbnailphoto'];
552
+    public function getAvatarAttributes(): array {
553
+        $value = $this->ldapUserAvatarRule ?: self::AVATAR_PREFIX_DEFAULT;
554
+        $defaultAttributes = ['jpegphoto', 'thumbnailphoto'];
555 555
 
556
-		if ($value === self::AVATAR_PREFIX_NONE) {
557
-			return [];
558
-		}
559
-		if (strpos($value, self::AVATAR_PREFIX_DATA_ATTRIBUTE) === 0) {
560
-			$attribute = trim(substr($value, strlen(self::AVATAR_PREFIX_DATA_ATTRIBUTE)));
561
-			if ($attribute === '') {
562
-				return $defaultAttributes;
563
-			}
564
-			return [strtolower($attribute)];
565
-		}
566
-		if ($value !== self::AVATAR_PREFIX_DEFAULT) {
567
-			\OC::$server->getLogger()->warning('Invalid config value to ldapUserAvatarRule; falling back to default.');
568
-		}
569
-		return $defaultAttributes;
570
-	}
556
+        if ($value === self::AVATAR_PREFIX_NONE) {
557
+            return [];
558
+        }
559
+        if (strpos($value, self::AVATAR_PREFIX_DATA_ATTRIBUTE) === 0) {
560
+            $attribute = trim(substr($value, strlen(self::AVATAR_PREFIX_DATA_ATTRIBUTE)));
561
+            if ($attribute === '') {
562
+                return $defaultAttributes;
563
+            }
564
+            return [strtolower($attribute)];
565
+        }
566
+        if ($value !== self::AVATAR_PREFIX_DEFAULT) {
567
+            \OC::$server->getLogger()->warning('Invalid config value to ldapUserAvatarRule; falling back to default.');
568
+        }
569
+        return $defaultAttributes;
570
+    }
571 571
 
572
-	/**
573
-	 * Returns TRUE if the ldapHost variable starts with 'ldapi://'
574
-	 */
575
-	public function usesLdapi(): bool {
576
-		return (substr($this->config['ldapHost'], 0, strlen('ldapi://')) === 'ldapi://');
577
-	}
572
+    /**
573
+     * Returns TRUE if the ldapHost variable starts with 'ldapi://'
574
+     */
575
+    public function usesLdapi(): bool {
576
+        return (substr($this->config['ldapHost'], 0, strlen('ldapi://')) === 'ldapi://');
577
+    }
578 578
 }
Please login to merge, or discard this patch.