Completed
Push — master ( f2b92c...0343d5 )
by Morris
41:44 queued 24:14
created
apps/user_ldap/lib/Connection.php 2 patches
Indentation   +623 added lines, -623 removed lines patch added patch discarded remove patch
@@ -63,628 +63,628 @@
 block discarded – undo
63 63
  * @property string ldapEmailAttribute
64 64
  */
65 65
 class Connection extends LDAPUtility {
66
-	private $ldapConnectionRes = null;
67
-	private $configPrefix;
68
-	private $configID;
69
-	private $configured = false;
70
-	private $hasPagedResultSupport = true;
71
-	//whether connection should be kept on __destruct
72
-	private $dontDestruct = false;
73
-
74
-	/**
75
-	 * @var bool runtime flag that indicates whether supported primary groups are available
76
-	 */
77
-	public $hasPrimaryGroups = true;
78
-
79
-	/**
80
-	 * @var bool runtime flag that indicates whether supported POSIX gidNumber are available
81
-	 */
82
-	public $hasGidNumber = true;
83
-
84
-	//cache handler
85
-	protected $cache;
86
-
87
-	/** @var Configuration settings handler **/
88
-	protected $configuration;
89
-
90
-	protected $doNotValidate = false;
91
-
92
-	protected $ignoreValidation = false;
93
-
94
-	protected $bindResult = [];
95
-
96
-	/**
97
-	 * Constructor
98
-	 * @param ILDAPWrapper $ldap
99
-	 * @param string $configPrefix a string with the prefix for the configkey column (appconfig table)
100
-	 * @param string|null $configID a string with the value for the appid column (appconfig table) or null for on-the-fly connections
101
-	 */
102
-	public function __construct(ILDAPWrapper $ldap, $configPrefix = '', $configID = 'user_ldap') {
103
-		parent::__construct($ldap);
104
-		$this->configPrefix = $configPrefix;
105
-		$this->configID = $configID;
106
-		$this->configuration = new Configuration($configPrefix,
107
-												 !is_null($configID));
108
-		$memcache = \OC::$server->getMemCacheFactory();
109
-		if($memcache->isAvailable()) {
110
-			$this->cache = $memcache->createDistributed();
111
-		}
112
-		$helper = new Helper(\OC::$server->getConfig());
113
-		$this->doNotValidate = !in_array($this->configPrefix,
114
-			$helper->getServerConfigurationPrefixes());
115
-		$this->hasPagedResultSupport =
116
-			(int)$this->configuration->ldapPagingSize !== 0
117
-			|| $this->ldap->hasPagedResultSupport();
118
-	}
119
-
120
-	public function __destruct() {
121
-		if(!$this->dontDestruct && $this->ldap->isResource($this->ldapConnectionRes)) {
122
-			@$this->ldap->unbind($this->ldapConnectionRes);
123
-			$this->bindResult = [];
124
-		}
125
-	}
126
-
127
-	/**
128
-	 * defines behaviour when the instance is cloned
129
-	 */
130
-	public function __clone() {
131
-		$this->configuration = new Configuration($this->configPrefix,
132
-												 !is_null($this->configID));
133
-		if(count($this->bindResult) !== 0 && $this->bindResult['result'] === true) {
134
-			$this->bindResult = [];
135
-		}
136
-		$this->ldapConnectionRes = null;
137
-		$this->dontDestruct = true;
138
-	}
139
-
140
-	/**
141
-	 * @param string $name
142
-	 * @return bool|mixed
143
-	 */
144
-	public function __get($name) {
145
-		if(!$this->configured) {
146
-			$this->readConfiguration();
147
-		}
148
-
149
-		if($name === 'hasPagedResultSupport') {
150
-			return $this->hasPagedResultSupport;
151
-		}
152
-
153
-		return $this->configuration->$name;
154
-	}
155
-
156
-	/**
157
-	 * @param string $name
158
-	 * @param mixed $value
159
-	 */
160
-	public function __set($name, $value) {
161
-		$this->doNotValidate = false;
162
-		$before = $this->configuration->$name;
163
-		$this->configuration->$name = $value;
164
-		$after = $this->configuration->$name;
165
-		if($before !== $after) {
166
-			if ($this->configID !== '' && $this->configID !== null) {
167
-				$this->configuration->saveConfiguration();
168
-			}
169
-			$this->validateConfiguration();
170
-		}
171
-	}
172
-
173
-	/**
174
-	 * @param string $rule
175
-	 * @return array
176
-	 * @throws \RuntimeException
177
-	 */
178
-	public function resolveRule($rule) {
179
-		return $this->configuration->resolveRule($rule);
180
-	}
181
-
182
-	/**
183
-	 * sets whether the result of the configuration validation shall
184
-	 * be ignored when establishing the connection. Used by the Wizard
185
-	 * in early configuration state.
186
-	 * @param bool $state
187
-	 */
188
-	public function setIgnoreValidation($state) {
189
-		$this->ignoreValidation = (bool)$state;
190
-	}
191
-
192
-	/**
193
-	 * initializes the LDAP backend
194
-	 * @param bool $force read the config settings no matter what
195
-	 */
196
-	public function init($force = false) {
197
-		$this->readConfiguration($force);
198
-		$this->establishConnection();
199
-	}
200
-
201
-	/**
202
-	 * Returns the LDAP handler
203
-	 */
204
-	public function getConnectionResource() {
205
-		if(!$this->ldapConnectionRes) {
206
-			$this->init();
207
-		} else if(!$this->ldap->isResource($this->ldapConnectionRes)) {
208
-			$this->ldapConnectionRes = null;
209
-			$this->establishConnection();
210
-		}
211
-		if(is_null($this->ldapConnectionRes)) {
212
-			\OCP\Util::writeLog('user_ldap', 'No LDAP Connection to server ' . $this->configuration->ldapHost, ILogger::ERROR);
213
-			throw new ServerNotAvailableException('Connection to LDAP server could not be established');
214
-		}
215
-		return $this->ldapConnectionRes;
216
-	}
217
-
218
-	/**
219
-	 * resets the connection resource
220
-	 */
221
-	public function resetConnectionResource() {
222
-		if(!is_null($this->ldapConnectionRes)) {
223
-			@$this->ldap->unbind($this->ldapConnectionRes);
224
-			$this->ldapConnectionRes = null;
225
-			$this->bindResult = [];
226
-		}
227
-	}
228
-
229
-	/**
230
-	 * @param string|null $key
231
-	 * @return string
232
-	 */
233
-	private function getCacheKey($key) {
234
-		$prefix = 'LDAP-'.$this->configID.'-'.$this->configPrefix.'-';
235
-		if(is_null($key)) {
236
-			return $prefix;
237
-		}
238
-		return $prefix.hash('sha256', $key);
239
-	}
240
-
241
-	/**
242
-	 * @param string $key
243
-	 * @return mixed|null
244
-	 */
245
-	public function getFromCache($key) {
246
-		if(!$this->configured) {
247
-			$this->readConfiguration();
248
-		}
249
-		if(is_null($this->cache) || !$this->configuration->ldapCacheTTL) {
250
-			return null;
251
-		}
252
-		$key = $this->getCacheKey($key);
253
-
254
-		return json_decode(base64_decode($this->cache->get($key)), true);
255
-	}
256
-
257
-	/**
258
-	 * @param string $key
259
-	 * @param mixed $value
260
-	 *
261
-	 * @return string
262
-	 */
263
-	public function writeToCache($key, $value) {
264
-		if(!$this->configured) {
265
-			$this->readConfiguration();
266
-		}
267
-		if(is_null($this->cache)
268
-			|| !$this->configuration->ldapCacheTTL
269
-			|| !$this->configuration->ldapConfigurationActive) {
270
-			return null;
271
-		}
272
-		$key   = $this->getCacheKey($key);
273
-		$value = base64_encode(json_encode($value));
274
-		$this->cache->set($key, $value, $this->configuration->ldapCacheTTL);
275
-	}
276
-
277
-	public function clearCache() {
278
-		if(!is_null($this->cache)) {
279
-			$this->cache->clear($this->getCacheKey(null));
280
-		}
281
-	}
282
-
283
-	/**
284
-	 * Caches the general LDAP configuration.
285
-	 * @param bool $force optional. true, if the re-read should be forced. defaults
286
-	 * to false.
287
-	 * @return null
288
-	 */
289
-	private function readConfiguration($force = false) {
290
-		if((!$this->configured || $force) && !is_null($this->configID)) {
291
-			$this->configuration->readConfiguration();
292
-			$this->configured = $this->validateConfiguration();
293
-		}
294
-	}
295
-
296
-	/**
297
-	 * set LDAP configuration with values delivered by an array, not read from configuration
298
-	 * @param array $config array that holds the config parameters in an associated array
299
-	 * @param array &$setParameters optional; array where the set fields will be given to
300
-	 * @return boolean true if config validates, false otherwise. Check with $setParameters for detailed success on single parameters
301
-	 */
302
-	public function setConfiguration($config, &$setParameters = null) {
303
-		if(is_null($setParameters)) {
304
-			$setParameters = array();
305
-		}
306
-		$this->doNotValidate = false;
307
-		$this->configuration->setConfiguration($config, $setParameters);
308
-		if(count($setParameters) > 0) {
309
-			$this->configured = $this->validateConfiguration();
310
-		}
311
-
312
-
313
-		return $this->configured;
314
-	}
315
-
316
-	/**
317
-	 * saves the current Configuration in the database and empties the
318
-	 * cache
319
-	 * @return null
320
-	 */
321
-	public function saveConfiguration() {
322
-		$this->configuration->saveConfiguration();
323
-		$this->clearCache();
324
-	}
325
-
326
-	/**
327
-	 * get the current LDAP configuration
328
-	 * @return array
329
-	 */
330
-	public function getConfiguration() {
331
-		$this->readConfiguration();
332
-		$config = $this->configuration->getConfiguration();
333
-		$cta = $this->configuration->getConfigTranslationArray();
334
-		$result = array();
335
-		foreach($cta as $dbkey => $configkey) {
336
-			switch($configkey) {
337
-				case 'homeFolderNamingRule':
338
-					if(strpos($config[$configkey], 'attr:') === 0) {
339
-						$result[$dbkey] = substr($config[$configkey], 5);
340
-					} else {
341
-						$result[$dbkey] = '';
342
-					}
343
-					break;
344
-				case 'ldapBase':
345
-				case 'ldapBaseUsers':
346
-				case 'ldapBaseGroups':
347
-				case 'ldapAttributesForUserSearch':
348
-				case 'ldapAttributesForGroupSearch':
349
-					if(is_array($config[$configkey])) {
350
-						$result[$dbkey] = implode("\n", $config[$configkey]);
351
-						break;
352
-					} //else follows default
353
-				default:
354
-					$result[$dbkey] = $config[$configkey];
355
-			}
356
-		}
357
-		return $result;
358
-	}
359
-
360
-	private function doSoftValidation() {
361
-		//if User or Group Base are not set, take over Base DN setting
362
-		foreach(array('ldapBaseUsers', 'ldapBaseGroups') as $keyBase) {
363
-			$val = $this->configuration->$keyBase;
364
-			if(empty($val)) {
365
-				$this->configuration->$keyBase = $this->configuration->ldapBase;
366
-			}
367
-		}
368
-
369
-		foreach(array('ldapExpertUUIDUserAttr'  => 'ldapUuidUserAttribute',
370
-					  'ldapExpertUUIDGroupAttr' => 'ldapUuidGroupAttribute')
371
-				as $expertSetting => $effectiveSetting) {
372
-			$uuidOverride = $this->configuration->$expertSetting;
373
-			if(!empty($uuidOverride)) {
374
-				$this->configuration->$effectiveSetting = $uuidOverride;
375
-			} else {
376
-				$uuidAttributes = Access::UUID_ATTRIBUTES;
377
-				array_unshift($uuidAttributes, 'auto');
378
-				if(!in_array($this->configuration->$effectiveSetting,
379
-							$uuidAttributes)
380
-					&& (!is_null($this->configID))) {
381
-					$this->configuration->$effectiveSetting = 'auto';
382
-					$this->configuration->saveConfiguration();
383
-					\OCP\Util::writeLog('user_ldap',
384
-										'Illegal value for the '.
385
-										$effectiveSetting.', '.'reset to '.
386
-										'autodetect.', ILogger::INFO);
387
-				}
388
-
389
-			}
390
-		}
391
-
392
-		$backupPort = (int)$this->configuration->ldapBackupPort;
393
-		if ($backupPort <= 0) {
394
-			$this->configuration->backupPort = $this->configuration->ldapPort;
395
-		}
396
-
397
-		//make sure empty search attributes are saved as simple, empty array
398
-		$saKeys = array('ldapAttributesForUserSearch',
399
-						'ldapAttributesForGroupSearch');
400
-		foreach($saKeys as $key) {
401
-			$val = $this->configuration->$key;
402
-			if(is_array($val) && count($val) === 1 && empty($val[0])) {
403
-				$this->configuration->$key = array();
404
-			}
405
-		}
406
-
407
-		if((stripos($this->configuration->ldapHost, 'ldaps://') === 0)
408
-			&& $this->configuration->ldapTLS) {
409
-			$this->configuration->ldapTLS = false;
410
-			\OCP\Util::writeLog(
411
-				'user_ldap',
412
-				'LDAPS (already using secure connection) and TLS do not work together. Switched off TLS.',
413
-				ILogger::INFO
414
-			);
415
-		}
416
-	}
417
-
418
-	/**
419
-	 * @return bool
420
-	 */
421
-	private function doCriticalValidation() {
422
-		$configurationOK = true;
423
-		$errorStr = 'Configuration Error (prefix '.
424
-			(string)$this->configPrefix .'): ';
425
-
426
-		//options that shall not be empty
427
-		$options = array('ldapHost', 'ldapPort', 'ldapUserDisplayName',
428
-						 'ldapGroupDisplayName', 'ldapLoginFilter');
429
-		foreach($options as $key) {
430
-			$val = $this->configuration->$key;
431
-			if(empty($val)) {
432
-				switch($key) {
433
-					case 'ldapHost':
434
-						$subj = 'LDAP Host';
435
-						break;
436
-					case 'ldapPort':
437
-						$subj = 'LDAP Port';
438
-						break;
439
-					case 'ldapUserDisplayName':
440
-						$subj = 'LDAP User Display Name';
441
-						break;
442
-					case 'ldapGroupDisplayName':
443
-						$subj = 'LDAP Group Display Name';
444
-						break;
445
-					case 'ldapLoginFilter':
446
-						$subj = 'LDAP Login Filter';
447
-						break;
448
-					default:
449
-						$subj = $key;
450
-						break;
451
-				}
452
-				$configurationOK = false;
453
-				\OCP\Util::writeLog(
454
-					'user_ldap',
455
-					$errorStr.'No '.$subj.' given!',
456
-					ILogger::WARN
457
-				);
458
-			}
459
-		}
460
-
461
-		//combinations
462
-		$agent = $this->configuration->ldapAgentName;
463
-		$pwd = $this->configuration->ldapAgentPassword;
464
-		if (
465
-			($agent === ''  && $pwd !== '')
466
-			|| ($agent !== '' && $pwd === '')
467
-		) {
468
-			\OCP\Util::writeLog(
469
-				'user_ldap',
470
-				$errorStr.'either no password is given for the user ' .
471
-					'agent or a password is given, but not an LDAP agent.',
472
-				ILogger::WARN);
473
-			$configurationOK = false;
474
-		}
475
-
476
-		$base = $this->configuration->ldapBase;
477
-		$baseUsers = $this->configuration->ldapBaseUsers;
478
-		$baseGroups = $this->configuration->ldapBaseGroups;
479
-
480
-		if(empty($base) && empty($baseUsers) && empty($baseGroups)) {
481
-			\OCP\Util::writeLog(
482
-				'user_ldap',
483
-				$errorStr.'Not a single Base DN given.',
484
-				ILogger::WARN
485
-			);
486
-			$configurationOK = false;
487
-		}
488
-
489
-		if(mb_strpos($this->configuration->ldapLoginFilter, '%uid', 0, 'UTF-8')
490
-		   === false) {
491
-			\OCP\Util::writeLog(
492
-				'user_ldap',
493
-				$errorStr.'login filter does not contain %uid place holder.',
494
-				ILogger::WARN
495
-			);
496
-			$configurationOK = false;
497
-		}
498
-
499
-		return $configurationOK;
500
-	}
501
-
502
-	/**
503
-	 * Validates the user specified configuration
504
-	 * @return bool true if configuration seems OK, false otherwise
505
-	 */
506
-	private function validateConfiguration() {
507
-
508
-		if($this->doNotValidate) {
509
-			//don't do a validation if it is a new configuration with pure
510
-			//default values. Will be allowed on changes via __set or
511
-			//setConfiguration
512
-			return false;
513
-		}
514
-
515
-		// first step: "soft" checks: settings that are not really
516
-		// necessary, but advisable. If left empty, give an info message
517
-		$this->doSoftValidation();
518
-
519
-		//second step: critical checks. If left empty or filled wrong, mark as
520
-		//not configured and give a warning.
521
-		return $this->doCriticalValidation();
522
-	}
523
-
524
-
525
-	/**
526
-	 * Connects and Binds to LDAP
527
-	 *
528
-	 * @throws ServerNotAvailableException
529
-	 */
530
-	private function establishConnection() {
531
-		if(!$this->configuration->ldapConfigurationActive) {
532
-			return null;
533
-		}
534
-		static $phpLDAPinstalled = true;
535
-		if(!$phpLDAPinstalled) {
536
-			return false;
537
-		}
538
-		if(!$this->ignoreValidation && !$this->configured) {
539
-			\OCP\Util::writeLog(
540
-				'user_ldap',
541
-				'Configuration is invalid, cannot connect',
542
-				ILogger::WARN
543
-			);
544
-			return false;
545
-		}
546
-		if(!$this->ldapConnectionRes) {
547
-			if(!$this->ldap->areLDAPFunctionsAvailable()) {
548
-				$phpLDAPinstalled = false;
549
-				\OCP\Util::writeLog(
550
-					'user_ldap',
551
-					'function ldap_connect is not available. Make sure that the PHP ldap module is installed.',
552
-					ILogger::ERROR
553
-				);
554
-
555
-				return false;
556
-			}
557
-			if($this->configuration->turnOffCertCheck) {
558
-				if(putenv('LDAPTLS_REQCERT=never')) {
559
-					\OCP\Util::writeLog('user_ldap',
560
-						'Turned off SSL certificate validation successfully.',
561
-						ILogger::DEBUG);
562
-				} else {
563
-					\OCP\Util::writeLog(
564
-						'user_ldap',
565
-						'Could not turn off SSL certificate validation.',
566
-						ILogger::WARN
567
-					);
568
-				}
569
-			}
570
-
571
-			$isOverrideMainServer = ($this->configuration->ldapOverrideMainServer
572
-				|| $this->getFromCache('overrideMainServer'));
573
-			$isBackupHost = (trim($this->configuration->ldapBackupHost) !== "");
574
-			$bindStatus = false;
575
-			try {
576
-				if (!$isOverrideMainServer) {
577
-					$this->doConnect($this->configuration->ldapHost,
578
-						$this->configuration->ldapPort);
579
-					return $this->bind();
580
-				}
581
-			} catch (ServerNotAvailableException $e) {
582
-				if(!$isBackupHost) {
583
-					throw $e;
584
-				}
585
-			}
586
-
587
-			//if LDAP server is not reachable, try the Backup (Replica!) Server
588
-			if($isBackupHost || $isOverrideMainServer) {
589
-				$this->doConnect($this->configuration->ldapBackupHost,
590
-								 $this->configuration->ldapBackupPort);
591
-				$this->bindResult = [];
592
-				$bindStatus = $this->bind();
593
-				$error = $this->ldap->isResource($this->ldapConnectionRes) ?
594
-					$this->ldap->errno($this->ldapConnectionRes) : -1;
595
-				if($bindStatus && $error === 0 && !$this->getFromCache('overrideMainServer')) {
596
-					//when bind to backup server succeeded and failed to main server,
597
-					//skip contacting him until next cache refresh
598
-					$this->writeToCache('overrideMainServer', true);
599
-				}
600
-			}
601
-
602
-			return $bindStatus;
603
-		}
604
-		return null;
605
-	}
606
-
607
-	/**
608
-	 * @param string $host
609
-	 * @param string $port
610
-	 * @return bool
611
-	 * @throws \OC\ServerNotAvailableException
612
-	 */
613
-	private function doConnect($host, $port) {
614
-		if ($host === '') {
615
-			return false;
616
-		}
617
-
618
-		$this->ldapConnectionRes = $this->ldap->connect($host, $port);
619
-
620
-		if(!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
621
-			throw new ServerNotAvailableException('Could not set required LDAP Protocol version.');
622
-		}
623
-
624
-		if(!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
625
-			throw new ServerNotAvailableException('Could not disable LDAP referrals.');
626
-		}
627
-
628
-		if($this->configuration->ldapTLS) {
629
-			if(!$this->ldap->startTls($this->ldapConnectionRes)) {
630
-				throw new ServerNotAvailableException('Start TLS failed, when connecting to LDAP host ' . $host . '.');
631
-			}
632
-		}
633
-
634
-		return true;
635
-	}
636
-
637
-	/**
638
-	 * Binds to LDAP
639
-	 */
640
-	public function bind() {
641
-		if(!$this->configuration->ldapConfigurationActive) {
642
-			return false;
643
-		}
644
-		$cr = $this->ldapConnectionRes;
645
-		if(!$this->ldap->isResource($cr)) {
646
-			$cr = $this->getConnectionResource();
647
-		}
648
-
649
-		if(
650
-			count($this->bindResult) !== 0
651
-			&& $this->bindResult['dn'] === $this->configuration->ldapAgentName
652
-			&& \OC::$server->getHasher()->verify(
653
-				$this->configPrefix . $this->configuration->ldapAgentPassword,
654
-				$this->bindResult['hash']
655
-			)
656
-		) {
657
-			// don't attempt to bind again with the same data as before
658
-			// bind might have been invoked via getConnectionResource(),
659
-			// but we need results specifically for e.g. user login
660
-			return $this->bindResult['result'];
661
-		}
662
-
663
-		$ldapLogin = @$this->ldap->bind($cr,
664
-										$this->configuration->ldapAgentName,
665
-										$this->configuration->ldapAgentPassword);
666
-
667
-		$this->bindResult = [
668
-			'dn' => $this->configuration->ldapAgentName,
669
-			'hash' => \OC::$server->getHasher()->hash($this->configPrefix . $this->configuration->ldapAgentPassword),
670
-			'result' => $ldapLogin,
671
-		];
672
-
673
-		if(!$ldapLogin) {
674
-			$errno = $this->ldap->errno($cr);
675
-
676
-			\OCP\Util::writeLog('user_ldap',
677
-				'Bind failed: ' . $errno . ': ' . $this->ldap->error($cr),
678
-				ILogger::WARN);
679
-
680
-			// Set to failure mode, if LDAP error code is not LDAP_SUCCESS or LDAP_INVALID_CREDENTIALS
681
-			if($errno !== 0x00 && $errno !== 0x31) {
682
-				$this->ldapConnectionRes = null;
683
-			}
684
-
685
-			return false;
686
-		}
687
-		return true;
688
-	}
66
+    private $ldapConnectionRes = null;
67
+    private $configPrefix;
68
+    private $configID;
69
+    private $configured = false;
70
+    private $hasPagedResultSupport = true;
71
+    //whether connection should be kept on __destruct
72
+    private $dontDestruct = false;
73
+
74
+    /**
75
+     * @var bool runtime flag that indicates whether supported primary groups are available
76
+     */
77
+    public $hasPrimaryGroups = true;
78
+
79
+    /**
80
+     * @var bool runtime flag that indicates whether supported POSIX gidNumber are available
81
+     */
82
+    public $hasGidNumber = true;
83
+
84
+    //cache handler
85
+    protected $cache;
86
+
87
+    /** @var Configuration settings handler **/
88
+    protected $configuration;
89
+
90
+    protected $doNotValidate = false;
91
+
92
+    protected $ignoreValidation = false;
93
+
94
+    protected $bindResult = [];
95
+
96
+    /**
97
+     * Constructor
98
+     * @param ILDAPWrapper $ldap
99
+     * @param string $configPrefix a string with the prefix for the configkey column (appconfig table)
100
+     * @param string|null $configID a string with the value for the appid column (appconfig table) or null for on-the-fly connections
101
+     */
102
+    public function __construct(ILDAPWrapper $ldap, $configPrefix = '', $configID = 'user_ldap') {
103
+        parent::__construct($ldap);
104
+        $this->configPrefix = $configPrefix;
105
+        $this->configID = $configID;
106
+        $this->configuration = new Configuration($configPrefix,
107
+                                                    !is_null($configID));
108
+        $memcache = \OC::$server->getMemCacheFactory();
109
+        if($memcache->isAvailable()) {
110
+            $this->cache = $memcache->createDistributed();
111
+        }
112
+        $helper = new Helper(\OC::$server->getConfig());
113
+        $this->doNotValidate = !in_array($this->configPrefix,
114
+            $helper->getServerConfigurationPrefixes());
115
+        $this->hasPagedResultSupport =
116
+            (int)$this->configuration->ldapPagingSize !== 0
117
+            || $this->ldap->hasPagedResultSupport();
118
+    }
119
+
120
+    public function __destruct() {
121
+        if(!$this->dontDestruct && $this->ldap->isResource($this->ldapConnectionRes)) {
122
+            @$this->ldap->unbind($this->ldapConnectionRes);
123
+            $this->bindResult = [];
124
+        }
125
+    }
126
+
127
+    /**
128
+     * defines behaviour when the instance is cloned
129
+     */
130
+    public function __clone() {
131
+        $this->configuration = new Configuration($this->configPrefix,
132
+                                                    !is_null($this->configID));
133
+        if(count($this->bindResult) !== 0 && $this->bindResult['result'] === true) {
134
+            $this->bindResult = [];
135
+        }
136
+        $this->ldapConnectionRes = null;
137
+        $this->dontDestruct = true;
138
+    }
139
+
140
+    /**
141
+     * @param string $name
142
+     * @return bool|mixed
143
+     */
144
+    public function __get($name) {
145
+        if(!$this->configured) {
146
+            $this->readConfiguration();
147
+        }
148
+
149
+        if($name === 'hasPagedResultSupport') {
150
+            return $this->hasPagedResultSupport;
151
+        }
152
+
153
+        return $this->configuration->$name;
154
+    }
155
+
156
+    /**
157
+     * @param string $name
158
+     * @param mixed $value
159
+     */
160
+    public function __set($name, $value) {
161
+        $this->doNotValidate = false;
162
+        $before = $this->configuration->$name;
163
+        $this->configuration->$name = $value;
164
+        $after = $this->configuration->$name;
165
+        if($before !== $after) {
166
+            if ($this->configID !== '' && $this->configID !== null) {
167
+                $this->configuration->saveConfiguration();
168
+            }
169
+            $this->validateConfiguration();
170
+        }
171
+    }
172
+
173
+    /**
174
+     * @param string $rule
175
+     * @return array
176
+     * @throws \RuntimeException
177
+     */
178
+    public function resolveRule($rule) {
179
+        return $this->configuration->resolveRule($rule);
180
+    }
181
+
182
+    /**
183
+     * sets whether the result of the configuration validation shall
184
+     * be ignored when establishing the connection. Used by the Wizard
185
+     * in early configuration state.
186
+     * @param bool $state
187
+     */
188
+    public function setIgnoreValidation($state) {
189
+        $this->ignoreValidation = (bool)$state;
190
+    }
191
+
192
+    /**
193
+     * initializes the LDAP backend
194
+     * @param bool $force read the config settings no matter what
195
+     */
196
+    public function init($force = false) {
197
+        $this->readConfiguration($force);
198
+        $this->establishConnection();
199
+    }
200
+
201
+    /**
202
+     * Returns the LDAP handler
203
+     */
204
+    public function getConnectionResource() {
205
+        if(!$this->ldapConnectionRes) {
206
+            $this->init();
207
+        } else if(!$this->ldap->isResource($this->ldapConnectionRes)) {
208
+            $this->ldapConnectionRes = null;
209
+            $this->establishConnection();
210
+        }
211
+        if(is_null($this->ldapConnectionRes)) {
212
+            \OCP\Util::writeLog('user_ldap', 'No LDAP Connection to server ' . $this->configuration->ldapHost, ILogger::ERROR);
213
+            throw new ServerNotAvailableException('Connection to LDAP server could not be established');
214
+        }
215
+        return $this->ldapConnectionRes;
216
+    }
217
+
218
+    /**
219
+     * resets the connection resource
220
+     */
221
+    public function resetConnectionResource() {
222
+        if(!is_null($this->ldapConnectionRes)) {
223
+            @$this->ldap->unbind($this->ldapConnectionRes);
224
+            $this->ldapConnectionRes = null;
225
+            $this->bindResult = [];
226
+        }
227
+    }
228
+
229
+    /**
230
+     * @param string|null $key
231
+     * @return string
232
+     */
233
+    private function getCacheKey($key) {
234
+        $prefix = 'LDAP-'.$this->configID.'-'.$this->configPrefix.'-';
235
+        if(is_null($key)) {
236
+            return $prefix;
237
+        }
238
+        return $prefix.hash('sha256', $key);
239
+    }
240
+
241
+    /**
242
+     * @param string $key
243
+     * @return mixed|null
244
+     */
245
+    public function getFromCache($key) {
246
+        if(!$this->configured) {
247
+            $this->readConfiguration();
248
+        }
249
+        if(is_null($this->cache) || !$this->configuration->ldapCacheTTL) {
250
+            return null;
251
+        }
252
+        $key = $this->getCacheKey($key);
253
+
254
+        return json_decode(base64_decode($this->cache->get($key)), true);
255
+    }
256
+
257
+    /**
258
+     * @param string $key
259
+     * @param mixed $value
260
+     *
261
+     * @return string
262
+     */
263
+    public function writeToCache($key, $value) {
264
+        if(!$this->configured) {
265
+            $this->readConfiguration();
266
+        }
267
+        if(is_null($this->cache)
268
+            || !$this->configuration->ldapCacheTTL
269
+            || !$this->configuration->ldapConfigurationActive) {
270
+            return null;
271
+        }
272
+        $key   = $this->getCacheKey($key);
273
+        $value = base64_encode(json_encode($value));
274
+        $this->cache->set($key, $value, $this->configuration->ldapCacheTTL);
275
+    }
276
+
277
+    public function clearCache() {
278
+        if(!is_null($this->cache)) {
279
+            $this->cache->clear($this->getCacheKey(null));
280
+        }
281
+    }
282
+
283
+    /**
284
+     * Caches the general LDAP configuration.
285
+     * @param bool $force optional. true, if the re-read should be forced. defaults
286
+     * to false.
287
+     * @return null
288
+     */
289
+    private function readConfiguration($force = false) {
290
+        if((!$this->configured || $force) && !is_null($this->configID)) {
291
+            $this->configuration->readConfiguration();
292
+            $this->configured = $this->validateConfiguration();
293
+        }
294
+    }
295
+
296
+    /**
297
+     * set LDAP configuration with values delivered by an array, not read from configuration
298
+     * @param array $config array that holds the config parameters in an associated array
299
+     * @param array &$setParameters optional; array where the set fields will be given to
300
+     * @return boolean true if config validates, false otherwise. Check with $setParameters for detailed success on single parameters
301
+     */
302
+    public function setConfiguration($config, &$setParameters = null) {
303
+        if(is_null($setParameters)) {
304
+            $setParameters = array();
305
+        }
306
+        $this->doNotValidate = false;
307
+        $this->configuration->setConfiguration($config, $setParameters);
308
+        if(count($setParameters) > 0) {
309
+            $this->configured = $this->validateConfiguration();
310
+        }
311
+
312
+
313
+        return $this->configured;
314
+    }
315
+
316
+    /**
317
+     * saves the current Configuration in the database and empties the
318
+     * cache
319
+     * @return null
320
+     */
321
+    public function saveConfiguration() {
322
+        $this->configuration->saveConfiguration();
323
+        $this->clearCache();
324
+    }
325
+
326
+    /**
327
+     * get the current LDAP configuration
328
+     * @return array
329
+     */
330
+    public function getConfiguration() {
331
+        $this->readConfiguration();
332
+        $config = $this->configuration->getConfiguration();
333
+        $cta = $this->configuration->getConfigTranslationArray();
334
+        $result = array();
335
+        foreach($cta as $dbkey => $configkey) {
336
+            switch($configkey) {
337
+                case 'homeFolderNamingRule':
338
+                    if(strpos($config[$configkey], 'attr:') === 0) {
339
+                        $result[$dbkey] = substr($config[$configkey], 5);
340
+                    } else {
341
+                        $result[$dbkey] = '';
342
+                    }
343
+                    break;
344
+                case 'ldapBase':
345
+                case 'ldapBaseUsers':
346
+                case 'ldapBaseGroups':
347
+                case 'ldapAttributesForUserSearch':
348
+                case 'ldapAttributesForGroupSearch':
349
+                    if(is_array($config[$configkey])) {
350
+                        $result[$dbkey] = implode("\n", $config[$configkey]);
351
+                        break;
352
+                    } //else follows default
353
+                default:
354
+                    $result[$dbkey] = $config[$configkey];
355
+            }
356
+        }
357
+        return $result;
358
+    }
359
+
360
+    private function doSoftValidation() {
361
+        //if User or Group Base are not set, take over Base DN setting
362
+        foreach(array('ldapBaseUsers', 'ldapBaseGroups') as $keyBase) {
363
+            $val = $this->configuration->$keyBase;
364
+            if(empty($val)) {
365
+                $this->configuration->$keyBase = $this->configuration->ldapBase;
366
+            }
367
+        }
368
+
369
+        foreach(array('ldapExpertUUIDUserAttr'  => 'ldapUuidUserAttribute',
370
+                        'ldapExpertUUIDGroupAttr' => 'ldapUuidGroupAttribute')
371
+                as $expertSetting => $effectiveSetting) {
372
+            $uuidOverride = $this->configuration->$expertSetting;
373
+            if(!empty($uuidOverride)) {
374
+                $this->configuration->$effectiveSetting = $uuidOverride;
375
+            } else {
376
+                $uuidAttributes = Access::UUID_ATTRIBUTES;
377
+                array_unshift($uuidAttributes, 'auto');
378
+                if(!in_array($this->configuration->$effectiveSetting,
379
+                            $uuidAttributes)
380
+                    && (!is_null($this->configID))) {
381
+                    $this->configuration->$effectiveSetting = 'auto';
382
+                    $this->configuration->saveConfiguration();
383
+                    \OCP\Util::writeLog('user_ldap',
384
+                                        'Illegal value for the '.
385
+                                        $effectiveSetting.', '.'reset to '.
386
+                                        'autodetect.', ILogger::INFO);
387
+                }
388
+
389
+            }
390
+        }
391
+
392
+        $backupPort = (int)$this->configuration->ldapBackupPort;
393
+        if ($backupPort <= 0) {
394
+            $this->configuration->backupPort = $this->configuration->ldapPort;
395
+        }
396
+
397
+        //make sure empty search attributes are saved as simple, empty array
398
+        $saKeys = array('ldapAttributesForUserSearch',
399
+                        'ldapAttributesForGroupSearch');
400
+        foreach($saKeys as $key) {
401
+            $val = $this->configuration->$key;
402
+            if(is_array($val) && count($val) === 1 && empty($val[0])) {
403
+                $this->configuration->$key = array();
404
+            }
405
+        }
406
+
407
+        if((stripos($this->configuration->ldapHost, 'ldaps://') === 0)
408
+            && $this->configuration->ldapTLS) {
409
+            $this->configuration->ldapTLS = false;
410
+            \OCP\Util::writeLog(
411
+                'user_ldap',
412
+                'LDAPS (already using secure connection) and TLS do not work together. Switched off TLS.',
413
+                ILogger::INFO
414
+            );
415
+        }
416
+    }
417
+
418
+    /**
419
+     * @return bool
420
+     */
421
+    private function doCriticalValidation() {
422
+        $configurationOK = true;
423
+        $errorStr = 'Configuration Error (prefix '.
424
+            (string)$this->configPrefix .'): ';
425
+
426
+        //options that shall not be empty
427
+        $options = array('ldapHost', 'ldapPort', 'ldapUserDisplayName',
428
+                            'ldapGroupDisplayName', 'ldapLoginFilter');
429
+        foreach($options as $key) {
430
+            $val = $this->configuration->$key;
431
+            if(empty($val)) {
432
+                switch($key) {
433
+                    case 'ldapHost':
434
+                        $subj = 'LDAP Host';
435
+                        break;
436
+                    case 'ldapPort':
437
+                        $subj = 'LDAP Port';
438
+                        break;
439
+                    case 'ldapUserDisplayName':
440
+                        $subj = 'LDAP User Display Name';
441
+                        break;
442
+                    case 'ldapGroupDisplayName':
443
+                        $subj = 'LDAP Group Display Name';
444
+                        break;
445
+                    case 'ldapLoginFilter':
446
+                        $subj = 'LDAP Login Filter';
447
+                        break;
448
+                    default:
449
+                        $subj = $key;
450
+                        break;
451
+                }
452
+                $configurationOK = false;
453
+                \OCP\Util::writeLog(
454
+                    'user_ldap',
455
+                    $errorStr.'No '.$subj.' given!',
456
+                    ILogger::WARN
457
+                );
458
+            }
459
+        }
460
+
461
+        //combinations
462
+        $agent = $this->configuration->ldapAgentName;
463
+        $pwd = $this->configuration->ldapAgentPassword;
464
+        if (
465
+            ($agent === ''  && $pwd !== '')
466
+            || ($agent !== '' && $pwd === '')
467
+        ) {
468
+            \OCP\Util::writeLog(
469
+                'user_ldap',
470
+                $errorStr.'either no password is given for the user ' .
471
+                    'agent or a password is given, but not an LDAP agent.',
472
+                ILogger::WARN);
473
+            $configurationOK = false;
474
+        }
475
+
476
+        $base = $this->configuration->ldapBase;
477
+        $baseUsers = $this->configuration->ldapBaseUsers;
478
+        $baseGroups = $this->configuration->ldapBaseGroups;
479
+
480
+        if(empty($base) && empty($baseUsers) && empty($baseGroups)) {
481
+            \OCP\Util::writeLog(
482
+                'user_ldap',
483
+                $errorStr.'Not a single Base DN given.',
484
+                ILogger::WARN
485
+            );
486
+            $configurationOK = false;
487
+        }
488
+
489
+        if(mb_strpos($this->configuration->ldapLoginFilter, '%uid', 0, 'UTF-8')
490
+            === false) {
491
+            \OCP\Util::writeLog(
492
+                'user_ldap',
493
+                $errorStr.'login filter does not contain %uid place holder.',
494
+                ILogger::WARN
495
+            );
496
+            $configurationOK = false;
497
+        }
498
+
499
+        return $configurationOK;
500
+    }
501
+
502
+    /**
503
+     * Validates the user specified configuration
504
+     * @return bool true if configuration seems OK, false otherwise
505
+     */
506
+    private function validateConfiguration() {
507
+
508
+        if($this->doNotValidate) {
509
+            //don't do a validation if it is a new configuration with pure
510
+            //default values. Will be allowed on changes via __set or
511
+            //setConfiguration
512
+            return false;
513
+        }
514
+
515
+        // first step: "soft" checks: settings that are not really
516
+        // necessary, but advisable. If left empty, give an info message
517
+        $this->doSoftValidation();
518
+
519
+        //second step: critical checks. If left empty or filled wrong, mark as
520
+        //not configured and give a warning.
521
+        return $this->doCriticalValidation();
522
+    }
523
+
524
+
525
+    /**
526
+     * Connects and Binds to LDAP
527
+     *
528
+     * @throws ServerNotAvailableException
529
+     */
530
+    private function establishConnection() {
531
+        if(!$this->configuration->ldapConfigurationActive) {
532
+            return null;
533
+        }
534
+        static $phpLDAPinstalled = true;
535
+        if(!$phpLDAPinstalled) {
536
+            return false;
537
+        }
538
+        if(!$this->ignoreValidation && !$this->configured) {
539
+            \OCP\Util::writeLog(
540
+                'user_ldap',
541
+                'Configuration is invalid, cannot connect',
542
+                ILogger::WARN
543
+            );
544
+            return false;
545
+        }
546
+        if(!$this->ldapConnectionRes) {
547
+            if(!$this->ldap->areLDAPFunctionsAvailable()) {
548
+                $phpLDAPinstalled = false;
549
+                \OCP\Util::writeLog(
550
+                    'user_ldap',
551
+                    'function ldap_connect is not available. Make sure that the PHP ldap module is installed.',
552
+                    ILogger::ERROR
553
+                );
554
+
555
+                return false;
556
+            }
557
+            if($this->configuration->turnOffCertCheck) {
558
+                if(putenv('LDAPTLS_REQCERT=never')) {
559
+                    \OCP\Util::writeLog('user_ldap',
560
+                        'Turned off SSL certificate validation successfully.',
561
+                        ILogger::DEBUG);
562
+                } else {
563
+                    \OCP\Util::writeLog(
564
+                        'user_ldap',
565
+                        'Could not turn off SSL certificate validation.',
566
+                        ILogger::WARN
567
+                    );
568
+                }
569
+            }
570
+
571
+            $isOverrideMainServer = ($this->configuration->ldapOverrideMainServer
572
+                || $this->getFromCache('overrideMainServer'));
573
+            $isBackupHost = (trim($this->configuration->ldapBackupHost) !== "");
574
+            $bindStatus = false;
575
+            try {
576
+                if (!$isOverrideMainServer) {
577
+                    $this->doConnect($this->configuration->ldapHost,
578
+                        $this->configuration->ldapPort);
579
+                    return $this->bind();
580
+                }
581
+            } catch (ServerNotAvailableException $e) {
582
+                if(!$isBackupHost) {
583
+                    throw $e;
584
+                }
585
+            }
586
+
587
+            //if LDAP server is not reachable, try the Backup (Replica!) Server
588
+            if($isBackupHost || $isOverrideMainServer) {
589
+                $this->doConnect($this->configuration->ldapBackupHost,
590
+                                    $this->configuration->ldapBackupPort);
591
+                $this->bindResult = [];
592
+                $bindStatus = $this->bind();
593
+                $error = $this->ldap->isResource($this->ldapConnectionRes) ?
594
+                    $this->ldap->errno($this->ldapConnectionRes) : -1;
595
+                if($bindStatus && $error === 0 && !$this->getFromCache('overrideMainServer')) {
596
+                    //when bind to backup server succeeded and failed to main server,
597
+                    //skip contacting him until next cache refresh
598
+                    $this->writeToCache('overrideMainServer', true);
599
+                }
600
+            }
601
+
602
+            return $bindStatus;
603
+        }
604
+        return null;
605
+    }
606
+
607
+    /**
608
+     * @param string $host
609
+     * @param string $port
610
+     * @return bool
611
+     * @throws \OC\ServerNotAvailableException
612
+     */
613
+    private function doConnect($host, $port) {
614
+        if ($host === '') {
615
+            return false;
616
+        }
617
+
618
+        $this->ldapConnectionRes = $this->ldap->connect($host, $port);
619
+
620
+        if(!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
621
+            throw new ServerNotAvailableException('Could not set required LDAP Protocol version.');
622
+        }
623
+
624
+        if(!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
625
+            throw new ServerNotAvailableException('Could not disable LDAP referrals.');
626
+        }
627
+
628
+        if($this->configuration->ldapTLS) {
629
+            if(!$this->ldap->startTls($this->ldapConnectionRes)) {
630
+                throw new ServerNotAvailableException('Start TLS failed, when connecting to LDAP host ' . $host . '.');
631
+            }
632
+        }
633
+
634
+        return true;
635
+    }
636
+
637
+    /**
638
+     * Binds to LDAP
639
+     */
640
+    public function bind() {
641
+        if(!$this->configuration->ldapConfigurationActive) {
642
+            return false;
643
+        }
644
+        $cr = $this->ldapConnectionRes;
645
+        if(!$this->ldap->isResource($cr)) {
646
+            $cr = $this->getConnectionResource();
647
+        }
648
+
649
+        if(
650
+            count($this->bindResult) !== 0
651
+            && $this->bindResult['dn'] === $this->configuration->ldapAgentName
652
+            && \OC::$server->getHasher()->verify(
653
+                $this->configPrefix . $this->configuration->ldapAgentPassword,
654
+                $this->bindResult['hash']
655
+            )
656
+        ) {
657
+            // don't attempt to bind again with the same data as before
658
+            // bind might have been invoked via getConnectionResource(),
659
+            // but we need results specifically for e.g. user login
660
+            return $this->bindResult['result'];
661
+        }
662
+
663
+        $ldapLogin = @$this->ldap->bind($cr,
664
+                                        $this->configuration->ldapAgentName,
665
+                                        $this->configuration->ldapAgentPassword);
666
+
667
+        $this->bindResult = [
668
+            'dn' => $this->configuration->ldapAgentName,
669
+            'hash' => \OC::$server->getHasher()->hash($this->configPrefix . $this->configuration->ldapAgentPassword),
670
+            'result' => $ldapLogin,
671
+        ];
672
+
673
+        if(!$ldapLogin) {
674
+            $errno = $this->ldap->errno($cr);
675
+
676
+            \OCP\Util::writeLog('user_ldap',
677
+                'Bind failed: ' . $errno . ': ' . $this->ldap->error($cr),
678
+                ILogger::WARN);
679
+
680
+            // Set to failure mode, if LDAP error code is not LDAP_SUCCESS or LDAP_INVALID_CREDENTIALS
681
+            if($errno !== 0x00 && $errno !== 0x31) {
682
+                $this->ldapConnectionRes = null;
683
+            }
684
+
685
+            return false;
686
+        }
687
+        return true;
688
+    }
689 689
 
690 690
 }
Please login to merge, or discard this patch.
Spacing   +67 added lines, -67 removed lines patch added patch discarded remove patch
@@ -106,19 +106,19 @@  discard block
 block discarded – undo
106 106
 		$this->configuration = new Configuration($configPrefix,
107 107
 												 !is_null($configID));
108 108
 		$memcache = \OC::$server->getMemCacheFactory();
109
-		if($memcache->isAvailable()) {
109
+		if ($memcache->isAvailable()) {
110 110
 			$this->cache = $memcache->createDistributed();
111 111
 		}
112 112
 		$helper = new Helper(\OC::$server->getConfig());
113 113
 		$this->doNotValidate = !in_array($this->configPrefix,
114 114
 			$helper->getServerConfigurationPrefixes());
115 115
 		$this->hasPagedResultSupport =
116
-			(int)$this->configuration->ldapPagingSize !== 0
116
+			(int) $this->configuration->ldapPagingSize !== 0
117 117
 			|| $this->ldap->hasPagedResultSupport();
118 118
 	}
119 119
 
120 120
 	public function __destruct() {
121
-		if(!$this->dontDestruct && $this->ldap->isResource($this->ldapConnectionRes)) {
121
+		if (!$this->dontDestruct && $this->ldap->isResource($this->ldapConnectionRes)) {
122 122
 			@$this->ldap->unbind($this->ldapConnectionRes);
123 123
 			$this->bindResult = [];
124 124
 		}
@@ -130,7 +130,7 @@  discard block
 block discarded – undo
130 130
 	public function __clone() {
131 131
 		$this->configuration = new Configuration($this->configPrefix,
132 132
 												 !is_null($this->configID));
133
-		if(count($this->bindResult) !== 0 && $this->bindResult['result'] === true) {
133
+		if (count($this->bindResult) !== 0 && $this->bindResult['result'] === true) {
134 134
 			$this->bindResult = [];
135 135
 		}
136 136
 		$this->ldapConnectionRes = null;
@@ -142,11 +142,11 @@  discard block
 block discarded – undo
142 142
 	 * @return bool|mixed
143 143
 	 */
144 144
 	public function __get($name) {
145
-		if(!$this->configured) {
145
+		if (!$this->configured) {
146 146
 			$this->readConfiguration();
147 147
 		}
148 148
 
149
-		if($name === 'hasPagedResultSupport') {
149
+		if ($name === 'hasPagedResultSupport') {
150 150
 			return $this->hasPagedResultSupport;
151 151
 		}
152 152
 
@@ -162,7 +162,7 @@  discard block
 block discarded – undo
162 162
 		$before = $this->configuration->$name;
163 163
 		$this->configuration->$name = $value;
164 164
 		$after = $this->configuration->$name;
165
-		if($before !== $after) {
165
+		if ($before !== $after) {
166 166
 			if ($this->configID !== '' && $this->configID !== null) {
167 167
 				$this->configuration->saveConfiguration();
168 168
 			}
@@ -186,7 +186,7 @@  discard block
 block discarded – undo
186 186
 	 * @param bool $state
187 187
 	 */
188 188
 	public function setIgnoreValidation($state) {
189
-		$this->ignoreValidation = (bool)$state;
189
+		$this->ignoreValidation = (bool) $state;
190 190
 	}
191 191
 
192 192
 	/**
@@ -202,14 +202,14 @@  discard block
 block discarded – undo
202 202
 	 * Returns the LDAP handler
203 203
 	 */
204 204
 	public function getConnectionResource() {
205
-		if(!$this->ldapConnectionRes) {
205
+		if (!$this->ldapConnectionRes) {
206 206
 			$this->init();
207
-		} else if(!$this->ldap->isResource($this->ldapConnectionRes)) {
207
+		} else if (!$this->ldap->isResource($this->ldapConnectionRes)) {
208 208
 			$this->ldapConnectionRes = null;
209 209
 			$this->establishConnection();
210 210
 		}
211
-		if(is_null($this->ldapConnectionRes)) {
212
-			\OCP\Util::writeLog('user_ldap', 'No LDAP Connection to server ' . $this->configuration->ldapHost, ILogger::ERROR);
211
+		if (is_null($this->ldapConnectionRes)) {
212
+			\OCP\Util::writeLog('user_ldap', 'No LDAP Connection to server '.$this->configuration->ldapHost, ILogger::ERROR);
213 213
 			throw new ServerNotAvailableException('Connection to LDAP server could not be established');
214 214
 		}
215 215
 		return $this->ldapConnectionRes;
@@ -219,7 +219,7 @@  discard block
 block discarded – undo
219 219
 	 * resets the connection resource
220 220
 	 */
221 221
 	public function resetConnectionResource() {
222
-		if(!is_null($this->ldapConnectionRes)) {
222
+		if (!is_null($this->ldapConnectionRes)) {
223 223
 			@$this->ldap->unbind($this->ldapConnectionRes);
224 224
 			$this->ldapConnectionRes = null;
225 225
 			$this->bindResult = [];
@@ -232,7 +232,7 @@  discard block
 block discarded – undo
232 232
 	 */
233 233
 	private function getCacheKey($key) {
234 234
 		$prefix = 'LDAP-'.$this->configID.'-'.$this->configPrefix.'-';
235
-		if(is_null($key)) {
235
+		if (is_null($key)) {
236 236
 			return $prefix;
237 237
 		}
238 238
 		return $prefix.hash('sha256', $key);
@@ -243,10 +243,10 @@  discard block
 block discarded – undo
243 243
 	 * @return mixed|null
244 244
 	 */
245 245
 	public function getFromCache($key) {
246
-		if(!$this->configured) {
246
+		if (!$this->configured) {
247 247
 			$this->readConfiguration();
248 248
 		}
249
-		if(is_null($this->cache) || !$this->configuration->ldapCacheTTL) {
249
+		if (is_null($this->cache) || !$this->configuration->ldapCacheTTL) {
250 250
 			return null;
251 251
 		}
252 252
 		$key = $this->getCacheKey($key);
@@ -261,10 +261,10 @@  discard block
 block discarded – undo
261 261
 	 * @return string
262 262
 	 */
263 263
 	public function writeToCache($key, $value) {
264
-		if(!$this->configured) {
264
+		if (!$this->configured) {
265 265
 			$this->readConfiguration();
266 266
 		}
267
-		if(is_null($this->cache)
267
+		if (is_null($this->cache)
268 268
 			|| !$this->configuration->ldapCacheTTL
269 269
 			|| !$this->configuration->ldapConfigurationActive) {
270 270
 			return null;
@@ -275,7 +275,7 @@  discard block
 block discarded – undo
275 275
 	}
276 276
 
277 277
 	public function clearCache() {
278
-		if(!is_null($this->cache)) {
278
+		if (!is_null($this->cache)) {
279 279
 			$this->cache->clear($this->getCacheKey(null));
280 280
 		}
281 281
 	}
@@ -287,7 +287,7 @@  discard block
 block discarded – undo
287 287
 	 * @return null
288 288
 	 */
289 289
 	private function readConfiguration($force = false) {
290
-		if((!$this->configured || $force) && !is_null($this->configID)) {
290
+		if ((!$this->configured || $force) && !is_null($this->configID)) {
291 291
 			$this->configuration->readConfiguration();
292 292
 			$this->configured = $this->validateConfiguration();
293 293
 		}
@@ -300,12 +300,12 @@  discard block
 block discarded – undo
300 300
 	 * @return boolean true if config validates, false otherwise. Check with $setParameters for detailed success on single parameters
301 301
 	 */
302 302
 	public function setConfiguration($config, &$setParameters = null) {
303
-		if(is_null($setParameters)) {
303
+		if (is_null($setParameters)) {
304 304
 			$setParameters = array();
305 305
 		}
306 306
 		$this->doNotValidate = false;
307 307
 		$this->configuration->setConfiguration($config, $setParameters);
308
-		if(count($setParameters) > 0) {
308
+		if (count($setParameters) > 0) {
309 309
 			$this->configured = $this->validateConfiguration();
310 310
 		}
311 311
 
@@ -332,10 +332,10 @@  discard block
 block discarded – undo
332 332
 		$config = $this->configuration->getConfiguration();
333 333
 		$cta = $this->configuration->getConfigTranslationArray();
334 334
 		$result = array();
335
-		foreach($cta as $dbkey => $configkey) {
336
-			switch($configkey) {
335
+		foreach ($cta as $dbkey => $configkey) {
336
+			switch ($configkey) {
337 337
 				case 'homeFolderNamingRule':
338
-					if(strpos($config[$configkey], 'attr:') === 0) {
338
+					if (strpos($config[$configkey], 'attr:') === 0) {
339 339
 						$result[$dbkey] = substr($config[$configkey], 5);
340 340
 					} else {
341 341
 						$result[$dbkey] = '';
@@ -346,7 +346,7 @@  discard block
 block discarded – undo
346 346
 				case 'ldapBaseGroups':
347 347
 				case 'ldapAttributesForUserSearch':
348 348
 				case 'ldapAttributesForGroupSearch':
349
-					if(is_array($config[$configkey])) {
349
+					if (is_array($config[$configkey])) {
350 350
 						$result[$dbkey] = implode("\n", $config[$configkey]);
351 351
 						break;
352 352
 					} //else follows default
@@ -359,23 +359,23 @@  discard block
 block discarded – undo
359 359
 
360 360
 	private function doSoftValidation() {
361 361
 		//if User or Group Base are not set, take over Base DN setting
362
-		foreach(array('ldapBaseUsers', 'ldapBaseGroups') as $keyBase) {
362
+		foreach (array('ldapBaseUsers', 'ldapBaseGroups') as $keyBase) {
363 363
 			$val = $this->configuration->$keyBase;
364
-			if(empty($val)) {
364
+			if (empty($val)) {
365 365
 				$this->configuration->$keyBase = $this->configuration->ldapBase;
366 366
 			}
367 367
 		}
368 368
 
369
-		foreach(array('ldapExpertUUIDUserAttr'  => 'ldapUuidUserAttribute',
369
+		foreach (array('ldapExpertUUIDUserAttr'  => 'ldapUuidUserAttribute',
370 370
 					  'ldapExpertUUIDGroupAttr' => 'ldapUuidGroupAttribute')
371 371
 				as $expertSetting => $effectiveSetting) {
372 372
 			$uuidOverride = $this->configuration->$expertSetting;
373
-			if(!empty($uuidOverride)) {
373
+			if (!empty($uuidOverride)) {
374 374
 				$this->configuration->$effectiveSetting = $uuidOverride;
375 375
 			} else {
376 376
 				$uuidAttributes = Access::UUID_ATTRIBUTES;
377 377
 				array_unshift($uuidAttributes, 'auto');
378
-				if(!in_array($this->configuration->$effectiveSetting,
378
+				if (!in_array($this->configuration->$effectiveSetting,
379 379
 							$uuidAttributes)
380 380
 					&& (!is_null($this->configID))) {
381 381
 					$this->configuration->$effectiveSetting = 'auto';
@@ -389,7 +389,7 @@  discard block
 block discarded – undo
389 389
 			}
390 390
 		}
391 391
 
392
-		$backupPort = (int)$this->configuration->ldapBackupPort;
392
+		$backupPort = (int) $this->configuration->ldapBackupPort;
393 393
 		if ($backupPort <= 0) {
394 394
 			$this->configuration->backupPort = $this->configuration->ldapPort;
395 395
 		}
@@ -397,14 +397,14 @@  discard block
 block discarded – undo
397 397
 		//make sure empty search attributes are saved as simple, empty array
398 398
 		$saKeys = array('ldapAttributesForUserSearch',
399 399
 						'ldapAttributesForGroupSearch');
400
-		foreach($saKeys as $key) {
400
+		foreach ($saKeys as $key) {
401 401
 			$val = $this->configuration->$key;
402
-			if(is_array($val) && count($val) === 1 && empty($val[0])) {
402
+			if (is_array($val) && count($val) === 1 && empty($val[0])) {
403 403
 				$this->configuration->$key = array();
404 404
 			}
405 405
 		}
406 406
 
407
-		if((stripos($this->configuration->ldapHost, 'ldaps://') === 0)
407
+		if ((stripos($this->configuration->ldapHost, 'ldaps://') === 0)
408 408
 			&& $this->configuration->ldapTLS) {
409 409
 			$this->configuration->ldapTLS = false;
410 410
 			\OCP\Util::writeLog(
@@ -421,15 +421,15 @@  discard block
 block discarded – undo
421 421
 	private function doCriticalValidation() {
422 422
 		$configurationOK = true;
423 423
 		$errorStr = 'Configuration Error (prefix '.
424
-			(string)$this->configPrefix .'): ';
424
+			(string) $this->configPrefix.'): ';
425 425
 
426 426
 		//options that shall not be empty
427 427
 		$options = array('ldapHost', 'ldapPort', 'ldapUserDisplayName',
428 428
 						 'ldapGroupDisplayName', 'ldapLoginFilter');
429
-		foreach($options as $key) {
429
+		foreach ($options as $key) {
430 430
 			$val = $this->configuration->$key;
431
-			if(empty($val)) {
432
-				switch($key) {
431
+			if (empty($val)) {
432
+				switch ($key) {
433 433
 					case 'ldapHost':
434 434
 						$subj = 'LDAP Host';
435 435
 						break;
@@ -462,12 +462,12 @@  discard block
 block discarded – undo
462 462
 		$agent = $this->configuration->ldapAgentName;
463 463
 		$pwd = $this->configuration->ldapAgentPassword;
464 464
 		if (
465
-			($agent === ''  && $pwd !== '')
465
+			($agent === '' && $pwd !== '')
466 466
 			|| ($agent !== '' && $pwd === '')
467 467
 		) {
468 468
 			\OCP\Util::writeLog(
469 469
 				'user_ldap',
470
-				$errorStr.'either no password is given for the user ' .
470
+				$errorStr.'either no password is given for the user '.
471 471
 					'agent or a password is given, but not an LDAP agent.',
472 472
 				ILogger::WARN);
473 473
 			$configurationOK = false;
@@ -477,7 +477,7 @@  discard block
 block discarded – undo
477 477
 		$baseUsers = $this->configuration->ldapBaseUsers;
478 478
 		$baseGroups = $this->configuration->ldapBaseGroups;
479 479
 
480
-		if(empty($base) && empty($baseUsers) && empty($baseGroups)) {
480
+		if (empty($base) && empty($baseUsers) && empty($baseGroups)) {
481 481
 			\OCP\Util::writeLog(
482 482
 				'user_ldap',
483 483
 				$errorStr.'Not a single Base DN given.',
@@ -486,7 +486,7 @@  discard block
 block discarded – undo
486 486
 			$configurationOK = false;
487 487
 		}
488 488
 
489
-		if(mb_strpos($this->configuration->ldapLoginFilter, '%uid', 0, 'UTF-8')
489
+		if (mb_strpos($this->configuration->ldapLoginFilter, '%uid', 0, 'UTF-8')
490 490
 		   === false) {
491 491
 			\OCP\Util::writeLog(
492 492
 				'user_ldap',
@@ -505,7 +505,7 @@  discard block
 block discarded – undo
505 505
 	 */
506 506
 	private function validateConfiguration() {
507 507
 
508
-		if($this->doNotValidate) {
508
+		if ($this->doNotValidate) {
509 509
 			//don't do a validation if it is a new configuration with pure
510 510
 			//default values. Will be allowed on changes via __set or
511 511
 			//setConfiguration
@@ -528,14 +528,14 @@  discard block
 block discarded – undo
528 528
 	 * @throws ServerNotAvailableException
529 529
 	 */
530 530
 	private function establishConnection() {
531
-		if(!$this->configuration->ldapConfigurationActive) {
531
+		if (!$this->configuration->ldapConfigurationActive) {
532 532
 			return null;
533 533
 		}
534 534
 		static $phpLDAPinstalled = true;
535
-		if(!$phpLDAPinstalled) {
535
+		if (!$phpLDAPinstalled) {
536 536
 			return false;
537 537
 		}
538
-		if(!$this->ignoreValidation && !$this->configured) {
538
+		if (!$this->ignoreValidation && !$this->configured) {
539 539
 			\OCP\Util::writeLog(
540 540
 				'user_ldap',
541 541
 				'Configuration is invalid, cannot connect',
@@ -543,8 +543,8 @@  discard block
 block discarded – undo
543 543
 			);
544 544
 			return false;
545 545
 		}
546
-		if(!$this->ldapConnectionRes) {
547
-			if(!$this->ldap->areLDAPFunctionsAvailable()) {
546
+		if (!$this->ldapConnectionRes) {
547
+			if (!$this->ldap->areLDAPFunctionsAvailable()) {
548 548
 				$phpLDAPinstalled = false;
549 549
 				\OCP\Util::writeLog(
550 550
 					'user_ldap',
@@ -554,8 +554,8 @@  discard block
 block discarded – undo
554 554
 
555 555
 				return false;
556 556
 			}
557
-			if($this->configuration->turnOffCertCheck) {
558
-				if(putenv('LDAPTLS_REQCERT=never')) {
557
+			if ($this->configuration->turnOffCertCheck) {
558
+				if (putenv('LDAPTLS_REQCERT=never')) {
559 559
 					\OCP\Util::writeLog('user_ldap',
560 560
 						'Turned off SSL certificate validation successfully.',
561 561
 						ILogger::DEBUG);
@@ -579,20 +579,20 @@  discard block
 block discarded – undo
579 579
 					return $this->bind();
580 580
 				}
581 581
 			} catch (ServerNotAvailableException $e) {
582
-				if(!$isBackupHost) {
582
+				if (!$isBackupHost) {
583 583
 					throw $e;
584 584
 				}
585 585
 			}
586 586
 
587 587
 			//if LDAP server is not reachable, try the Backup (Replica!) Server
588
-			if($isBackupHost || $isOverrideMainServer) {
588
+			if ($isBackupHost || $isOverrideMainServer) {
589 589
 				$this->doConnect($this->configuration->ldapBackupHost,
590 590
 								 $this->configuration->ldapBackupPort);
591 591
 				$this->bindResult = [];
592 592
 				$bindStatus = $this->bind();
593 593
 				$error = $this->ldap->isResource($this->ldapConnectionRes) ?
594 594
 					$this->ldap->errno($this->ldapConnectionRes) : -1;
595
-				if($bindStatus && $error === 0 && !$this->getFromCache('overrideMainServer')) {
595
+				if ($bindStatus && $error === 0 && !$this->getFromCache('overrideMainServer')) {
596 596
 					//when bind to backup server succeeded and failed to main server,
597 597
 					//skip contacting him until next cache refresh
598 598
 					$this->writeToCache('overrideMainServer', true);
@@ -617,17 +617,17 @@  discard block
 block discarded – undo
617 617
 
618 618
 		$this->ldapConnectionRes = $this->ldap->connect($host, $port);
619 619
 
620
-		if(!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
620
+		if (!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
621 621
 			throw new ServerNotAvailableException('Could not set required LDAP Protocol version.');
622 622
 		}
623 623
 
624
-		if(!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
624
+		if (!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
625 625
 			throw new ServerNotAvailableException('Could not disable LDAP referrals.');
626 626
 		}
627 627
 
628
-		if($this->configuration->ldapTLS) {
629
-			if(!$this->ldap->startTls($this->ldapConnectionRes)) {
630
-				throw new ServerNotAvailableException('Start TLS failed, when connecting to LDAP host ' . $host . '.');
628
+		if ($this->configuration->ldapTLS) {
629
+			if (!$this->ldap->startTls($this->ldapConnectionRes)) {
630
+				throw new ServerNotAvailableException('Start TLS failed, when connecting to LDAP host '.$host.'.');
631 631
 			}
632 632
 		}
633 633
 
@@ -638,19 +638,19 @@  discard block
 block discarded – undo
638 638
 	 * Binds to LDAP
639 639
 	 */
640 640
 	public function bind() {
641
-		if(!$this->configuration->ldapConfigurationActive) {
641
+		if (!$this->configuration->ldapConfigurationActive) {
642 642
 			return false;
643 643
 		}
644 644
 		$cr = $this->ldapConnectionRes;
645
-		if(!$this->ldap->isResource($cr)) {
645
+		if (!$this->ldap->isResource($cr)) {
646 646
 			$cr = $this->getConnectionResource();
647 647
 		}
648 648
 
649
-		if(
649
+		if (
650 650
 			count($this->bindResult) !== 0
651 651
 			&& $this->bindResult['dn'] === $this->configuration->ldapAgentName
652 652
 			&& \OC::$server->getHasher()->verify(
653
-				$this->configPrefix . $this->configuration->ldapAgentPassword,
653
+				$this->configPrefix.$this->configuration->ldapAgentPassword,
654 654
 				$this->bindResult['hash']
655 655
 			)
656 656
 		) {
@@ -666,19 +666,19 @@  discard block
 block discarded – undo
666 666
 
667 667
 		$this->bindResult = [
668 668
 			'dn' => $this->configuration->ldapAgentName,
669
-			'hash' => \OC::$server->getHasher()->hash($this->configPrefix . $this->configuration->ldapAgentPassword),
669
+			'hash' => \OC::$server->getHasher()->hash($this->configPrefix.$this->configuration->ldapAgentPassword),
670 670
 			'result' => $ldapLogin,
671 671
 		];
672 672
 
673
-		if(!$ldapLogin) {
673
+		if (!$ldapLogin) {
674 674
 			$errno = $this->ldap->errno($cr);
675 675
 
676 676
 			\OCP\Util::writeLog('user_ldap',
677
-				'Bind failed: ' . $errno . ': ' . $this->ldap->error($cr),
677
+				'Bind failed: '.$errno.': '.$this->ldap->error($cr),
678 678
 				ILogger::WARN);
679 679
 
680 680
 			// Set to failure mode, if LDAP error code is not LDAP_SUCCESS or LDAP_INVALID_CREDENTIALS
681
-			if($errno !== 0x00 && $errno !== 0x31) {
681
+			if ($errno !== 0x00 && $errno !== 0x31) {
682 682
 				$this->ldapConnectionRes = null;
683 683
 			}
684 684
 
Please login to merge, or discard this patch.